Technical Blog

6 Posts tagged with the 6.2 tag

Having fun with SWT

Posted by Arman Sharif Sep 9, 2011
Background

Being new to the SWT I wanted to learn a little about the API by making a simple change to the Commerce Manager UI. I put this post together with the hope that it might have some useful tidbits for other SWT newbies out there.

 

Goal

The CM client displays a product icon in the catalog's Product Listing view. The icon may vary depending on whether the product is a bundle or has multiple SKUs, but otherwise it is the same icon for every product. To make things more interesting I decided to customise the view to generate an icon specific to each individual product. In the real world, the image location would probably come from a product attribute. To keep things simple however we will simply generate a small square image with a random background colour.

 

 

Solution

 

To achieve our goal we will create a new class ProductIconImageRegistry. This class will be responsible for creating SWT product image icons that can be obtained via the following get(Product) method.

 

/**
* Returns an image for the given product.
*/
public Image get(final Product product) {
     final Long key = product.getUidPk();
     Image image = imageCache.get(key);
 
     if (image == null) {
          if (isCacheFull()) {
               freeCache();
          }
               
          image = getProductIcon(product);
          addToCache(key, image);
     }
          
     return image;
}

 

 

Because every new SWT image instance requires an allocation of OS resources, we will cache the icons in a hash map. To keep the cache from growing indefinitely we will define an upper limit and free up some cache when it reaches the maximum size.

 

Two important rules to bear in mind (see References) when working with SWT components are:

 

    "If you created it, you dispose it."

    "Disposing the parent disposes the children"

 

The rules apply to a number of SWT classes including Image, Color, Font, Widget, GC, and so forth. If you invoke a constructor to instantiate one of these classes, you must free them using the dispose() method.

 

Color color = new Color(...); // allocates platform resources
color.dispose();

 

However if you acquire an instance without calling the constructor there is no need to dispose().

 

Color color = display.getSystemColor(SWT.COLOR_BLUE);

 

In the case of the ProductIconImageRegistry class, we are creating a new icon image as follows:

 

/**
  * Returns an icon for the given product.
  */
private Image getProductIcon(final Product product) {
     final Display display = Display.getCurrent();
     final Color color = createRandomColor(display);
     final Image iconImage = createIconImage(display, color);
     return iconImage;
}
 
/**
  * Creates a random Color.
  */
private Color createRandomColor(final Display display) {
     final int red = random.nextInt(256);
     final int green = random.nextInt(256);
     final int blue = random.nextInt(256);
     return new Color(display, red, green, blue);
}
 
/**
  * Creates an Image with the specified background Color.
  */
private Image createIconImage(final Display display, final Color color) {
     final Image image = new Image(display, ICON_LENGTH, ICON_LENGTH);
     final GC gc = new GC(image);
     gc.setBackground(color);
     gc.fillRectangle(0, 0, ICON_LENGTH, ICON_LENGTH);
     
     drawIconBorder(gc, display.getSystemColor(SWT.COLOR_GRAY));
     gc.dispose();
     return image;
}
 
/**
  * Draws a border around the icon.
  */
private void drawIconBorder(final GC gc, final Color borderColor) {
     final int border = ICON_LENGTH - 1;
     gc.setForeground(borderColor);
     gc.drawLine(0, 0, 0, border);
     gc.drawLine(0, 0, border, 0);
     gc.drawLine(0, border, border, border);
     gc.drawLine(border, 0, border, border);
}

 

 

Our freeCache() method will simply purge a tenth of its contents and call dispose() on every removed image.

 

private void freeCache() {
     int removeQty = CACHE_SIZE / 10;
     for (int i = 0; i < removeQty; i++) {
          final Long removedKey = cacheKeys.removeFirst();
          final Image removedImage = imageCache.remove(removedKey);
          removedImage.dispose();
     }
}

 

We will also provide a disposeAllImages() method on the ProductIconImageRegistry class to allow the client code purge everything on shutdown.

 

public void disposeAllImages() {
     for (Long key : imageCache.keySet()) {
          final Image image = imageCache.get(key);
          image.dispose();
     }
     imageCache.clear();
     cacheKeys.clear();
}
 

 

Finally, we need to plug in our new class into the existing CatalogImageRegistry and CoreImageRegistry classes. This can be done by updating the getImageForProduct(Product) method:

 

public static Image getImageForProduct(final Product product) {
     if (product instanceof ProductBundle) {
          return getImage(PRODUCT_BUNDLE);
     }
          
     if (product.hasMultipleSkus()) {
          return getImage(PRODUCT_MULTI_SKU);
     }
          
     return getImage(PRODUCT);
}

 

and replacing the last line with

 

return productIconImageRegistry.get(product);

 

We also need to hook in the disposeAllImages() method:

 

static void disposeAllImages() {
     for (final ImageDescriptor desc : IMAGES_MAP.keySet()) {
          final Image image = IMAGES_MAP.get(desc);
          if (!image.isDisposed()) {
               image.dispose();
          }
     }
 
     productIconImageRegistry.disposeAllImages();
}

 

With the all pieces together, the final result looks as shown in the screen shot. The icons in the Product Listing view are provided by the CatalogImageRegistry class.

 

grep-cmclient.png

 

The CoreImageRegistry class provides icons for the Select a Product dialog, which looks as follows with the changes in place:

 

grep-cmclient-search.png

 

 

 

References

 

http://www.eclipse.org/articles/Article-SWT-images/graphics-resources.html

http://www.eclipse.org/articles/swt-design-2/swt-design-2.html

http://eclipse.org/articles/Article-SWT-graphics/SWT_graphics.html

0 Comments Permalink

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

Elastic Path Commerce version 6.2 was released in January with little fanfare, but don’t let that fool you; 6.2 is packed with lots of advanced ecommerce features. This release was all about giving merchants more flexibility in terms of how they sell their products. One of the big features we added was bundling (or kitting, if you prefer). Bundling gives merchants the ability to configure groups of products that can be sold as package deals. This gives their customers greater value and simplifies their purchase decisions. For merchants who wish to give their customers the value of package deals, but flexibility of choice, they can use dynamic bundles. Dynamic bundles give customers the choice between several merchant-defined options.

 

Many merchants will also be happy to learn that we've moved prices out of the catalog and into price lists. And by linking price lists to our targeted selling framework,  we’ve given merchants the ability to target price lists to different markets and customer segments. For B2B merchants, price lists are a great way to manage negotiated contract pricing for different accounts.

 

In 6.2, we've also introduced the ability to personalize products. By creating a configurable product type, merchants can give their customers the power to customize products before checkout. A good example would be a custom screening printing site that allows shoppers to upload the designs they want to print on their T-shirts.

 

For store managers and IT staff involved in store operations, the new staging to production feature will be tremendously useful. It allows changes to products, prices, promotions and marketing content to be previewed in a staging environment, and submitted for review and approval before being pushed over to the production environment.

 

For the tech folks, the 6.2 release includes support for new versions of various application servers, Java 6 support, and an upgrade to JPA 1.2.1. Storefront performance has also been improved with the addition of multi-level caching and other performance enhancements. 6.2 includes upgrade scripts, which should allow existing clients to upgrade quickly and make use of all the new features that 6.2 has to offer.

 

For more information, check out the 6.2.0 release notes and stay tuned for blog posts looking more in depth at some of these exciting, new features.

0 Comments Permalink

Bundles – package deals, value packages, savings packs, whatever you call them are everywhere in the marketplace and are becoming an indispensable online merchandising tool. At their simplest, they are just a collection of products intended to be marketed and sold together. The upcoming platform release of EP (6.2) strives to provide flexibility and ease of use for you to incorporate bundling into your overall merchandising strategy. In advance of that release, over the course of the next few EP Insider posts, I want to discuss what they are and how they work in EP as well as the thinking behind our decisions – both technical and business.


There are lots of reasons for using bundles and you know them best for your market. Probably the most common is simply increasing average order size by offering savings across a group of items, for example, “Buy this Xbox 360 together with Halo 3 for $X”, where $X is just enough less than the combined price of the two items to encourage the shopper to spend more by buying them together. There’s also the ability to move less desirable surplus product by bundling it with other more desirable items, for example, Buy this Xbox 360 together with Pong for $Y, where $Y is sufficiently more than the price of the Xbox to yield an effective unit price for the Pong game that you’d never get selling Pong by itself. Or there’s the situation that I’m facing this Christmas since I’ve finally broken down and decided to buy a Wii for my kids. (I think I can safely assume they won’t be reading this post.) As a confused, middle-aged gaming newbie, I’m perfectly willing to pay a little bit more for a "pre-configured" bundle where everything is guaranteed to be compatible.

 

Regardless of the marketing motivation, bundles are essentially made up of two parts: the bundle itself and the collection of items inside it. So bundles contain products but are also products themselves. That is to say, in EP, we have modeled the bundle itself as a product, albeit a special kind. With this approach, basically anything you’re used to doing with a product, you can do with a bundle. You can manage it as a single entity in your catalog. You can give it a price (or prices). You can associate it with other products (upsell or cross sell). You can promote it, feature it, find it, etc. And in the storefront, just like any product can present itself via the basic template, any bundles will present themselves using a bundle-specific template. A bundle will show up in searches or other lists of products and its details can be viewed in the context of a product details page. If it’s what the shopper wants, they can add it to their cart with the click of a single button just like any other product. Additionally, your shoppers will find them first. If a shopper searches for “xbox”, the bundles containing Xboxes will be shown above the Xboxes themselves - the assumption here being that a larger order size is always a safe default goal.

 

Since bundles contain products but are also products themselves, guess what? Bundles can contain other bundles. We call these nested bundles. This provides significant flexibility in both offering and managing bundles. Smaller, foundational bundles can be re-used across many parent bundles. Think of the "gamer's accessory pack" that includes a game and extra controller. This pack could then be nested in various parent bundles that hold different models of the base gaming console. How far can you go with this? Well, theoretically the model supports infinite nesting, but for practical purposes, we have cut it off at three levels of nesting, which, when combined with the top level parent, allows for a total of four levels of bundles. Much beyond this and I think you're taxing anyone's mental model of something worth buying, let alone worth managing.

 

Earlier, I said that bundles are "marketed and sold together." I didn't include "delivered." This is key. A bundle is useful for defining a collection to be offered in a store, but the actual order and its subsequent fulfillment are more about the individual items. In the early stages of the ecommerce lifecycle (catalog management, display in the storefront, etc.) the emphasis is on the bundle that knows about its items. But in the downstream stages (order processing, fulfillment), the emphasis is on the items that know about their parent bundle.

 

There's always the special case of the "shrink-wrapped" bundle, but when you think about it, this is just a regular single product. If three things are managed, sold, processed, and delivered as a whole – a “shrink-wrapped” package - it's really no more a bundle than a shirt that is made up of a collar, two sleeves and some buttons. The shirt has to be kept together to be of any value but for a real bundle – say, the Xbox  and a downloadable game the items have appeal when offered together, even though they’re ultimately split up for fulfillment. You explicitly create bundles if, at various points in the ecommerce lifecycle, your system is interested in the collection and at other points it’s more interested in the items.

 

That’s our view of bundles from the stratosphere. Over the next few blog posts, I'll drop down a few thousand feet and cover some of these sub-features...

  • If the bundle means the shopper gets everything, it’s fixed but if you want to offer some choice for one or more of the items, then it's a Dynamic Bundle.
  • If one or more of those choices is worth more than other choices, you may want to charge more - that's a Price Adjustment.
  • If selling the bundle depends on the availability of the items then Bundles and Inventory become key.
  • To be able to ship items separately and/or accept returns and exchanges, you need to have Apportioned Pricing for each item.
0 Comments Permalink

Prices are moving out

Posted by Michael Vax Oct 20, 2009

The upcoming 6.2 release of Elastic Path will include some big changes to price management. Currently, prices are a property of the product and live inside the catalog. This means the only way to have multiple prices for the same product is to use virtual catalogs. That's fine if you want to have different prices in different stores, but it doesn't help if you need to have multiple prices for the same product in the same store.

     

In 6.2, prices are getting lives of their own. They're moving out of catalogs.

     

There are several business and technical drivers behind this change:

 

  • In many enterprises, different systems are used to manage pricing and catalog information. This means different update cycles and integration points.
  • It is not uncommon to distribute responsibilities for maintaining pricing and catalog data between different departments or people.
  • Online retailers want to have flexibility to price products differently for different customer segments. For example, you may want to offer better prices to registered users.
  • The ability to support multiple price lists is especially important in B2B environments where prices can be determined by the contract with each business customer.
  • By separating Price from Product, it would be possible to cache other product information in memory, which would significantly improve storefront performance.

     

In 6.2, all price information (price tiers, sale and list prices, etc.) is now stored in price lists. A price list contains prices in one currency only. If your store supports multiple currencies, you will need to create a separate price list for each currency.

     

    FromCatalogToPL.jpg

     

 

There will be a new way to manage prices in Commerce Manager. There will be a Price List Manager activity that provides a way to manage a set of product prices from price list's perspective. Users will still be able to use the Pricing tab in the Product Editor to manage prices for a product, but under the hood, the prices are actually stored in multiple price lists, not in the Catalog.

 

Commerce Manager permissions have been extended to separate responsibilities for managing catalog from managing price information.

     

Separation of prices from catalogs is also reflected in EP's import/export features. When exporting catalogs using the Import-Export tool, the exported catalog data will not include price information anymore. Price lists will be imported and exported using Price List Import / Export instead. And in the Commerce Manager, it will be possible to import price lists in CSV format as well.

     

In 6.2 you will be able to define any number of price lists and use them with more than one catalog across multiple stores. Let's see how this works.

     

A Commerce Manager user associates a Price List with a Catalog by creating a Price List  Assignment (PLA).

    PLA.jpg

     

     

Each PLA has a priority and, optionally, some targeted selling conditions that determine which shoppers are eligible for the price list. These conditions use the same tags that are used to determine which Dynamic Content shoppers see in the storefront. A Price List Assignment is very similar to a Dynamic Content Delivery. For more information, see the blog posts on the Tagging Framework and Dynamic Content.

 

Users can associate multiple Price Lists with a catalog by creating multiple Price List Assignments, each with different priorities and targeted selling conditions.

    PLAs.jpg

     

By evaluating PLA conditions against the shopper's tag set, EP builds a Price List Stack from Price Lists that meet the targeted selling conditions. Price Lists are arranged in the stack according to their priorities. To determine a product's price, the system goes through the Price Lists in the stack until it finds the first price list that contains a price for the product.This means that it is not required for a Price List to have prices for all products in the Catalog. If, for example, you have different people managing prices for different product categories, you can create separate price lists and assign them all to the same catalog.

PL Stack.jpg

Price management is a complex area, and required quite a bit of upfront design and refactoring many points of the application. Being able to leverage the Tagging Framework for Price List Assignment was a big help. A lot of customers are really looking forward to this, so it was definitely worth the effort. We have a couple other big features coming in 6.2 and I'll try to take a few moments to talk about them in the next couple weeks.

0 Comments Permalink