Macneil Shonle
Ankit Shah
Version 1.1
12 March 2003
Classes CompilationEnvironment and AspectPlugin form the standard interface as used by any plugin. The design of each of these classes is described below:
Download Source Code of CompilationEnvironment Class
public class CompilationEnvironment {
private MessageLog errors = new MessageLog();
private MessageLog warnings = new MessageLog();
private AspectIDRegistry aReg = new AspectIDRegistry();
// methods that a plug-in can call:
public void reportError(String mesg, String fromAspectID, int line);
public void reportError(String mesg, String fromAspectID)
public void reportError(String mesg)
public void reportWarning(String mesg, String fromAspectID, int line);
public void reportWarning(String mesg, String fromAspectID);
public void reportWarning(String mesg);
// methods called by ajc:
public void mapAspect(String aspectID, File file, int startingLine)
public Iterator getErrors(String fromAspectID);
public Iterator getWarnings(String fromAspectID);
public Iterator getErrors()
public Iterator getWarnings()
public int getNumErrors(String fromAspectID);
public int getNumWarnings(String AspectID);
public int getNumErrors()
public int getNumWarnings()
}
The 3 data members hold the necessary information. AspectIDRegistry and MessageLog are 2 implementation classes to support the storage of aspect line and filename information and error and warning messages.
mapAspect() method must be called by ajc to register aspect information in the Environment. Failure to do so, will result in the failure of all other methods.
getNumErrors() & getNumWarnings() methods provide information about the total number of errors and warnings generated so far. If an optional aspectID is provided, then only the count of errors or warnings generated for those aspects is returned.
getErrors() & getWarnings() methods return an Iterator to iterate through all the errors or warnings. If no errors or warnings are generated, null is returned. Optional AspectID may passed to get that aspect-specific information.
class MessageLog {
private HashMap log = new HashMap();
public void addMessage(String aspectID, String msg);
public Iterator extractMessages (String aspectID);
public Iterator extractMessages ();
public int size (String fromAspectID);
public int size ();
}
MessageLog class provides a repository to store errors and warnings generated during compilation. This class is just a support class for CompilationEnvironment and is not visible outside the "xaspects" package
class AspectIDRegistry {
private HashMap registry = new HashMap();
class FileInfo {
File filename;
int startLine;
FileInfo (File filename, int startLine);
}
void register(String aspectID, File filename, int startLine);
boolean isRegistered(String aspectID);
File getFile (String aspectID);
int getStartLine (String aspectID);
Iterator allAspectIDs ();
}
AspectIDRegistry stores for an aspect, an ID, a reference to the file it is written in and the line number inside the file where it starts. To store the latter 2 pieces of information, an inner class FileInfo is used. Methods to store and retrieve data are provided.
Download Source Code of AspectPlugin Class
public abstract class AspectPlugin {
CompilationEnvironment ce;
private File workingDirectory = null;
public void init(CompilationEnvironment ce);
// These must be implemented by Concrete Classes
abstract public void receiveBody(AspectInfo aspectInfo, String aspectID, String body);
abstract public File[] generateExternalInterfaces();
abstract public File[] generateCode(File[] classFiles);
public File getWorkingDirectory ();
public void cleanup();
}
Download Source Code of AspectInfo Class
class AspectInfo {
String packageName = null;
String[] imports = null;
String[] modifiers;
String[] extendings;
String[] implementings;
String pluginName;
String aspectName;
String body;
File file;
int line;
public AspectInfo(List modifiers, List extendings, List implementings,
String pluginName, String aspectName, String body,
File file, int line);
/* Returns a String representation of the AspectInfo. */
public String toString();
/* Set import and package information */
public void setImports(List imports);
public void setPackage(String packageName);
/* "Formatted String" Methods */
public String getSourceContext();
public String getModifierString();
public String getInheritString();
/* "Direct Access" Methods */
public String getPackageName ();
public Iterator getImports();
public Iterator getModifiers();
public Iterator getExtends();
public Iterator getImplements();
public String getPluginName();
public String getAspectID();
public String getBody();
public int getStartingLine ();
public File getFile ();
}
AspectPlugin is the superclass of all plugins. Every plugin must inherit from AspectPlugin.
Every Plugin must be initialized to provide the reference to Compilation Environment object.
The 3 abstract methods must be implemented in the plugin. These are the means of communication with the main compiler.
receiveBody() method is called by the compiler to pass all the
data specific to an aspect to the plugin for accurate code generation.
While in the initial design, this was a trivial method, this one now
really does a lot more than just code transfer. We can dissect an aspect input source file as follows:
1
package edu.neu.ccs.xaspects;
2
import java.util.ArrayList;
import java.io.IOException;
3
public abstract 4 aspect (5AspectJ)6ABC7extends HashMap 8implements Iterator 9 {
... body ...
}
Now these various pieces of information are passed through the 3 parameters as follows:
Tag Is is passed thru in this example
-----------------------------------------------------------------------------------------
1 Name of Package to which AspectInfo.packageName packageName="edu.neu.ccs.xaspects"
this class belongs
2 Packages / Classes Imported AspectInfo.imports imports[0]="java.util.ArrayList"
imports[1]="java.io.IOException"
3 Modifiers - Space separated list AspectInfo.modifiers modifiers[0]="public"
of modifiers[1]="abstract"
4 Keyword "aspect". This is not passed
5 Name of Plugin should be the name of class AspectJ extends AspectPlugin
the class that extends
AspectPlugin
6 Name of the aspect aspectID aspectID="ABC"
7 The class it extends AspectInfo.extnds extnds=HashMap
8 The interfaces it implements AspectInfo.implmnts implmnts[0]="Iterator"
9 the body of the class. body. (However the body="\n\t... body...\n"
outermost pair of
{} is not included
As you can see, all information concerning the namespace and inheritance
environment of the aspect is passed using AspectInfo class. Methods of
AspectInfo class are explained below. If no information is to be passed
using AspectInfo, all fields of aspectInfo will be null!! [aka new
AspectInfo(null, null, null. null, null)]
generateExternalInterfaces() method is called by the main compiler to invoke the first pass of compilation to generate interfaces or stubs that should be available for generating reflective information. An array of File objects is returned which refers to the files generated in that pass.If due to error, no files are generated, null must be returned.
generateCode() method is called by the main compiler to invoke the second pass of compilation to generate final set of files. A list of generated class files of interfaces/stubs from the first pass is passed to these methods for taking advantage of structure information. Like the above, it should return an array of File objects or null if no files are found.
Files returned in first pass are not retained by the compiler. If they are needed for the second pass again, they SHOULD be returned again. Retaining the files between passes is the responsibility of the plugin.
getWorkingDirectory() returns a reference to a File object that refers to a temporary directory for that plugin.This directory is then the working directory for that plugin. This method will check to see if a working Directory already exists. If it does, it is returned straightaway. If it doesn't exist, one is created and returned.
This method abstracts the process of having a workingDirectory from the concrete plugins. This method also ensures that no 2 plugins get the same directory as Directories have same name as the plugin class name.
cleanup() is called at the end of compilation by the main compiler to delete all the files generated during the process and also delete the temporary directory. Plugin need not bother about retaining the files. If needed, they will be retained by the main compiler by copying it to some other directory.
Constructor
Initialize the object with most info about the aspect
Set Methods
These methods are used to set the information about package to which the current aspect belongs and the packages and / or classes imported
Formatted String Methods
These methods return the information in a formatted string that can be used directly without further processing
getSourceContext() returns string that says for the above example:
"package edu.neu.ccs.xaspects;
import java.util.ArrayList;
import java.io.IOException;"
will be returned
getModifierString() returns a String of all modifiers separated by spaces. In above example, the string returned is:
"public abstract"
getInheritString() returns string that returns a string for extends and implements clauses. For above example:
"extends HashMap implements Iterator"
will be returned
In each of the above methods, if no data exists, empty strings are returned.
Direct Access Methods
These methods return pieces of information as is. If information is
only a string, the String is returned. If it is an array of Strings, an
iterator is returned. Null if no data exists.
XAspects Project Home Page, <http://www.ccs.neu.edu/research/demeter/xaspects>.
|
Author: Ankit Shah. Copyright © 2003. All rights reserved. |