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

Recently, I needed to reproduce a problem that was only occurring when the storefront was under heavy load. As a developer, I cannot easily generate realistic load in my environment and I don't have access to a live production system, so I used JMeter to help me out. JMeter is a Java application for performing load tests on web applications. In this post, I'll show how to use JMeter to quickly set up a simple performance test against the Elastic Path Commerce storefront.

 

I wanted to see how long it would take to perform a search in the storefront for Canon products. In this case, I wanted JMeter to fire the following query a few hundred times using one or more threads: http://demo.elasticpath.com:8080/storefront/search.ep?categoryId=&keyWords=canon&submit=search

 

First, I created a thread group under the test plan tree node. (Right-click the test plan and choose Add->Thread Group.) If you want to simulate more than one user hitting the same search at the same time, you can set the number of threads in the thread group configuration.

img1_1.png

 

Next, I added a loop controller to my thread group. (Right-click the thread group and click Add->Logic Controller->Loop Controller.) Here, I defined how many times the loop will run. In my case, I checked the Infinite checkbox.

img2.png

 

Then, I added an HTTP request to the loop controller. (Right-clicking the loop controller and click Add->Sampler->HTTP Request.) I set the Server Name, Server Port, URL Path, chose GET in the dropdown and set three parameters in the request URL.

img3_1.png

 

At this point, I started the test by clicking Run->Start. JMeter starts to execute the HTTP request I defined in the loop controller. Since I set the loop count to Forever, it will continue to execute until I stop it.

 

Now, it would be a good idea to attach some reports to debug the execution. I tried a few reports and found that the View Results Tree presented all the information I needed. It shows the raw request sent by JMeter and the response data the server is providing. You can examine the server response to make sure the HTTP request you configured is doing what it is expected to do.

 

To add a View Results Tree report to your test plan, right-click your HTTP request test, and choose Add->Listener->View Results Tree.

You can finally see the results of each call on the report.

 

img4.png

 

You can build more complex tests, with several simultaneous requests over different URLs. For example, you can configure JMeter to first simulate a user logging in to your application (and hold session information), then a few requests to simulate the user navigating through the web application and then repeat this test a few hundred times using as many threads as you want (or your machine can handle).

 

Using JMeter, I was able to simulate a sufficently heavy load to reproduce the problem I wanted to reproduce and this post should help you do the same thing if you face a similar problem. For more details on JMeter, go to: http://jakarta.apache.org/jmeter/

 

Hope you enjoy!

2 Comments Permalink