String qualifiedName = getQualifiedName(className);
String aspectName = nameForCombining + "_instrument";
File aspectFile = new File(directoryPath, aspectName + ".aj");
if (aspectFile.exists()) aspectFile.delete();
if (!aspectFile.createNewFile())
throw new AnalysisException("aspect file " + aspectFile
+ " already exists");
ps = new PrintStream(new FileOutputStream(aspectFile));
ps.println("package " + aspectPathInfo.getPackageName() + ";");
ps.println("import java.util.List;");
ps.println("import java.util.HashSet;");
ps.println("import java.util.ArrayList;");
ps.println("import java.lang.reflect.Field;");
ps.println("import java.lang.reflect.Method;");
ps.println("import org.mitre.sim.analysis.instrument.InstrumentedTrigger;");
//aspect is privileged to allow it access to Triggers' private fields
ps.println("\nprivileged aspect " + aspectName + " {");
ps.println("\n declare parents : " + unqualifiedName
+ " implements InstrumentedTrigger;");
ps.println(" private ArrayList " + unqualifiedName + ".earlyBoundNotifiers"
+ " = new ArrayList();");
AspectData.TriggerRecord tr = (AspectData.TriggerRecord)aspectData
.getTriggerRecord(className);
String enclosingClassName = null, unqualifiedEnclosingClassName = null;
String enclosingNameForCombining = null;
if (tr.enclosingClassName != null) {
enclosingClassName = getQualifiedName(tr.enclosingClassName);
unqualifiedEnclosingClassName = getUnqualifiedName(tr.enclosingClassName);
enclosingNameForCombining = unqualifiedEnclosingClassName.replace('.', '_');
}
if (tr.enclosingClassName != null && tr.enclosingCollections.size() > 0)
addTheAddNotifierMethod(ps, unqualifiedName);
ps.println("\n public List " + unqualifiedName
+ ".getNotifiers(InstrumentedTrigger it) {");
ps.println(" ArrayList allNotifiers = new ArrayList();");
//for each Collection class field in Trigger
for (Iterator cc = tr.collectionFields.keySet().iterator(); cc.hasNext(); ) {
String fieldName = (String)cc.next();
ps.println(" allNotifiers.add(((" + unqualifiedName + ")it)."
+ fieldName + ");" );
}
//for each Collection class field in enclosing class
if (enclosingClassName != null) {
for (Iterator ecc = tr.enclosingCollections.keySet().iterator();
ecc.hasNext(); ) {
String fieldName = (String)ecc.next();
AspectData.EnclosingClassCollectionRecord eccr = (AspectData.EnclosingClassCollectionRecord)
tr.enclosingCollections.get(fieldName);
ps.println(" addTortugaNotifier(it,");
ps.println(" allNotifiers,");
ps.println(" " + unqualifiedName + ".class,");
ps.println(" " + unqualifiedEnclosingClassName + ".class,");
ps.println(" \"" + eccr.accessMethodName + "\",");
ps.println(" \"" + tr.referenceToEnclosingName + "\");");
}
}
ps.println(" allNotifiers.addAll(earlyBoundNotifiers);" );
ps.println(" return allNotifiers;" );
ps.println(" } //getNotifiers");
ps.println("\n public void " + unqualifiedName + ".addNotifier(Object n)" );
ps.println(" { earlyBoundNotifiers.add(n); }" );
//add enclosing class as notifier, if it has primitive fields
if (enclosingClassName != null && !tr.enclosingPrimitives.isEmpty()) {
String pointcutName = nameForCombining + "_add_" + enclosingNameForCombining;
ps.println("\n pointcut " + pointcutName + "(InstrumentedTrigger trigger)");
ps.println(" : initialization(public " + unqualifiedName
+ ".new(..)) && target(trigger);" );
ps.println("\n after (InstrumentedTrigger trigger) : "
+ pointcutName + "(trigger) {");
ps.println(" try {");
ps.println(" Field enclosingThisField = trigger.getClass().getDeclaredField(\""
+ tr.referenceToEnclosingName + "\");");
ps.println(" enclosingThisField.setAccessible(true);");
ps.println(" trigger.addNotifier(enclosingThisField.get(trigger));");
ps.println(" }");
ps.println(" catch (Exception e) {");
ps.println(" throw new IllegalStateException(\"See Tortuga Support. "
+ "(\" + e + \" in trigger instrument aspect for field "
+ tr.referenceToEnclosingName + " trigger " + qualifiedName
+ ")\");");
ps.println(" } //catch");
ps.println(" } //after" );
}
//add trigger class itself as notifier, if it has primitive fields
if (!tr.primitiveFields.isEmpty()) {
String pointcutName = nameForCombining + "_add_" + nameForCombining;
ps.println("\n pointcut " + pointcutName + "(InstrumentedTrigger trigger)");
ps.println(" : initialization(public " + unqualifiedName
+ ".new(..)) && target(trigger);" );
ps.println("\n after (InstrumentedTrigger trigger) : "
+ pointcutName + "(trigger) {");
ps.println(" trigger.addNotifier(trigger);" );
ps.println(" } //after" );
}
ps.println("} //aspect");
}
catch (IOException ex) {
throw new AnalysisException(ex);
}
finally {
if (ps != null) ps.close();
}
}