Plugging Into AcmeStudio

In addition to standard Eclipse extensions, AcmeStudio defines a number of additional extension points that allow hooking in to AcmeStudio. This section provides examples of how to use these extensions.

Hooking into AcmeStudio

AcmeStudio allows plugins to access various aspects of AcmeStudio, in addition to well-defined plugin points. Currently, plugins can see all of the classes defined by AcmeStudio. This is as powerful as it is dangerous, so using these classes should be done carefully.

In general, each plugin has access to the AcmeLib internal data structure for any design in AcmeStudio. The design associated with the currently active editor can be retrieved through the ASContext class:

AcmeStudio.core.ASContext.current ().getActiveDesign ();

For a plugin to play nicely with AcmeStudio, it should listen for changes to the AcmeDesign that may be made by AcmeStudio, as well as report any changes that it makes to the design. This is done through a publish-subscribe bus implemented in AcmeStudio.util.AcmeStudioChangeManager. To register with this bus, a listener must implement the AcmeModelChangeListener interface, which contains the following methods:

/**

 * This method is called by the change bus when a model is changed

 * @param evt The event causing the change to occur

 */

public void changeModel (AcmeStudioChangeManager.AcmeStudioChangeEvent evt);

 

/**

 * Lets parties register their interest in particular types of events

 * @param eventType The type of event being queried, which will be an int defined in AcmeStudioChangeManager

 * @return whether the party is interested in this type of event. If it is, changeModel will be called. If not, changeModel

 *            will not be called.

 */

public boolean interestedInEvent (int eventType);

 

A plugin registers to the bus by calling: AcmeStudioChangeManager.registerListener, passing itself as a parameter.

Furthermore, when making changes to the design, a plugin must announce this change to the bus (in addition to changing the model), by calling AcmeStudioChangeManager.globalChangeManager.on*, passing the appropriate data.

Annotating the Design

In many instances, plugins may wish to annotate an architectural diagram with additional information that needs to be saved along with the system. For example, legends in AcmeStudio are saved in an XML file that is associated with an Acme system, and is loaded and saved whenever the design is loaded and saved. Similarly, visual information such as x,y coordinates and width and height are saved separately to the design in AcmeStudio.

Saving additional information is done through the dataPersistence extension. Extensions must implement the AcmeStudio.core.resource.datapersistence.IDataPersistence interface with the following methods:

/**

 * Called immediately after an AcmeDesign is loaded into AcmeStudio. Subclasses should override

 * to load plugin-specific information about the design.

 * @param design The design that was loaded

 * @param resource The file that the design was loaded from

 */

public void load (AcmeDesign design, File resource);

/**

 * Called immediately after an AcmeDesign is saved by AcmeStudio. Subclasses should override

 * to save plugin-specific information about the design

 * @param design The Acme design that was saved

 * @param resource The file to which the design was saved

 */

public void save (AcmeDesign design, File resource) ;

/**

 * Returns the data to be persisted that is in the design. The object returned

 * will be passed back into injectData.

 * @param design The design containing the data

 * @return the data to be persisted

*/

public Object extractData (AcmeDesign design);

/**

 * Annotates the design with data. The data passed in will have been retrieved

 * by a call to extractData

 * @param design The design to annotae

 * @param data The data do annotate with

*/

public void injectData (AcmeDesign design, Object data);

 

To hook into the extension, the extension point must be referenced in the plugin.xml of your AcmeStudio plugin.

<extension id="your-id" point="AcmeStudio.dataPersistence">

      <dataPersistence name="your-name"  class="your.class"

            id="your-id">

      </dataPersistence>

</extension>

 

Extending the Diagram Editor

It is possible to extend AcmeStudio to add your own diagram elements to a diagram. This is done through the elementFactory extension point. An example usage of this is the AcmeStudio legend, which is added through this extension point. Users of this extension point must implement the AcmeStudio.ui.editors.diagram.IElementFactory interface and define the following methods:

 

/**

 * Returns the models that are extensions of this system. Elements in the

 * list should extend AcmeElement.

 * @param parent The system containing extensions

 * @return the list of models that a plugin has extended the system with

 */

public List getModels(AcmeSystem parent);

   

/**

 * Returns a new edit part associated with the object, which will be one

 * of the elements returned from getModels

 * @param child The element

 * @return A new editpart to add to the diagram

 */

public EditPart getEditPart(Object child);

   

/**

 * Gets the selection policy for the extension

 * @param target the object

 * @return The selection edit policy

 */

public SelectionEditPolicy getSelectionPolicy (Object target);

  

/**

 * Returns the command to delete the model from the diagram

 * @param model The model to delete

 * @return the command to use to delete the model

 */

public Command getDeleteCommand(Object model);

 

To use this extension point, the factory must be registered using the AcmeStudio.elementFactory extension point. For example, the factory that is used by the Legend plugin is registered as:

<extension

         point="AcmeStudio.elementFactory">

      <action

            class="AcmeDiagramLegend.LegendFactory"

            id="legend_factory">

      </action>

   </extension>

In addition, having your model implement the IDiagramModelExtension means that it will be able to participate in ordering commands (such as move back/forward) in the diagram.

In addition to the above extensions, it may be necessary to provide your own layout policy to be able to move, resize, reconnect, etc. an extension’s elements on the diagram. To do this, extensions need to provide a class that is an extension of org.eclipse.gef.policies.XYLayoutPolicy, and register this with AcmeStudio using the AcmeStudio.XYLayoutPolicy extension point. Below is the example for the annotations extensions.

<extension

         point="AcmeStudio.XYLayoutPolicy">

         <XYLayoutPolicy id="annotation_layout" class="AcmeStudioShapeExtension.policies.LayoutPolicyExtension"/>

</extension>

 

Extending the Element View

Many plugins that add architectural analyses will define their own architectural properties to use in the analysis. Usually, this is done through a family that defines types that contain specific properties. For example, the Performance Analysis Plugin defines PerformanceComponentType to contain properties such as perf-responseTime, perf-load. In such cases, plugins may want to provide their own way to display this data, in addition to restricting which properties may be changed by the user. This can be done through adding a page on the ElementView, and this is done through the elementViews extension. Such extensions must extend the abstract class AcmeStudio.ui.views.parts.ElementViewPart. In particular, the following methods must be implemented:

/**

  * Creates the control for that will be added to the element view. Users should override this element.

  * @param parent The parent composite

  * @param style The style of the widget to create

  * @param vp The ElementView that this control will be attached to

  */

 public void createControl (Composite parent, int style, IElementViewPage vp);

// The super implementation of this method should be called by the subclasses

   

/**

 * Returns the contributions of the ElementViewPart. These

 * will be added to the toolbar

 * @return the contributions

 */

public IContributionItem [] getContributions ();

              

/**

 * Returns whether this view part is valid for a particular object. This is used

 * by the element view to determine whether to display the tab when an

 * element is selected

 * @param o The object that is selected

 * @return whether the view part should be shown for this object

 */

 public boolean isValidFor (AcmeObject o);

 

/**

 *

 * @return The title to be used in the tab for this part

 */

public String getTitle();

 

To use this extension point, the view must be registered using the AcmeStudio.elementViews extension point. For example, the Error tab of the element view is added in the following way:

  <extension

         point="AcmeStudio.elementViews">

      <elementView

            name="Errors"

            class="AcmeStudio.ui.views.parts.ErrorList"

            id="AcmeStudio.ErrorList">

      </elementView>

   </extension>

Adding “Global” Families

For analysis plugins, as mentioned above, the plugin may want to provide its own set of families that can be used by AcmeStudio users. For example, the Performance Analysis plugin must be used with the PerformanceFam family. A plugin can specify a directory that contains these families through the familyDirectory extension.

Extensions must implement the AcmeStudio.core.resource.IFamilyContributor interface, and provide the following method.

/**

 * @return An array of strings containing the the full path to the directories containing Acme families

 */

public String [] getPathContributions ();

 

To use this extension point, contributor must be registered using the AcmeStudio.familyDirectory extension point. This can be done in the following way:

<extension point="AcmeStudio.familyDirectory">

  <contributor id="MyFamily" class="MyFamilyContributorClassPath"/>

</extension>

Adding Sections to the Palette

It is possible that plugins will want to extend the palette to include new tools, especially if the plugin wants to extend adding elements on the diagram. The paletteTabs extension point allows this. For each paletteTab extension, a new section is created in the palette. Extensions must implement the AcmeStudio.ui.editors.diagram.palette.extensions.IPaletteExtender interface, and provide the following methods:

/**

 * Adds the tools and templates specific to a particular extension. These tools must be added to the parentGroup

 * @param parentGroup The group to add the new palette tools to. This group is added as a section in the palette by AcmeStudio

 */

public void createPaletteChildren (PaletteGroup parentGroup);

 

/**

 * Returns true if the extension is applicable for this particular system. If true is returned, AcmeStudio

 * will call createPaletteChildren to add a new section to the palette

 * @param system The Acme system being tested as a candidate for this extension

 * @return Whether the system should ignore this extension for this system

 */

public boolean isApplicable (AcmeSystem system);

 

To use this extension point, the palette extender must be registered using the AcmeStudio.paletteTabs extension point. For example, the tab for the annotations plugin is registered in the following way:

<extension

         name="Annotations"

         point="AcmeStudio.paletteTabs">

      <tabEntry

            extenderClass="AcmeStudioShapeExtension.AnnotationPaletteExtender"

            name="Annotations"/>

   </extension>