# Using PatchExpert to Extend Your Code More Easily Blog

Version 2

 Contents Problem Introducing Pat chExpert Framework PatchExpert API Configuration File An Example of Using PatchExpert Pros and Cons Compared to an AOP Solution Conclusion Reference

It's often very difficult to apply extensions or patches to an existing application. Consider the steps required. First, a software developer has to modify some source code. Then a platform engineer rebuilds and repackages the system, creating a detailed installation guideline. Finally, a deployment engineer redeploys the software at customer site. Hopefully, it all works. Is there any method to make these tasks simpler?

PatchExpert is a simple tool to satisfy this requirement. It can insert software extensions or patches through some predefined extension points.

## Problem

Let's look at an example first to see how difficult it is to apply a patch to an existing application.

TestMain is a simple application used to print out an onscreen triangle of asterisk ("`*`") characters. It has a`Calculator` class to calculate the level of triangle according to the given integer and asks `TrianglePrint`to print out the triangle.

Here's the source code for a basic implementation.`Calculator` uses the Singletonpattern, and is used to figure out how many asterisks to print out. This implementation simply doubles the given argument.

``` ```
public class Calculator { static Calculator instance = new Calculator(); public static Calculator getInstance() { return instance; } protected Calculator() { } public int calc(int num) { return num * 2; } }```
```

`TrianglePrint` prints out the triangle line by line, according to the given level.

``` ```
public class TrianglePrint { int level; public TrianglePrint(int level) { this.level = level; } public void print() { for (int i = 1; i <= level; i++) System.out.println(getLine(i)); } protected String getLine(int num) { StringBuffer sb = new StringBuffer(); for(int i = 1; i <= num; i++) sb.append("*"); return sb.toString(); } public int getLevel() { return level; } }```
```

Finally, TestMain exercises the code by getting a`Calculator` instance, calling `calc()`, and sending the result on to `TrianglePrint`.

``` ```
public class TestMain { public static void main(String[] args) { Calculator c = Calculator.getInstance(); int num = c.calc(4); TrianglePrint printer = new TrianglePrint(num); printer.print(); } }```
```

The application will print out an ASCII art triangle like this:

``` ```
* ** *** **** ***** ****** ******* ********```
```

Now imagine that after the application has been deployed on the customer site, the requirements change: both the`Calculator` algorithm and `TrianglePrint`print behavior need to be changed. A patch should be applied to the software. Below are the tasks typically taken to achieve that goal.

The developer uses inheritance to minimize the changes applied directly to the existing source code. He needs to add two new classes and modify two of the original classes.

He creates `ModernCalculator`, a subclass of`Calculator`. It overrides `calc(int)` to provide a new algorithm that simply adds 1 to the given integer number instead of doubling it.

``` ```
public class ModernCalculator extends Calculator { public int calc(int num) { return num + 1; } }```
```

A new `FancyTrianglePrint` subclasses`TrianglePrint`. It overrides `getLine(int)`to generate a new string for the given line.

``` ```
public class FancyTrianglePrint extends TrianglePrint { public FancyTrianglePrint(int level) { super(level); } protected String getLine(int num) { int level = getLevel(); StringBuffer sb = new StringBuffer(); for (int t = 1; t <= level - num; t++) sb.append(" "); for(int t = 1; t <= num; t++) { sb.append("*"); if (t != num) sb.append(" "); } for (int t = 1; t <= level - num; t++) sb.append(" "); return sb.toString(); } }```
```

Now the new implementation classes are ready. But how to integrate them into the existing application? TestMain needs to be modified to use `FancyTrianglePrint` instead of`TrianglePrint`.

``` ```
public class TestMain { public static void main(String[] args) { Calculator c = Calculator.getInstance(); int num = c.calc(4);
//TrianglePrint printer = new TrianglePrint(num); TrianglePrint printer = new FancyTrianglePrint(num); printer.print(); } } ```
```
`Since Calculator uses a Singleton pattern, it should be modified to use a singleton instance ofModernCalculator instead ofCalculator.`
``` ```
public class Calculator {
//static Calculator instance = new Calculator(); static Calculator instance = new ModernCalculator(); ... }```
```

With changes to the project source, the platform engineer needs to add the new files to the project, rebuild the whole system, re-package it (for a big project, it is most likely that some modules need to be rebuilt and re-packaged) and ship it to the deployment engineer with a detailed patch installation guide.

The deployment engineer needs to install the patch on the customer site. The installation involves backing up old files and deleting, adding, or replacing files according to the patch installation guide.

Now the application with patch is ready to work. It prints out the triangle like this:

``` * * * * * * * * * * * * * * *
```

## Introducing PatchExpert

##### Framework

The java.net project PatchExpert is a simple tool to make extending and patching software easier. It allows the developer to define some extension points in the target application. Through these extension points, it can insert implementation at runtime or by configuration. Figures 1 and 2 demonstrate the relationship among these elements.

Figure 1. The relationship among elements

Figure 2. The relationship among elements

The software architect decides where the software can be extended. At these extension points, the developer makes a call to PatchExpert, providing a name for the extension point.

There can be many different implementations to be inserted into the extension point. Of course, these implementations should have something in common. They often have the same superclass or implement the same interface.

An external XML configuration file is used to map the named extension point to a specific implementation. Of course, this means it is possible to change implementations without touching the original code.

##### PatchExpert API

`ObjectFactory` is the main class of PatchExpert. Let's check the methods in this class one by one.

• `public static ObjectFactory getInstance()`

This is the factory method. It always returns the singleton instance of `ObjectFactory`.

• `public Object newObject(String module, String name)`

This method creates an implementation instance for a specific extension point. The parameter `module` is the module name of the extension point. It acts like a namespace to avoid name collision. The parameter `name` specifies the extension point in the module. This method is suitable for an implementation class with an accessible default constructor.

• `public Object newObject(String module, String name, ClassLoader cl)`

This method is almost the same as `newObject(String module, String name)`. The only difference is that it uses`cl` to specify which class loader is used to load the implementation class.

• `public Object newObject(String module, String name, Class[] paramTypes, Object[] paramValues)`

This method is used when the implementation class has a non-default accessible constructor. The parameter`paramTypes` is used to specify the constructor signature, while `paramValues` specifies the parameters for the constructor.

• `public Object newObject(String module, String name, Class[] paramTypes, Object[] paramValues, ClassLoader cl)`

This method is almost the same as `newObject(String module, String name, Class[] paramTypes, Object[] paramValues)`, except that it uses the given class loader `cl` to load the implementation class.

These `newObject()` methods only specify the extension point and how to initialize the implementation instance. They have no knowledge about which implementation class will be used for that extension point. It is the external configuration file's responsibility to combine a specific implementation class with the extension point.

• `public void putClassConfig(String moduleName, String name, String className)`

This method is used to change the combination of implementation class and extension point at runtime. The parameter`className` gives the full name of the implementation class. The effect of this method will overwrite the setting in the external configuration file.

• `public void refresh()`

This method is used to refresh the combination of implementation class and extension point at runtime. It can be called after the external configuration file has changed.

##### Configuration File

The configuration file is where you specify implementation classes for extension points. The default configuration file name is classfactory.xml. If needed, this name can be changed through the system property`org.jingle.patchexpert.configname`. The configuration file should be placed in the META-INF directory, which can be accessed by class path or .jar file.

Below is a template of the configuration file.

``` ```
<?xml version="1.0" encoding="UTF-8"?> <application> <module name="moduleName"> <extPoint className="class.full.name" name="pointName"/> ... <extPoint .../> </module> ... <module ...> ... </module> <patch name="patchfile.xml"/> ... <patch .../> </application>```
```
• The configuration file should have a root tag`application`.
• There can be zero or more `module` tags and`patch` tags under the `application`tag.
• The `module` tag acts like a namespace. It contains zero or more `extPoint` sub-elements.
• The `extPoint` tag combines the extension point with an implementation class name to define an extension point.
• The `patch` tag is used to specify the patch configuration file location, which is relative to theMETA-INF directory. The patch configuration file has the same format and its settings will overwrite the original settings.
There may be more than one accessible configuration file in an application. When the `ObjectFactory` is initialized, it loads all of the accessible configuration files, according to the opposite order of the class path. Configuration file settings loaded later will overwrite previous ones.

## An Example of Using PatchExpert

Now let's apply PatchExpert to the previous example. The code has only a few changes.

The `TrianglePrint` instance creation is an extension point. Instead of creating an explicit `TrianglePrint`instance, we create an implementation instance for the extension point `printer` in the module `triangle`. The implementation class should have an accessible constructor with an`int` parameter.

``` ```
public class TestMain { public static void main(String[] args) { Calculator c = Calculator.getInstance(); int num = c.calc(4);
//TrianglePrint printer = new TrianglePrint(num); TrianglePrint printer = (TrianglePrint) ObjectFactory.getInstance().newObject( "triangle", "printer", new Class[] {Integer.TYPE}, new Object[] {new Integer(num)}); printer.print(); } }```
```

There's another extension point where the`Calculator` singleton instance is created. We create an implementation instance for the extension point `cal` in the module `calculator` here. The implementation class should have an accessible default constructor.

``` ```
public class Calculator {
//static Calculator instance = new Calculator(); static Calculator instance = (Calculator) ObjectFactory.getInstance().newObject( "calculator", "cal"); public static Calculator getInstance() { return instance; } protected Calculator() { } public int calc(int num) { return num * 2; } }```
```

Now you need a classfactory.xml file, under theMETA-INF directory and inside of the targetsample.jar file.

``` ```
<?xml version="1.0" encoding="UTF-8"?> <application> <module name="triangle"> <extPoint className="TrianglePrint" name="printer"/> </module> <module name="calculator"> <extPoint className="Calculator" name="cal"/> </module> </application>```
```

This configuration file connects the actual implementation classes to the extension points.

The target sample.jar file is deployed on the customer site. Now look at how the requirements change is handled when PatchExpert is used.

The developer provides two new classes,`ModernCalculator` and `FancyTrianglePrint`, as before. There is no modification applied to the old source code. This can reduce the risk of introducing new bugs when fixing old ones.

The platform engineer builds the new Java files with the original sample.jar and packages the new Java classes intopatch.jar with a `classfactory.xml` under theMETA-INF directory.

``` ```
<?xml version="1.0" encoding="UTF-8"?> <application> <module name="triangle"> <extPoint className="FancyTrianglePrint" name="printer"/> </module> <module name="calculator"> <extPoint className="ModernCalculator" name="cal"/> </module> </application>```
```
This is a much lighter workload compared to rebuilding the whole system. And there is no need to re-package the system. Only the newly created patch.jar is shipped to the deployment engineer.

The deployment engineer just drops the patch.jar file into the library directory and makes sure that it appears beforesample.jar in the class path.

That's all. Now the patch works. It is much easier than before, isn't it?

## Pros and Cons Compared to an AOP Solution

Aspect-Oriented Programming (AOP) is another commonly used technique to provide extensions and patches to an existing application. The AOP approach and PatchExpert both try to avoid touching the old system in order to reduce the upgrade risk. But at the byte-code level, the AOP compiler will insert some byte code into old class files while compiling the new aspect. Compared to the AOP approach, PatchExpert has the following pros and cons:

Pros:

• AOP's byte-code-level change may require the rebuilding and repackaging of a whole module or system. And the deployment engineer still has many things to do: backing up old files and deleting, adding, or replacing files according to the patch installation guide. A PatchExpert approach is free of this workload.
• With the help of PatchExpert, the target application can switch implementations via an edit of the external configuration file. In some cases, it can even switch the implementation at runtime.
• With PatchExpert, it is very easy to discard the extension or patch and roll back to the original version. No build is required; just delete the add-on patch package.

Cons:

• For PatchExpert to work, it has to be part of the application framework. This means it should be integrated at the beginning of the software design process. You cannot use PatchExpert to apply a patch to an application that does not already use PatchExpert. In this case, an AOP solution is much more flexible, since an AOP approach can be used regardless of whether the original application uses AOP or not.
• PatchExpert asks the architect to think carefully in the design phase about where extension points should go. AOP has no such requirement; it can define arbitrary "point cuts" as its extension points.

## Conclusion

PatchExpert can simplify the task of applying extensions or patches to an existing application. It just adds the patch package without touching the original system. This reduces the risk of introducing new bugs when fixing old ones. In the meantime, it makes the rolling back easier: it's no more complicated than deleting the add-on patch package.

Of course, PatchExpert can be used in other domains, such as software integration testing. For example, when the integration test depends on external services that are not currently available, it is very easy to continue the test by adding mock services into the test environment without touching the source code. When the external services are available, just remove the mock services and test again.