Technical Blog

5 Posts tagged with the upgrade tag

Before we start, you may speculate about the usefulness of class shadowing. Class shadowing can be used as a trick to patch or replace behaviors of classes at runtime, taking advantage of the first-come first-served algorithm of Java’s class loader. If there are more than one class with the same fully qualified name in the Java class loader, the first one that shows up always take precedence over the rest.

 

This is extremely useful in an upgrade project. For example, in order to make some out-of-the-box (OOTB) methods extensible without directly changing the source, or to provide backward-compatibility support, class shadowing is a good technique to separate the OOTB code and the customized code. By creating a patch jar against the OOTB jar and putting it before the OOTB jar on classpath, classes with the same qualified name are merged at runtime.

 

Class shadowing is only one way of patching a class. It’s based on class loader’s runtime class resolution. Another way is to use class overlay. For example, the Maven war overlays plugin expands the war file and copy them on top of the host classes.

 

If you are already familiar with OSGi based technology, patch fragment is actually taking advantage of the class shadowing mechanism. This post is not targeting at building OSGi application but at standard Maven project.

 

To instruct Java’s class loader to load jars in a specific order, we can make use of the “-cp” option. For example,

 

> java -cp patch.jar ootb.jar -jar main.jar

 

Besides, we can also make use of the Class-Path attribute of the jar manifest to specify the classpath. We will adopt this method in this post.

 

Here is an example we are going to build. HelloWorldProxy is a proxy artifact that exports its classpath in such an order that classes in HelloWorldPatch are replacing classes in HelloWorld. HelloWorldTest depends on HelloWorldProxy and doesn’t know which implementation(HelloWorld or HelloWorldPatch) HelloWorldProxy is exporting. The dependency graph is as followed:

 

Screen shot 2010-07-12 at 11.51.58 AM.png

In the pom.xml of HelloWorldProxy, it has two dependencies and we put HelloWorldPatch before HelloWorld, since we would like see classes in HelloWorldPatch replacing the ones in HelloWorld. As of Maven 2.0.9, the ordering of dependencies on the classpath is preserved. The code snippet is as followed:

 

<dependencies>
    <dependency>
        <groupId>HelloWorld</groupId>
        <artifactId>HelloWorldPatch</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <type>jar</type>
        <scope>compile</scope>
    </dependency>
    <dependency>
        <groupId>HelloWorld</groupId>
        <artifactId>HelloWorld</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <type>jar</type>
        <scope>compile</scope>
    </dependency>
</dependencies>

 

We also need to make sure HelloWorldProxy exports the two jars in the Class-Path attribute of the MANIFEST.MF file with the correct ordering. The key is to set the addClasspath flag to true in the maven-jar-plugin:

 

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-jar-plugin</artifactId>
    <version>2.3.1</version>
    <configuration>
        <archive>
            <manifest>
                <addClasspath>true</addClasspath>
            </manifest>
        </archive>
    </configuration>
</plugin>

 

Run “mvn package” in HelloWorldProxy and take a look at the generated MANIFEST.MF:

 

Screen shot 2010-07-12 at 11.56.55 AM.png

 

Voila! That’s what we expect! HelloWorldPatch takes precedence over HelloWorld on HelloWorldProxy’s classpath!

 

Now HelloWorldTest can safely depends on HelloWorldProxy and expects that HelloWorldProxy will export HelloWorldPatch’s implementations at runtime:

 


<dependency>
    <groupId>HelloWorld</groupId>
    <artifactId>HelloWorldProxy</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <type>jar</type>
    <scope>compile</scope>
</dependency>

 

The source of this example is available on GitHub http://github.com/jingweno/patching_with_class_shadowing_and_maven. You can also view it directly with CodeFaces http://codefaces.org/http://github.com/jingweno/patching_with_class_shadowing_and_maven.

0 Comments Permalink

Anyone who has had the pleasure of customizing the Commerce Manager knows that it is a complicated piece of software with a lot of moving parts. 

 

However, with the release of 6.2.1 combined with the new binary-based architecture and a number of clients going through an upgrade process, it has become even more complex with the introduction of patch fragments and a new approach to customizations.

 

For this blog post, I wanted to demonstrate a handy Eclipse plug-in that lets you visualize the dependencies between the various plug-ins within the Commerce Manager.  This is really useful for quickly discovering which plug-ins/bundles are dependent on each other.

 

The plug-in is called "Plug-In Dependency Graph Plugin". You can download it from http://testdrivenguy.blogspot.com/2009/05/eclipse-plug-in-dependency-graph.html. Then just unpack it into your Eclipse plugins folder and restart Eclipse.

 

Open the "Graph Plug-in Dependencies" view, click the search icon in the top right corner, and type in the name of the plugin you want to check out. In this example, I am interested in the our customized admin.configuration plugin.

 

admin-config-callees.png

 

You can see that there are a lot of dependencies between all the plugins, but by highlighting the admin.configuration plugin I can quickly see which plugins are directly referenced by it.

 

Alternatively, if you want to see who is directly referencing your plugin, you can show the callers:

 

admin-config-callers.png

In this case, not too interesting.  Let's take a look at com.elasticpath.cmclient.core:

 

cmclient-core-callers.png

 

A little more interesting. This plugin can help you quickly track down configuration issues in your plug-in manifest files when developing using the new patch fragment approach.

 

In future posts, I will provide more technical details as to our approach in implementing the patch fragment architecture including technical challenges encountered and our solutions to these issues.

0 Comments Permalink
Background

 

Our client's e-commerce store has been powered by Elastic Path for well over a year now. Our team started development of the store on a beta version of Elastic Path 6.0 in January 2008. After 3 months of development, including a merge with the public release of Elastic Path 6.0, we launched the store in March 2008. We continued to add new features and bug fixes. We even took advantage of EP 6.0's multi-store support to add a few more stores in August 2008. At the beginning of 2009, after a year's worth of customizations atop the client's EP 6.0 deployment, we decided that it was time to upgrade to EP 6.1.
timeline.jpg



Why Upgrade?

 

Upgrading a customized version of Elastic Path Commerce is not a trivial process. So you need to ask yourself (and the client) if an upgrade is even necessary. The first step of upgrading Elastic Path is determining whether the benefits of upgrading exceed the costs of upgrading. The cost is time and money.

 

What are the benefits? Here are some of ours:
  • EP 6.1 provides full multistore. In EP 6.0, multiple stores required multiple storefront WAR files: one for each store. EP 6.1 runs multiple stores from a single WAR file. Less WAR files translates to quicker deployments and a smaller resource footprint.  This is especially relevant to us since our client is running six stores.
  • EP 6.1 comes with 300+ bug fixes.
  • Upgrading to EP 6.1 paves the way for upgrades to future versions of Elastic Path. This is crucial, because our client is anticipating features that are planned in future versions of EP (e.g. import/export of promotion data, available in EP 6.1.1).
  • EP 6.1 comes with FIT integration tests.
  • EP 6.1 introduces the import/export utility, used to migrate catalog data between databases.
  • EP 6.1 introduces the settings framework, an improved way to manage configuration settings.
  • EP 6.1 allows search index rebuilding to be triggered from the CM Client.
  • The Store configuration UI has been overhauled in EP 6.1; the Store wizard has been replaced by a Store editor.
  • In EP 6.1, assets (e.g. velocity templates, images, etc.) are stored outside the web application, making the view layer much easier to modify.

 

We presented a list of EP 6.1 benefits to our client, provided an estimate on the amount of time it would take to complete the upgrade, and got the green light to go ahead with it. These were the benefits relevant to us, but EP 6.1 has many other improvements. For example, here are 7 Big Code Changes in EP 6.1.



The Upgrade

 

After we convinced ourselves and our client that upgrading to EP 6.1 was worthwhile, we moved on to the fun part: the upgrade itself. There are several steps that need to be completed during an upgrade and it's easy to become overwhelmed at first, so we broke the upgrade down into more manageable sub-tasks:
  1. Database updates
  2. Merging the code
  3. Moving customized named database queries
  4. Using the new settings framework
  5. Relocating the assets directory
  6. Setting up Maven
Let's cover each sub-task in more detail.

 

1. Database Updates
The database schema did not change significantly between EP 6.0 and EP 6.1. Elastic Path has a script that upgrades the database from EP 6.0.x to EP 6.0.3 and another that upgrades it from EP 6.0.3 to EP 6.1. We ran both of these scripts against our database with no problems. Most of the schema changes consists of new tables and new columns and there are few changes to existing columns. Click here for detailed information about the EP 6.1 database updates.

 

After upgrading the schema with the scripts, a few data updates needed to be made:
  • By default, full credit card numbers are stored in the database for each order; we turned this off (the ability to turn it off is a new EP 6.1 feature). This is accomplished by setting STORE_FULL_CREDIT_CARDS to 0 for each row in TSTORE.
  • Populate the new TSTORESUPPORTEDLOCALE table with store-locale mappings; these mappings mirrored the catalog-locale mappings already in TCATALOGSUPPORTEDLOCALE.
  • Populate the new TSTORESUPPORTEDCURRENCY table with the store-currency mappings; these mappings are similar to the catalog-currency mappings already in TCATALOGSUPPORTEDCURRENCY.

 

2. Merging the Code
The majority of the time spent on the upgrade was in this step: merging code. Generally, the more changes you make to a codebase, the harder it is to upgrade in the future. I say "generally" because there are ways to customize code that minimize future code merge conflicts. For example, this GREP technical blog post shows how to customize code with the decorator design pattern; a strategy that significantly reduces code conflicts.

 

The easiest way to merge large amounts of code is by using your version control software's merge tools combined with vendor branches. We have a great GREP article explaining what vendor branches are and how they can be used for merging code here. Since we use subversion for this particular project, we ended up using svn merge to merge the code.

 

This is the svn merge command we used:
svn merge https://svn.elasticpath.com/perfect_code/pd/ep5/tags/publicrelease6.0/ https://svn.elasticpath.com/perfect_code/pd/ep5/tags/publicrelease6.1/ . --accept postpone
This command takes the differences between OOTB EP 6.0 and OOTB EP 6.1 (whose vendor branches are specified in green and blue respectively), and applies those differences onto our customized codebase (specified in red, this command was run from our project's root level directory). The --accept postpone part tells the utility to postpone resolving any merge conflicts that occur.

 

The following diagram shows the branches referred to in the svn merge command and our desired "Customized EP 6.1" end state:
codemerge.jpg
When svn merge hits a conflicted file, it produces 3 output files. For example, consider a file called MyClass.java that is conflicted; svn merge will produce the files MyClass.java.left, MyClass.java.right, and MyClass.java.working. The highlighted colors correspond to the branches in the svn merge command above. The .left file is the EP6.0 version, the .right file is the EP 6.1 version, and the .working file is our customized codebase version.

 

The utility does a pretty good job at merging the source files. Some stats we gathered after running this command:
  • 3682 files were added
  • 118 files were deleted
  • 953 files were automatically merged successfully
  • 132 files were conflicted and not automatically merged
The high number of files added is largely attributed to the relocated assets directory and the new FIT tests. The 953 files merged successfully demonstrates the advantage of using a utility to automatically merge files. Unfortunately, not everything can be automatically merged; we had to manually merge the 132 conflicted files. These numbers will vary depending on the type and amount of customizations you've made on your codebase; our codebase has a lot of customizations.

 

There are many approaches to manually merging a conflicted file. The .left, .right, and .working files produced by svn merge, described above, are invaluable to this process.

 

This is my strategy:
  1. diff (i.e. compare) the .left file (EP 6.0 version) with the .right file (EP 6.1 version); this shows Elastic Path's changes to the file from version 6.0 to 6.1.
  2. diff the .left file (EP 6.0 version) with the .working file (your customized version); this shows your customizations to the file from 6.0 to its current state.
  3. Based on the comparisons above, who changed the file more? Elastic Path or you?
    • If Elastic Path made more changes to the file, start with the .right file and incorporate your changes (indicated by the diff in step 2) to the file.
    • If you made more changes to the file, start with the .working file and incorporate Elastic Path's changes (indicated by the diff in step 1) to the file.
    • If they have the same amount of changes, it doesn't really matter which version you pick as your starting point; the amount of work will roughly be the same. I lean towards picking the .right file (EP 6.1 version) because aligning your codebase to Elastic Path's will make future upgrades smoother.
  4. After merging the file in step 3, you are done. Move onto the next file!
More numbers. Of the 132 conflicted files:
  • 88 were relatively easy/trivial merges
  • 23 were moderately complicated merges
  • And 21 were very complicated merges
The very complicated merges were the files that were changed significantly by both us (i.e. our customizations) and by Elastic Path (during the development of EP 6.1). These files include the class files for ShoppingCart, OrderService, CheckoutService, and other areas of Elastic Path that are often modified.

 

All in all, the code merge is likely not as painful as most anticipate it to be. Even with 40+ files requiring non-trivial manual merges, our code merge went pretty smoothly.

 

A couple tips:
  • Take advantage of dry-run modes of your merging tool to preview how much work needs to be done without actually performing the merge. For example, adding the --dry-run option to our svn merge command enabled us to see how many merge conflicts we'd have to resolve in advance of the merge itself; this information is very useful during the estimation phase.
svn merge https://svn.example.com/project/tags/publicrelease6.0/ https://svn.example.com/project/tags/publicrelease6.1/ . --accept postpone --dry-run
  • As we manually merged the conflicted files, we took note of the merge details in a list. For each file that required non-trivial merging, we jotted down a couple sentences describing the merge (e.g. which methods were merged, etc.). Taking notes during the code merge requires a little overhead, but the list proved to be very useful when bugs caused by the merge were found later on.

 

3. Moving Customized Named Database Queries

 

In EP 6.0, named JPA database queries were embedded in the class files. For example, this bit of code is in CatalogImpl.java:
@NamedQueries({
    @NamedQuery(name = "CATALOG_IN_USE_BY_PRODUCT_TYPE",
            query = "SELECT pt.uidPk FROM ProductTypeImpl pt"
                    + " LEFT JOIN pt.catalog c WHERE c.uidPk = ?1")
    ...
})

In EP 6.1, the named JPA database queries have been moved from the class files to separate object-relational mapping XML files. The query above has been moved to the catalog-orm.xml file.
The code merge should take care of the OOTB (out-of-the-box) named queries but any customized name queries that we added had to be manually moved from the class file to the appropriate XML file. 


4. Using the New Settings Framework

 

In EP 6.0, configuration settings were stored in various XML files (e.g. commerce-config.xml, default.xml, etc.). EP 6.1 introduces a new settings framework that stores settings in the database and allows them to be managed from the CM Client; the setting values are retrieved wherever they are needed in the code via the SettingsService class. The new settings framework is a big improvement for managing configuration settings, but some work needs to be done to take advantage of it.

 

First, some of the OOTB setting values need to be overridden with your project's values. For instance, our client's stores use Elastic Path's one-page checkout. There is a boolean setting that turns this feature on. By default, this setting is off. In EP 6.0, we turned this setting on by modifying a line in commerce-config.xml: onepage.enable=true. In EP 6.1, this setting value is no longer retrieved from commerce-config.xml (although the value may still be there depending on how it was handled during the code merge), but it is not being used. The setting value is now retrieved from the database via the new settings framework. We located the setting (COMMERCE/STORE/enableOnePageCheckout) and changed its value from false to true with a database update. After we were done modifying the OOTB setting values, we removed all unused setting definitions from the XML files.

 

Second, we had to migrate all of the custom settings we created to the new settings framework. We have approximately 60 custom settings -- much more than typical projects. Migrating custom settings is not absolutely required since they are still parsed from XML files and retrievable using the ElasticPath class, but there are many advantages of using the settings framework.

To migrate a custom setting, you first need to create the setting definition with a database insert statement. For instance, the following insert statement creates our "tradeshow timeout" setting:
INSERT INTO TSETTINGDEFINITION(UIDPK, PATH, DEFAULT_VALUE, VALUE_TYPE, DESCRIPTION, MAX_OVERRIDE_VALUES)
 VALUES(81, "CUSTOM/tradeshowTimeout", "120000", "Integer", "Indicates the tradeshow timeout interval, in seconds.", -1);
Next, find all the places in the code that use this setting. Modify the code to use the SettingsService to retrieve the setting value from the database instead of from the XML files (via ElasticPath). Going back to the example above, we make the following javascript change:
timeoutId = window.setTimeout("resetTradeshowPage()", $ctxStoreConfig.getSetting("CUSTOM/STORE/tradeshowTimeout").getValue());
...and the following java code change:
final String settingValue = getSettingsService().getSettingValue("CUSTOM/STORE/tradeshowTimeout").getValue();
 
During our merge, we went one extra step and implemented environment-specific settings, a feature that is not available out of the box and that required some additional customization. You can read more about environment-specific settings in this technical blog post on GREP.

 

5. Relocating the Assets Directory

 

In EP 6.1, the assets directory was moved outside of the war file. For example, storefront templates were previously located in com.elasticpath.sf/WEB-INF/templates/; they are now located in assets/themes/storecode/default/templates. Note that the storefront templates were not the only ones that were relocated; CM templates, like those used for order confirmation emails, were also moved from the com.elasticpath.sf project to the new assets directory. The relocation decouples the view (i.e. templates, images, etc.) from the model and controller (the application). There are many advantages to this, including the ability to easily hot-swap template changes. However, the relocated assets directory made the code merge more complex.

Depending on your merging tool, the automated code merge may handle the relocated assets directory differently. We used svn merge. Unfortunately, svn merge was not smart enough to realize that the assets were relocated; it assumed that the assets directory was simply removed from its old location and that a new assets directory was added to its new location. As a result, the files were not merged at all. The new assets directory was the OOTB version.

 

Thus, we needed to manually merge all of our template changes. This process is not as bad as it sounds, since Elastic Path did not make any major changes to the templates from EP 6.0 to EP 6.1. We merged most of the templates by first diffing the EP 6.0 and EP 6.1 versions and then adding those differences to our customized versions.
Some of the bigger template changes made between EP 6.0 and EP 6.1 include:
  • Retrieving the store and catalog not from the ElasticPath object anymore but from the new StoreConfig object
  • Using the #emailMessage macro (instead of the #springMessage macro) in the email templates to display localized messages
Also worth mentioning is the new layout of the assets directory. Previously, all templates where put into a single templates directory. In EP 6.1, there is support for multiple themes and store-specific templates. For instance, the view-cart.vm template file may live in /assets/themes/mytheme/store1/templates/velocity/shoppingCart; this means that the store whose storecode is "store1" and whose theme is "mytheme" will use that particular view-cart.vm template. Another store, whose theme setting is set to "anothertheme"and doesn't use store-specific templates would have its view-cart.vm template in /assets/themes/anothertheme/default/templates/velocity/shoppingCart. During the merge, we made sure to set up the assets directory structure in a way that would best work for us.

Note: I mentioned above that template files can now be easily hot-swapped. One thing to keep in mind is that by default, templates are cached when the application starts up. If you hot-swap or modify a template file, you need to force a cache refresh by invalidating the cache. A quick and easy way to do this is to open the
invalidate-cache.ep URL in a web browser.

 


6. Setting up Maven

 

EP 6.1 uses Maven to manage project dependencies. In the past, if a project required a component (e.g. a 3rd party library) that was not used OOTB, we would put that component in the libs directory. With Maven, there's no longer a need for a libs directory, so we were able to remove it altogether during our merge. There was one caveat however: we were using a 3rd party library for GeoIP lookups (Maxmind). We added the dependency to our GeoIP library by adding the following in the storefront's pom.xml file:
<dependency>
    <groupId>maxmind</groupId>
    <artifactId>geoip</artifactId>
    <version>1.2.1</version>
    <scope>compile</scope>
</dependency>
The storefront is now dependant on the Maxmind GeoIP component. However, Maxmind is not available OOTB so we also had to make sure that Maven would be able to download the library files from somewhere.
Elastic Path uses Archiva repositories to store the dependent libraries. Rather than adding the Maxmind files to the internal Elastic Path repositories, we decided to add it to our team's Archiva repository. Archiva has a nice web interface to upload jar files into the repository. We added the following to elasticpath.pom to tell Maven that it needed to look in our team's archiva repository (maven-ps.elasticpath.net) for some of its dependencies:
<repository>
    <id>ps-extras</id>
    <name>Elastic Path PS Extras Repository</name>
    <url>http://maven-ps.elasticpath.net:8080/archiva/repository/extras/</url>
    <releases>
        <enabled>true</enabled>
    </releases>
    <snapshots>
        <enabled>false</enabled>
    </snapshots>
</repository>

To sum up, setting up Maven should require no work if your project does not have any custom dependencies. If your project does have dependencies that are not included with OOTB Elastic Path, they will need to be defined in the project object model (POM) files.

 


Testing & Bug Fixing


Our QA team's first task was to verify that EP 6.1 worked on our test servers. We grabbed the OOTB public release version of EP 6.1, deployed it on our test machines, and ran through a smoke test. Once we were able to confirm that the OOTB EP 6.1 worked on our servers, we focused on our merged codebase.

 

The code merge modified numerous files across the entire project. As a result, a full regression test on all of our customizations was required to verify that the code merge was done correctly. It goes without saying that the full regression test took a considerable amount of time to complete. The faster the code is merged, compiled cleanly, and deployed to test servers, the sooner testing can begin. After merging the code, we pushed a testable build out as soon as we could so that our QA team could begin testing. The first half-dozen builds contained many blocking bugs, but they were still testable. The key is to fix the blocking bugs quickly so that the QA team can be kept busy with the full regression test.

 

The JUnit tests should also be run and fixed as soon as possible, preferably even before the first testable build is deployed; they are a great way to catch bugs at the source code level.

 

The new FIT tests in EP 6.1, however, were a little more difficult to run. They require some setup and many may be broken after the code merge depending on the customizations. We skipped the FIT tests during the code merge and instead chose to run them after the upgrade.

 


Time Estimates

 

There's no definitive answer for how long an upgrade will take. It depends on the amount and type of customizations. For our client's upgrade, the entire process -- including scoping, upgrading, testing, and bug fixing -- took three months. One developer completed the upgrade (i.e. database updates, code merge, etc.), two QA analysts performed the testing, and three developers tackled the bugs found by the testers. 8% of our budget was spend on scoping and estimating, 60% was spend on the actual upgrade tasks and bug fixing, and 32% was spent on testing.

 

These numbers will vary from project to project. For example, the client's custom settings required additional custom work, which took approximately two weeks to design and implement. This task is something we developed specifically for this project only.

 


Conclusion

 

Upgrading Elastic Path is neither trivial or impossible. Elastic Path provides documentation on the various aspects of upgrading to Elastic Path 6.1 (database updates, settings migration, assets relocation, etc.), but the complete story is different for each project. The amount of work depends on the number and type of customizations that have been made. If you have any questions or comments, feel free to post them here.

 

0 Comments Permalink

Alternative title: How to Make Your Life Easier and Not Go Bald from Pulling Your Hair out Trying to Keep Current on a Constantly Evolving and Shifting Codebase

 

This is probably the biggest and most avoided question from all of our successfully launched Professional Services projects. How can we upgrade to the greatest and latest on our heavily customized EP project? Let's be clear that performing a point release upgrade, or even consuming the latest sprint of code from our extremely productive Product Development group isn't trivial. A full version upgrade is even more daunting and usually heavily balanced against the cost of re-implementing from scratch.

 

First off, hopefully you are following our advice to try to avoid customizing EP code as far as possible, as noted in our documentation and tutorials. Following this methodology will make your life a lot easier, as upgrading core EP classes that have only minor changes will be a lot easier.

 

With that in mind, the best method through tried and tested experience, from brute force patching and merging, to re-implementing large customizations, is to take advantage of the merge tools from your chosen source control software (you are using source control I hope! If not, this book will be your best friend). Why do all the manual merge work when X does it so well already (X being subversion, perforce, cvs, vss, git, the next big flavor of the month). The key to leveraging your source control software to facilitate an upgrade is the concept of a vendor branch.

 

Working with a vendor branch is straight forward. This is applicable to any 3rd-party library you are using and modifying, not just EP. Take a quick gander at these various interweb sites for a better explanation than i can reasonably provide. For our purposes, a vendor branch for EP is an untainted, pristine copy of EP source. Don't just take our beloved zip of source code and stash it in your network drive! Check it in and show it off! You can branch your customized codeline off the vendor branch and start working away with the enthusiasm of a frenzied squirrel in the spring. The next time a new version of EP comes along, simply drop it directly on top of the current vendor branch of EP in your repository. With this new EP revision, you can perform your normal merge routine of just the diff between these EP revisions and merge the delta of changes into your customized eCommerce solution. And, if you have been following the procedures to avoid modifying EP source, conflicts should be kept to a minimum, files will just resolve themselves, and you can go out for a quick pint. Sure sounds easy huh? But how about in real life?

 

Well, let's see how we've taken this and made our lives easier at a client site in Perforce. I'm not the biggest Perforce fan, but I sure appreciate it's advanced branching and visual merging capabilities. We've set this up as follows:

 

  • EP_IMPORT, our EP vendor branch containing 100% pure EP 6.1 eCommerce goodness
  • Stable - our main development branch, full of customizations of the greatest and latest variety

 

Now, presume we're taking in change after massive change from our Product Development group. They've given us EP 6.1.1! Hooray! But how do we get this into our source control? Looks easy enough. Drop it on top of EP_IMPORT and check it in? Whoa, hold on there, code cowboy. This baby probably won't compile just with that.

 

The main things to remember is to collect three things with each new drop of code:

 

  1. All files that have been updated in 6.1.1
  2. All files that have been deleted in 6.1.1
  3. All files that have been added in 6.1.1

 

Once you have all three, you can mark the relevant files for delete, add and update. I've taken a short cut to calculate the files that fall into the above three buckets in this case. I have access to our internal subversion repository at EP, so I'm just going to take a log of files taken in by 'svn update' when updating from the 6.1 tag and the new 6.1.1 tag. You can essentially calculate the same bucket of files using the diff command. But in my case I'm just taking a shortcut and doing:

 

svn update > merge.txt

 

This logs out for us a lot of lines of this variety:

U    com.elasticpath.core/WEB-INF/src/main/java/com/elasticpath/service/rules/PromotionRuleDelegate.java
D    com.elasticpath.core/WEB-INF/src/main/java/com/elasticpath/service/misc/impl/WorkAroundOpenJPAFetchPlanHelperImpl.java
A    com.elasticpath.core/WEB-INF/src/main/java/com/elasticpath/service/misc/impl/OpenJPAEventListeningFetchPlanHelperImpl.java

 

With some help from sed (for the non-Unixers, feel free to grab and install cygwin, or your favorite port of the beloved Unix command line tools), I'm going to parse the log and split it into three files:

cat merge.txt | sed \-e '/D /d' | sed \-e '/U /d' | sed \-e 's/A[ ]*//' > adds.txt
cat merge.txt | sed \-e '/A /d' | sed \-e '/U /d' | sed \-e 's/D[ ]*//' > deletes.txt
cat merge.txt | sed \-e '/A /d' | sed \-e '/D /d' | sed \-e 's/[ ]*[U]*[ ]*//' > updates.txt

 

Now, Perforce is a bit finicky in that I need to mark which files I'm going to edit to remove the read-only permissions of relevant files. Sure, I can mark every file for editing, but let's play it safe:

pwd
/perforce/depot/branches/EP_IMPORT/
cat updates.txt | xargs p4 edit -f

 

Next, time to mark the deleted files for removal:

cat deletes.txt | xargs p4 delete -f

 

Finally, it's time to unzip on top all the files from the new EP 6.1.1 source zip and mark our new files for add:

tar -xvzf EP6.1.1_Export.tgz .
cat adds.txt | xargs p4 add -f

 

That does it! Now check that all in! Now we have EP 6.1.1 in our EP_IMPORT branch. Time to use the impressive P4V tool from Perforce to integrate from the EP_IMPORT branch into the Stable branch. Since we've avoided modify EP source as much as possible, the majority of the changes should auto-resolve. Clean up some of the conflicts and tweak the customizations as necessary, run the normal routine of compile, checkstyle, pmd, unit tests, integration tests and your project should now be ready to go. Okay, that's a gross over-simplication of the conflict resolution and regression testing process that goes hand in hand with a version upgrade, but hopefully you see how a vendor branch does wonders in facilitating an easier upgrade process with custom code. No more awkward patch files and brute force.

 

Assuming you don't have access to our subversion to get a hold of the list of changes, you can use diff to log file differences and files missing from the 6.1 and 6.1.1 codebases.

 

diff -r /perforce/depot/branches/EP_IMPORT /tmp/EP611/ > diffs.txt

 

This should give you a nice log that is easily parsed into the same add/delete/update buckets. So now you're freshly armed to do the upgrade that has been haunting you late at night. Vendor branches and merge tools are your new best friends! Happy upgrading and merging.

 

Drew

0 Comments Permalink

     

Elastic Path Commerce 6.1 introduces a number of changes from version 6.0.x. Primary among these are a major change to the store asset directory structure; movement of store configuration information from the file system to the database; and a number of minor changes to the existing database tables. As a result, 6.0.4 deployments with existing data can be upgraded to the 6.1 codebase with relocation of store assets; migration of configuration files into the database; and database upgrade scripts.

 

Note that it's assumed that the codebase has already been upgraded to 6.1; it's up to you to decide how code merge is done. It's also assumed that the existing deployment was already at the latest service release (6.0.4) before upgrading to 6.1.


Store Assets Relocation

Along with the XML configuration files, store-specific visual presentation elements used in the Storefront and emails have been moved from the WAR files into a central assets directory.  These include all Velocity templates, message properties files, images, javascript, css and Power Reviews.

 

  • The simplest way to move storefront assets out of the WAR file is to copy the directories com.elasticpath.sf/template-resources and com.elasticpath.sf/WEB-INF/templates to the new assets directory under a theme folder of your choosing. The assets directory will have the structure:

 

assets/themes/<theme_name>/<store_code>/templates

assets/themes/<theme_name>/<store_code>/template-resources

 

  • Email templates previously located in com.elasticpath.cm/WEB-INF/templates also need to be moved to the assets folder. Email templates and property files that are not connected to any particular store will need to be moved to: assets/cmassets/templates/velocity

 

  • Storefront related emails will be located under their respective theme folders: assets/themes/<theme_name>/<store_code>/templates/velocity

Configuration File Migration

Much of the configuration data previously in XML files within Elastic Path WAR directories has been moved into the database to be managed through the Settings framework in the CM. This includes commerce-config.xml, search-config.xml, urlrewrite.xml, intelligent-browsing.xml. Please consult the settings framework documentation before migrating configuration settings.

 

  • With the exception of web.sf.context.url, all settings previously in commerce-config.xml have been moved to the Settings framework and are no longer required to be in the XML file. Values in these settings (e.g. VFS paths/login) should be updated in the Settings framework through the CM Settings configuration view as new Setting values or inserted into tables TSETTINGVALUE where appropriate. Additional custom settings in commerce-config.xml file should be moved to the Settings framework as new Setting definitions in TSETTINGDEFINITION. A table of where settings in the commerce-config.xml reside in the settings framework is provided in Appendix A.

 

  • Content in intelligent-browsing.xml has been moved to the Settings framework and the file is no longer needed. Its contents should be inserted as a new Setting Value for the setting COMMERCE/STORE/FILTEREDNAVIGATION/filteredNavigationConfiguration

 

The content can also be copied into the CM Store Editor's Filtered Navigation section.

 

  • Content in urlrewrite.xml has been moved to the Settings framework and the file is no longer needed. Its contents should be inserted as a new Setting Value for the setting COMMERCE/SYSTEM/urlRewriteConfig

 

  • Content in search-config.xml has been moved to the Settings framework and the file is no longer needed. If any customization has been made, the Setting values under the paths COMMERCE/SEARCH/<setting> should be updated appropriately.

Database Upgrade

Upgrade SQL scripts are provided along with each release of Elastic Path to capture changes in the database schema between the new release and the latest service release.

Each supported database (MySQL, SQL Server, Oracle) will have its own upgrade script.

 

  • Upgrade scripts are provided in the 6.1 distribution for each database, and should be run by the tools provided by the database vendor.
  • Upgrade scripts will apply schema changes and insert necessary base data on an existing 6.0.x database, but does not change existing data.

 

After running the upgrade script, the steps can be done through the CM or directly through the database to get your deployment up and running:

 

  • Reassign supported currency and supported locales to existing stores in the CM, or insert entries in the TSTORESUPPORTEDCURRENCY and TSTORESUPPORTEDLOCALE respectively.
  • Change the display theme of existing stores appropriately by editing the COMMERCE/STORE/theme setting in either the System Configuration section of the CM or the Store Editor.
  • Set the correct value for the search server in the settings framework, under the path COMMERCE/SERVER/SEARCH/searchHost
  • Search indexes need to be rebuilt. This is an automatic step if old indexes are deleted.
  • Set the correct values for the asset VFS in the settings framework under COMMERCE/APPSPECIFIC/RCP/ASSETS/<setting>
  • Gift certificate themes need to be recreated through the CM, and assigned to stores in the CM Store Editor.
  • Be aware that stores can now only be accessed through the URL defined in the CM Store Editor (TSTORE table in the databse), and care should be taken when testing.

Caveats

  • The upgrade process cannot cover all possible database and code customizations to the 6.0.x codebase, and upgrade scripts should be reviewed before running on any schemas that you have customized.
  • Before moving existing storefront assets, be aware that there are changes in these files (Velocity templates, property files) that might not be picked up through a normal code merge due to the change in location.
  • New configuration settings introduced in 6.1 take on their default values after an upgrade, and should be reviewed for correctness.

 

Upgrading to 6.1 from 6.0.4 requires little database change. Configuration files and asset migration make up the bulk of the upgrading effort, and existing customizations to configuration and assets should be reviewed to take advantage of the new settings framework and asset repository.

0 Comments 0 References Permalink