In order to extend the design pattern plug-in with custom design patterns (or other additional functionality), you will have to obtain the corresponding Eclipse projects from its website at http://eloquence.sourceforge.net. There are the following four projects:
Add these projects to your workspace. You can run the plug-in in a separate run-time workspace to see the effects of any changes that you make without requiring to go through the cycle of installing and, possibly, deinstalling the design pattern plug-in each time. Before doing this, please deinstall any concurrently existing installations of the design pattern plug-in in your workspace in order to avoid any possible conflicts. Then, select
from the workbench menu of Eclipse.
The following dialog will appear:
To run the plug-in in a separate run-time workspace, create an Eclipse Application entry as shown in the screenshot. Running this task will open a separate instance of Eclipse that has its own workspace and that contains the plug-in. Having completed any possible extension to the design pattern plug-in, you can distribute it in the usual manner by building the 'plugin', 'plugin feature', and 'plugin updatesite' projects in sequence. By putting the contents of the updatesite into a local folder or onto a remote webserver, you can use the Eclipse configuration manager to install and deinstall the plug-in.
The most common extension of the design pattern plug-in will be custom design patterns; the procedure to add a custom design pattern consists of three steps:
In the following, we will describe each of these steps in more detail.
The first step, adding an entry to the design pattern library file, makes the design pattern known to the plug-in. This is done by adding an entry similar to the following one to the library.xml file residing in the root of the 'plugin' project:
<design-pattern name="Sample"> <type>net.sourceforge.eloquence.plugin.designpatterns.DesignPattern</type> <path>sample/</path> <file>sample/Sample</file> </design-pattern>
This adds the 'Sample' design pattern to the library. The plug-in represents all design patterns as objects which are of the type DesignPattern or which extend this type. The particular type used is specified in the <type> element of the design pattern. Usually, using DesignPattern is sufficient for most design patterns, but a different type may be useful in particular situations-- for example, if additional state information needs to be kept. The <file> and <path> elements determine the location of the file holding the design pattern meta-information as well as the path for the templates to be instantiated. These locations are relative to the library folder. The path needs to end with a /, and the file may not have an extension (because the appropriate extension is determined by the plug-in itself). You are able to organise design patterns within categories-- looking at the provided library.xml file probably best illustrates how to accomplish this.
The second step, describing the design pattern meta-information, consists of defining an XML file with information on the design pattern. This XML file needs to be placed and named as defined in the <file> attribute of the library.xml file-- for the 'Sample' example, it would be sample/Sample.xml. The XML file defines the following information:
The following corresponds to an abridged version of the XML file of 'Sample':
<design-pattern> <name>Sample</name> <id>SampleDP</id> <code-mapping isImplemented="true" reservedTypeNames="SampleDP"> <code-file template="Sample.aj" name="SampleDP#SamplePA" type=".aj" /> <code-element ignoreAsSkeleton="true" name="Sample Pattern Aspect" id="SamplePA" /> <code-element name="Role 1" id="Role1" type="class" /> <code-element name="Role 2" id="Role2" type="class" /> </code-mapping> <catalog-information> <name>Sample</name> <intent></intent> ... <special-remarks></special-remarks> </catalog-information> </design-pattern>
Please also have a look at the existing XML files of the design patterns in the library to get a feeling of what information is represented how in these files. The <name> and <id> elements are fairly straightforward, but the rest of the elements requires the following more detailed explanations:
The templates folder of the 'plugin' project contains an empty template for the XML file as well as DTD and XSD documents which can be used to validate the XML file. It is important that all XML files generated or modified in the process of adding custom design patterns to the design pattern plug-in validate against the DTD or XSD; otherwise, the design pattern plug-in may not function properly.
The third step, generating the templates to be instantiated, completes the addition of a custom design pattern. For each of the code files defined in the design pattern XML file, create the corresponding template. This template can be a class, interface, aspect, and so on. It may contain strings of the form design-pattern-id#code-element-id. The template instantiator replaces these strings by values provided by the user in the mapping stage of the integration wizard. For example, suppose the ID of the design pattern is SampleDP and code elements with the IDs Role1 and Role2 have been defined for a code file Sample.aj. Then, all matches of the strings SampleDP#Role1 and SampleDP#Role2, respectively, in Sample.aj would be replaced by the strings that the user defines in the mapping stage of the integration wizard. In more detail, this could be a possible Sample.aj:
public aspect SampleDP#SamplePA { public interface Role1{}; public interface Role2{}; declare parents : SampleDP#Role1 implements Role1; declare parents : SampleDP#Role2 implements Role2; protected pointcut role1StateChange() : call(* SampleDP#Role1.*()); protected pointcut role2StateChange() : call(* SampleDP#Role2.*()); before() : role1StateChange() || role2StateChange() { ... } after() : role1StateChange() || role2StateChange() { ... } }
Now suppose that the user defines SamplePA=SamplePA as well as Role1=ClassA and Role2=ClassB in the mapping stage of the integration wizard. The template instantiator would then produce the following instantiation of the template:
public aspect SamplePA { public interface Role1{}; public interface Role2{}; declare parents : ClassA implements Role1; declare parents : ClassB implements Role2; protected pointcut role1StateChange() : call(* ClassA.*()); protected pointcut role2StateChange() : call(* ClassB.*()); before() : role1StateChange() || role2StateChange() { ... } after() : role1StateChange() || role2StateChange() { ... } }
This example concludes the discussion of the extension of the Eloquence design pattern plug-in library with custom design patterns.