The Acme language provides a facility that allows clients to add their own external design analyses, to provide checks of the design that cannot be expressed in the current Acme Language. This document illustrates how to do this by defining a function that returns the average value in a sequence of integers.
In an Acme family, an external analysis will be defined as follows:
External analysis average (values : sequence<int>) : float = … <this will refer to the Java class implemented below>…
The function will be called average and it will be used in the following way:
Component c = {
Property values : sequence<int> = <1,1,3,2,3,4,2,1>;
Rule averageRule = invariant average (values) > 2.0;
}
To integrate this function with AcmeStudio, you must use the Eclipse Plugin development perspective to develop two AcmeStudio plugins – one that defines the function in Java, and the other that defines the function in Acme. This document proceeds with describing how to set up your Eclipse environment to be able to compile against the Acme java libraries. It then goes on to describe how to define the design analysis, and the family that defines how to use the function in Acme. Finally, it describes how to install the plugins into AcmeStudio so that they can be used in architectural descriptions.
In order for an analysis to be referenced in Acme rules, it must first be defined in an Acme family. This document will be working in the org.acmestudio.analysis.example Acme project, which later be imported into Eclipse so that the Java implementation of the analysis can be defined.
1. In AcmeStudio, create a new Acme Family, which will define the design analysis in Acme.
2. In
the Functions Tab of the AcmeStudio family editor, create a new DesignAnalysis (by
pressing the New button) with the following signature:
3. In
the next page of the wizard, enter the class that will be used to evaluate this
function:
4. Defining
the function in Acme is still not enough to finish the job. AcmeStudio reports
an error on the function because the class reference that was used is
undefined.
5. Save the family.
The next thing to do is to configure an Eclipse environment that has the Plugin Development perspective installed to define the class.
Once the definition of the family is completed in Acme, it is necessary to write the Java code to implement the design analysis. This can be done in a couple of ways. In this example, the code will be generated in the same place as the family, and then introduced into AcmeStudio as a plugin that will contribute a family. This means that the family will not be editable once the process is finished. Another possibility is to construct a different plugin to contain the code and install that in AcmeStudio.
1. Click on File>Export and select General/Archive file (or File System). Follow the wizard through to the end. The project will now be ready to pull into Eclipse.
Developing the Java implementation of a design analysis means that various AcmeStudio classes will need to be made available in the Eclipse environment. The simplest way to do this is to install AcmeStudio into an Eclipse environment that has the JDT and the Plugin Development (PDE) perspectives installed. This can be achieved by going to the AcmeStudio update site and installing the feature.
1. In an Eclipse PDE environment, go to Help>Software Updates>Find and Install…
2. Select “Search for new features to install” and then press Next>
3. Add a new remote update site, entering the update site for the version of AcmeStudio required (Update sites can be found at http://acme.able.cs.cmu.edu/acmeweb/download.php).
4. Make sure the update site is selected, and press Finish.
5. Got through the process of installing the AcmeStudio and AcmeLib features into the Eclipse environment.
The next step is to import that project that defines the family, and set up the project so that a Java class can be defined that accesses the Acme libraries.
1. Select File>Import and import the Acme project
2. Open the Plugin Development perspective in Eclipse
3. Right click on the project, and select PDE Tools>Convert projects to plugin projects
7. Right click on the project and select Configure Build Path
a. Create a new source folder for the project, called src, in the Source tab
b. In the Libraries tab, add org.acmestudio.acme…jar as an external jar. The Jar file can be found in the plugins folder of the eclipse installation
c. Select Add Library… and select the JRE system library
8. Open the META-INF/MANIFEST.MF file. Go to the dependencies tab and Add… org.acmestudio.acme as a required plugin.
9. Create a new package org.acmestudio.example.average
Design Analyses implementations in Java are represented as classes that implement the IExternalAnalysisExpressionNode interface. It is this class that is referred to in Acme when the Acme analysis is defined. The Acme runtime will call a particular method in the class, evaluate, which is the entry point for running the new analysis. As mentioned above, this document will walk through developing an analysis that expects to take a sequence of integers and will return a float that has the average value of this sequence.
In the plugin project, create a new Java class that implements org.acmestudio.acme.rule.node.IExternalAnalysisExpressionNode. Eclipse will automatically create a method that implements the one required method of this interface, evaluate:
public Object
evaluate(IAcmeType requestedType, List<Object> params,
Stack<AcmeError>
errorStack) throws AcmeExpressionEvaluationException {
// TODO
Auto-generated method stub
return null;
}
The arguments for this method are as follows (note that the arguments above have been renamed to more meaningful names):
This document will not describe the inner workings of the AcmeLib. Please refer to the JavaDocs that are available online.
Evaluation of the design analysis should follow a basic outline of: a) check that the parameters are of the expected type (instances of the right classes) and return errors if not; b) gather appropriate information to do the evaluation; c) evaluate the method; d) construct the Acme value to return.
The implementation of the method for evaluate is:
public Object
evaluate(IAcmeType requestedType, List<Object> params,
Stack<AcmeError>
errorStack) throws AcmeExpressionEvaluationException {
// a) Check that the parameters are of
the expected type
if (params == null || params.size
() != 1) {
processMessage(errorStack, "The
function average expects one argument.");
}
if
(!(params.get(0) instanceof IAcmeSequenceValue)) {
processMessage(errorStack, "The
function average expects a value of the type 'sequence<int>' to be passed
in.");
}
IAcmeSequenceValue sequence =
(IAcmeSequenceValue )params.get (0);
IAcmeSequenceType seqType =
(IAcmeSequenceType) AcmeTypeHelper.unwrapType(sequence.getType());
if
(!(seqType.getSequenceType() instanceof IAcmeIntType))
{
processMessage(errorStack, "The
function average expects a value of the type 'sequence<int>' to be passed
in.");
}
// b) Gather information required --
in this case, we just need the sequence which we got above.
// c) Evaluate the function
int sum = 0;
for
(IAcmePropertyValue value : sequence.getValues()) {
if (!(value instanceof IAcmeIntValue))
{
processMessage
(errorStack, "The function average expects a value of the type
'sequence<int>' to be passed in.");
}
IAcmeIntValue i =
(IAcmeIntValue )value;
sum += i.getValue();
}
float average = (float )sum / sequence.getValues().size();
// d) Construct the Acme value to
return (not UM*Value objects allow you to construct I*Value objects to be
returned)
UMFloatValue returnValue = new UMFloatValue
(average);
return returnValue;
}
private void processMessage(Stack<AcmeError>
errorStack, String message)
throws
AcmeExpressionEvaluationException {
AcmeError error = new AcmeError ();
error.setMessageText(message);
errorStack.push (error);
throw new
AcmeExpressionEvaluationException (error);
}
Select .acmeproject, .project, META-INF, bin, families, and plugin.xml to be included in the binary build.
To make this new analysis and family available in an installation of AcmeStudio, the plugin must first be exported. To do this, open the File>Export… wizard and follow these steps:
1. Select Plug-in Development/Deployable plug-ins and fragments; select Next >
2. Select the plugin (org.acmestudio.example.analysis). Enter the directory into which to generate the plugin (for now, use a temporary place).
3. Select Finish
This creates a JAR file (org.acmestudio.example.analysis_1.0.0.jar) in the plugins directory of the temporary storage place indicated in step 2. To make this plugin available in AcmeStudio:
1. Quite AcmeStudio.
2. Copy the JAR file into the plugins directory of the AcmeStudio installation site.
3.