Java tutorial
/******************************************************************************* * Copyright (c) 2009 Jeffrey Koch. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Jeffrey Koch - initial API and implementation. I Am Not A Lawyer, but if I read * http://www.eclipse.org/legal/legalfaq.php, http://www.eclipse.org/legal/eplfaq.php, * and the EPL correctly, I think I have the copyright for this code since I'm * initial implementer of this module even though it extends Java2UMLConverter which * was copyrighted by its initial implementer (David Sciamma). *******************************************************************************/ package edu.utdallas.fdaf.aspectj.reverse; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.aspectj.asm.IProgramElement; import org.aspectj.asm.IRelationship; import org.eclipse.ajdt.core.model.AJProjectModelFacade; import org.eclipse.ajdt.core.model.AJProjectModelFactory; import org.eclipse.ajdt.core.model.AJRelationshipManager; import org.eclipse.ajdt.core.model.AJRelationshipType; import org.eclipse.core.runtime.CoreException; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.jdt.core.Flags; import org.eclipse.jdt.core.ICompilationUnit; import org.eclipse.jdt.core.IField; import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.IMember; import org.eclipse.jdt.core.IMethod; import org.eclipse.jdt.core.IPackageFragment; import org.eclipse.jdt.core.IType; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.uml2.uml.Class; import org.eclipse.uml2.uml.Classifier; import org.eclipse.uml2.uml.Element; import org.eclipse.uml2.uml.Enumeration; import org.eclipse.uml2.uml.EnumerationLiteral; import org.eclipse.uml2.uml.Interface; import org.eclipse.uml2.uml.NamedElement; import org.eclipse.uml2.uml.Namespace; import org.eclipse.uml2.uml.Operation; import org.eclipse.uml2.uml.Package; import org.eclipse.uml2.uml.Parameter; import org.eclipse.uml2.uml.Property; import org.eclipse.uml2.uml.Stereotype; import org.eclipse.uml2.uml.StructuredClassifier; import org.eclipse.uml2.uml.Type; import org.eclipse.uml2.uml.UMLFactory; import org.topcased.java.reverse.Java2UMLConverter; /** * Extends Topcased's Java2UMLConverter to convert AspectJ and Java to UML. * * @author Jeff Koch * */ public class AspectJ2UMLConverter extends Java2UMLConverter { AspectJUmlProfile profile; AJProjectModelFacade ajModel; /** * This contains the map between IJavaElements and UML elements. * I wrapped the map inside this (and intentionally called it "Info" * instead of "Map") so I could override the normal Map behavior of * allowing the Value for a Key to be changed. (That's also why * I called the method addNodeToInfo instead of the normal Map-like * name of "add()".) * * @author Jeff Koch * */ private class Aj2UmlInfo { Map<String, NamedElement> modelMap; /** * */ protected Aj2UmlInfo() { modelMap = new HashMap<String, NamedElement>(); } /** * If no UML node has been associated with the IJavaElement, associates this NamedElement * with the IJavaElement. * @param jElement element from the AspectJ/Java Model * @param umlType element from the UML Model */ void addNodeToInfo(IJavaElement jElement, NamedElement umlNode) { String typeHandle = jElement.getHandleIdentifier(); if (!modelMap.containsKey(typeHandle)) { modelMap.put(typeHandle, umlNode); // System.err.println("Map update: " + typeHandle + " to " + umlNode.getName()); } } NamedElement get(String key) { // return modelMap.get(key); //Stop when we find a match, or when we run out of string. NamedElement umlElement = null; // StringBuilder curKey = new StringBuilder(key); // while ((umlElement == null) && (curKey.length() > 0)) { // umlElement = modelMap.get(curKey.toString()); // if (umlElement == null) { // curKey.deleteCharAt(curKey.length()-1); // } // } for (StringBuilder curKey = new StringBuilder(key); (umlElement == null) && (curKey.length() > 0); curKey.deleteCharAt(curKey.length() - 1)) { umlElement = modelMap.get(curKey.toString()); } return umlElement; } } private Aj2UmlInfo a2uInfo; /** * @see edu.utdallas.fdaf.org.topcased.java.reverse.AbstractJava2UMLConverter#convert(org.eclipse.jdt.core.IJavaElement, org.eclipse.emf.ecore.resource.Resource) * @param javaElement * @param pEmfResource * @return * @throws CoreException */ @Override public Package convert(IJavaElement javaElement, Resource pEmfResource) throws CoreException { // TODO Auto-generated method stub return super.convert(javaElement, pEmfResource); } /** * Initialise the created types and populated them with operation properties and inner types. * * This code modifies Java2UMLConverter.initializeTypes() to handle AspectJ elements. */ @Override protected void initializeTypes(Package packageObject, IPackageFragment fragment) throws JavaModelException { ajModel = AJProjectModelFactory.getInstance().getModelForJavaElement(fragment); for (IJavaElement javaElement : fragment.getChildren()) { if (javaElement instanceof ICompilationUnit) { ICompilationUnit unit = (ICompilationUnit) javaElement; // AJParseTree tree = new AJParseTree(unit); for (IType type : unit.getAllTypes()) { String typeName = type.getElementName(); NamedElement element = packageObject.getOwnedMember(typeName); if (element == null && type.getParent() != null) { element = findInnerType(packageObject, type, typeName); } if (element instanceof Interface) { Interface interfaceObject = (Interface) element; // Super interfaces for (String interfaceName : type.getSuperInterfaceNames()) { Type interfaceType = findType(packageObject, interfaceName); if (interfaceType == null && type.getParent() != null) { interfaceType = findInnerType(packageObject, type, typeName); } if (interfaceType != null && interfaceType instanceof Classifier) { interfaceObject.createGeneralization((Classifier) interfaceType); } } // Inner objects createProperties(type, interfaceObject); createOperations(type, interfaceObject); } else if (element instanceof Enumeration) { Enumeration enumeration = (Enumeration) element; for (String interfaceName : type.getSuperInterfaceNames()) { Type interfaceType = findType(packageObject, interfaceName); if (interfaceType == null) { interfaceType = findGenericType(packageObject, interfaceName); } if (interfaceType == null && type.getParent() != null) { interfaceType = findInnerType(packageObject, type, typeName); } if (interfaceType != null && interfaceType instanceof Interface) { Classifier classifier = (Classifier) interfaceType; if (enumeration.getGeneralization(classifier) == null) { enumeration.createGeneralization(classifier); } } } // Inner objects createProperties(type, enumeration); createOperations(type, enumeration); } else if (element instanceof Class) { Class classObject = (Class) element; // Super Interfaces for (String interfaceName : type.getSuperInterfaceNames()) { Type interfaceType = findType(packageObject, interfaceName); if (interfaceType == null) { interfaceType = findGenericType(packageObject, interfaceName); } if (interfaceType == null && type.getParent() != null) { interfaceType = findInnerType(packageObject, type, typeName); } if (interfaceType != null && interfaceType instanceof Interface) { Interface interf = (Interface) interfaceType; if (classObject.getInterfaceRealization(interfaceName, interf) == null) { classObject.createInterfaceRealization(interfaceName, interf); } } } // Generalization String superClassName = type.getSuperclassName(); Type classType = findType(packageObject, superClassName); if (classType == null && type.getParent() != null) { classType = findInnerType(packageObject, type, typeName); } if (classType == null) { classType = findOrCreateType(packageObject, superClassName); } if (classType != null && classType instanceof Classifier) { Classifier classifier = (Classifier) classType; // Create generalization only if it is needed if (classObject.getGeneralization(classifier) == null) { classObject.createGeneralization(classifier); } } /* * Eventually, here's what I need to do. I need to find the * ProgramElement that corresponds to the class; if it's an * Aspect, then plug in the Aspect stereotype. (For now, I'll * hand-wave it by sticking in a comment to syserr.) * * Don't know if I'll try to handle the intertype stuff here, * or if I'll push that down into createProperties/createOperations. * Probably the former, which means I wouldn't call createProperties * or createOperations at all for Aspects. */ IProgramElement ajElement = javaElementToProgramElement(type); if (ajElement.getKind().toString().equals("aspect")) { System.err.println("aspect found: javaElement " + typeName + " (handle " + type.getHandleIdentifier() + "), programElement " + ajElement.getName() + ", UML object = " + classObject.getQualifiedName()); Stereotype aspectST = profile.getStereotype("Aspect"); try { classObject.applyStereotype(aspectST); } catch (Exception e) { System.err.println( "Exception attempting to apply Aspect stereotype to " + typeName + ":"); e.printStackTrace(); } //Extract elements from the Program Element createAjFeatures(type, ajElement, classObject); } else { // Inner objects createProperties(type, classObject); createOperations(type, classObject); } } } } } addAspectRelationships(ajModel, packageObject, fragment); } private IProgramElement javaElementToProgramElement(IType type) { return ajModel.javaElementToProgramElement(type); } private IJavaElement programElementToJavaElement(IProgramElement element) { return ajModel.programElementToJavaElement(element); } /** * Converts an AspectJ (IProgramElement) handle to its Java (IJavaElement) * counterpart. * @param ajHandle AspectJ Model (IProgramElement) handle * @return the Java Model (IJavaElement) counterpart to ajHandle */ private String ajHandleToJavaHandle(String ajHandle) { IJavaElement jElement = ajModel.programElementToJavaElement(ajHandle); return jElement.getHandleIdentifier(); } /** * Creates the features (StaticCrossCuttingFeatures, Advices, and PointCuts) for * the aspect. * @param jType Java Model node for the aspect. * @param ajElement ProgramElement for the aspect. * @param classifier UML node for the aspect * @throws JavaModelException */ private void createAjFeatures(IType jType, IProgramElement ajElement, Class classifier) throws JavaModelException { List children = ajElement.getChildren(); for (Object object : children) { if (object instanceof IProgramElement) { IProgramElement child = (IProgramElement) object; printChildInfo(ajElement, child); String childType = child.getKind().toString(); if ((childType.equals("inter-type field")) || (childType.equals("inter-type constructor"))) { Property intertypeField = addAspectProperty(classifier, child); applyStereotype(intertypeField, "StaticCrossCuttingFeature"); } else if (childType.equals("inter-type method")) { Operation intertypeMethod = addAspectOperation(classifier, child); applyStereotype(intertypeMethod, "StaticCrossCuttingFeature"); } else if (childType.equals("inter-type parent")) { //TODO handle inter-type parent } else if (childType.equals("pointcut")) { /* * Evermann defines Pointcut as an abstract stereotype * that's extended by specific pointcut types * (AdviceExecutionPointCut, OperationPointCut, * PointCutPointCut, etc). IProgramElement doesn't * specific pointcut types, so for now I'm making Pointcut * non-abstract and lumping all pointcuts under that * stereotype. */ Property pointcutProperty = addAspectProperty(classifier, child); applyStereotype(pointcutProperty, "PointCut"); } else if (childType.equals("advice")) { /* * Advice is a behavioral feature (Operation in our case). */ Operation adviceOp = addAspectOperation(classifier, child); applyStereotype(adviceOp, "Advice"); //Now set adviceExecution: before/after/around setAdviceExecution(child, adviceOp); } } } } /** * Sets the adviceExecution (before, after, around) for a newly created advice * @param modelAdvice the advice as it appears in the AspectJ/Java Model * @param umlAdvice the advice as it appears in the UML model */ private void setAdviceExecution(IProgramElement modelAdvice, Operation umlAdvice) { Stereotype stereotype = profile.getStereotype("Advice"); String literalName; String adviceType = modelAdvice.getName(); if (adviceType.contains("before")) { literalName = "BeforeAdvice"; } else if (adviceType.contains("after")) { literalName = "AfterAdvice"; } else { literalName = "AroundAdvice"; } EnumerationLiteral literal = profile.getEnumLiteral("AdviceExecutionType", literalName); umlAdvice.setValue(stereotype, "adviceExecution", literal); } /** * Applies a {@link Stereotype} to an {@link Element}. * @param elementObject UML Element that needs the Stereotype * @param stereotypeName Name of the Stereotype to be applied. */ private void applyStereotype(Element elementObject, String stereotypeName) { Stereotype st = profile.getStereotype(stereotypeName); /* * OK, so I'm being lazy by printing to syserr instead of throwing * a proper exception myself. OTOH, this should (in theory) only * happen in development, so this is a heads-up that I typo'd the * stereotype name, and it'll show up right before elementObject.applyStereotype * triggers the exception because st is null. */ if (st == null) { System.err.println("Couldn't find stereotype for " + stereotypeName); } try { elementObject.applyStereotype(st); } catch (Exception e) { System.err.println("Exception thrown while attempting to apply stereotype " + stereotypeName + " to Element " + elementObject.toString()); e.printStackTrace(); } } /** * Creates a UML Property for the IProgramElement and adds it to the UML aspect. * * The Property could be any aspect-related "property"--intertype fields, * pointcuts, or the like. The caller is responsible for adding the * appropriate stereotype to the Property. * * @param classifier UML Class representing an aspect * @param child IProgramElement representing the property * @return UML Property representing the property * @throws JavaModelException */ private Property addAspectProperty(Class classifier, IProgramElement child) throws JavaModelException { //JWK: Don't look for an existing aspect property // Property propertyObject = findProperty(classifier, child.getName()); // if (propertyObject != null) // { // // Just update // attachJavadoc(propertyObject, child); // } // else // { // // Creates a new one // propertyObject = createProperty(classifier, child); // classifier.getOwnedAttributes().add(propertyObject); // // //processAnnotations(classifier.getNamespace(), type, propertyObject); // } // Creates a new one Property propertyObject = createProperty(classifier, child); classifier.getOwnedAttributes().add(propertyObject); a2uInfo.addNodeToInfo(ajModel.programElementToJavaElement(child), propertyObject); return propertyObject; } // // future aspect-related stuff: // public static final Kind DECLARE_PARENTS = new Kind("declare parents"); // public static final Kind DECLARE_WARNING = new Kind("declare warning"); // public static final Kind DECLARE_ERROR = new Kind("declare error"); // public static final Kind DECLARE_SOFT = new Kind("declare soft"); // public static final Kind DECLARE_PRECEDENCE = new Kind("declare precedence"); // * // * // * "Inside types" and other stuff I might implment later: // public static final Kind CLASS = new Kind("class"); // public static final Kind INTERFACE = new Kind("interface"); // public static final Kind ASPECT = new Kind("aspect"); // // TBD: // public static final Kind ENUM = new Kind("enum"); // public static final Kind ENUM_VALUE = new Kind("enumvalue"); // public static final Kind ANNOTATION = new Kind("annotation"); // public static final Kind INITIALIZER = new Kind("initializer"); // public static final Kind CONSTRUCTOR = new Kind("constructor"); // public static final Kind METHOD = new Kind("method"); // public static final Kind FIELD = new Kind("field"); // public static final Kind CODE = new Kind("code"); // public static final Kind ERROR = new Kind("error"); // public static final Kind DECLARE_ANNOTATION_AT_CONSTRUCTOR = new Kind("declare @constructor"); // public static final Kind DECLARE_ANNOTATION_AT_FIELD = new Kind("declare @field"); // public static final Kind DECLARE_ANNOTATION_AT_METHOD = new Kind("declare @method"); // public static final Kind DECLARE_ANNOTATION_AT_TYPE = new Kind("declare @type"); // public static final Kind SOURCE_FOLDER = new Kind("source folder"); // public static final Kind PACKAGE_DECLARATION = new Kind("package declaration"); // */ // /** * Creates a UML Operation based on an IProgramElement, and * adds it to the aspect Class. This "operation" could be an intertype * method, advice, or the like; it's up to the calling module to add the * appropriate stereotype to the Operation. * * @param classifier UML Class representing an aspect. * @param child IProgramElement representing some operation. This "operation" * could be an intertype method, advice, or the like. * @return the UML Operation created * @throws JavaModelException */ private Operation addAspectOperation(Class classifier, IProgramElement child) throws JavaModelException { /* * JWK: I was looking for an existing (UML) operation that * matched the IProgramElement, but that messes up when I have * identical aspect operations; for instance, one of our test systems * have two identical advices in a row. I'll see what happens * if I disable that check. */ // Operation operationObject = findOperation(classifier, child); // if (operationObject != null) // { // // Just update the javadoc // attachJavadoc(operationObject, child); // } // else // { // // Creates a new one // operationObject = createOperation(classifier, child); // classifier.getOwnedOperations().add(operationObject); // // } Operation operationObject = createOperation(classifier, child); classifier.getOwnedOperations().add(operationObject); // processAnnotations(classifier.getNamespace(), child, operationObject); a2uInfo.addNodeToInfo(ajModel.programElementToJavaElement(child), operationObject); return operationObject; } private Operation createOperation(Class classifier, IProgramElement child) throws JavaModelException { // protected Operation createOperation(Element element, IMethod method) throws JavaModelException // { String methodName = child.getName(); Operation operationObject = UMLFactory.eINSTANCE.createOperation(); operationObject.setName(methodName); update(operationObject, child.getRawModifiers()); int flags = child.getRawModifiers(); operationObject.setIsAbstract(Flags.isAbstract(flags)); operationObject.setIsStatic(Flags.isStatic(flags)); attachJavadoc(operationObject, child); createParameters(classifier, operationObject, child); //JWK: For now, I'm assuming that the child will exist and won't be a Constructor of some sort. // if (child.exists() && !child.isConstructor()) // { // TEMP createTemplateParameters(child, operationObject); // String returnTypeSig = child.getReturnType(); // // String returnTypeWithoutArray = Signature.getElementType(returnTypeSig); // String returnTypeName = Signature.toString(Signature.getTypeErasure(returnTypeWithoutArray)); String returnTypeName = child.getCorrespondingType(true); Type returnType = findTemplateParameter(classifier, returnTypeName); if (returnType == null) { returnType = findTemplateParameter(operationObject, returnTypeName); } if (returnType == null) { returnType = findOrCreateType(classifier.getNearestPackage(), returnTypeName); } // Type returnType = findOrCreateType(element.getNearestPackage(), // returnTypeName); if (returnType != null) { operationObject.createReturnResult("return", returnType); } // } return operationObject; } // private void createTemplateParameters(IProgramElement child, // Operation operationObject) { //// private void createTemplateParameters(IMethod method, Operation operationObject) throws JavaModelException //// { // ITypeParameter[] typeParameters = child.getTypeParameters(); // for (ITypeParameter typeParameter : typeParameters) // { // TemplateSignature templateSignature = operationObject.getOwnedTemplateSignature(); // // FIXME See how to update the template signature // if (templateSignature == null) // { // templateSignature = operationObject.createOwnedTemplateSignature(); // ClassifierTemplateParameter classifierTemplateParameter = UMLFactory.eINSTANCE.createClassifierTemplateParameter(); // templateSignature.getOwnedParameters().add(classifierTemplateParameter); // ParameterableElement parameteredElement = classifierTemplateParameter.createOwnedParameteredElement(UMLPackage.Literals.CLASS); // if (parameteredElement instanceof Class) // { // Class clazz = (Class) parameteredElement; // clazz.setName(typeParameter.getElementName()); // }// end of if (parameteredElement instanceof Class) // } // } // } private void createParameters(Class classifier, Operation operationObject, IProgramElement child) { // protected void createParameters(Element element, Operation operation, IMethod method) throws JavaModelException // { List<?> paramNameList = child.getParameterNames(); //If there weren't any parm names, don't create any parms if (paramNameList == null) { return; } Object[] paramNames = paramNameList.toArray(); Object[] paramTypeSigs = child.getParameterTypes().toArray(); /* * child.getParameterNames is List<String>, but child.getParameterNames is * actually List<char[]> or something equally bizarre. Which is why the * typeSigObj-to-typeSig conversion is so weird. */ for (int i = 0; i < paramNames.length; i++) { Object nameObj = paramNames[i]; Object typeSigObj = paramTypeSigs[i]; if (nameObj instanceof String) { String name = (String) nameObj; char[] typeSigArr = (char[]) typeSigObj; String typeName = String.valueOf(typeSigArr); // String typeSig = String.valueOf(typeSigArr); // Parameter parameter = UMLFactory.eINSTANCE.createParameter(); parameter.setName(name); // // String typeWithoutArray = Signature.getElementType(typeSig); // String typeName = Signature.toString(Signature.getTypeErasure(typeWithoutArray)); Type paramType = findTemplateParameter(classifier, typeName); if (paramType == null) { paramType = findOrCreateType(classifier.getNearestPackage(), typeName); } if (paramType != null) { parameter.setType(paramType); } operationObject.getOwnedParameters().add(parameter); } // processAnnotations(classifier.getNearestPackage(), child, parameter); } } private Operation findOperation(StructuredClassifier classifier, IProgramElement child) { // protected Operation findOperation(Classifier classifier, IMethod method) // { for (Operation op : classifier.getOperations()) { if (op.getOwner().equals(classifier) && op.getName().equals(child.getName())) { // try // { List lParamNames = child.getParameterNames(); // if ((lParamNames == null) || (lParamNames.size() == 1)) // { // if (op.getOwnedParameters().size() == 1) // { // return op; // } // } if (lParamNames == null) { if (op.getOwnedParameters().size() == 0) { return op; } } else if (lParamNames.size() == 1) { if (op.getOwnedParameters().size() == 1) { return op; } } else { Object[] aParamNames = lParamNames.toArray(); int i = 0; int paramCount = 0; for (Parameter param : op.getOwnedParameters()) { if (!param.getName().equals("return")) { if (i < aParamNames.length && param.getName().equals(aParamNames[i].toString())) { paramCount++; } i++; } } if (paramCount == aParamNames.length) { return op; } } // } // catch (JavaModelException e) // { // e.printStackTrace(); // } } } return null; } /** * @param propertyObject * @param child * @throws JavaModelException */ private void attachJavadoc(Element elementObject, IProgramElement child) throws JavaModelException { IJavaElement javaChild = programElementToJavaElement(child); if (javaChild instanceof IMember) { attachJavadoc(elementObject, (IMember) javaChild); } } private Property createProperty(Element element, IProgramElement field) throws JavaModelException { String fieldName = field.getName(); // String fieldTypeSig = field.getCorrespondingType(); // // String fieldTypeWithoutArray = Signature.getElementType(fieldTypeSig); // String fieldTypeName = Signature.toString(Signature.getTypeErasure(fieldTypeWithoutArray)); String fieldTypeName = field.getCorrespondingType(true); Type fieldType = findTemplateParameter(element, fieldTypeName); if (fieldType == null) { fieldType = findOrCreateType(element.getNearestPackage(), fieldTypeName); } Property propertyObject = UMLFactory.eINSTANCE.createProperty(); // if (isGenericType(fieldType)) // { // // TODO : find the explicit type and define a template parameter // // extractGenericTypesFromCurrentSignature(fieldTypeSig); // } propertyObject.setName(fieldName); if (fieldType != null) { propertyObject.setType(fieldType); } attachJavadoc(propertyObject, field); //BOOKMARK //JWK: I'm hoping that getRawModifiers() = getFlags for IField. update(propertyObject, field.getRawModifiers()); // // No need to check the null (done with instanceof which returns always false) // if (field.getConstant() instanceof String) // { // LiteralString defaultValue = (LiteralString) propertyObject.createDefaultValue("", propertyObject.getType(), UMLFactory.eINSTANCE.createLiteralString().eClass()); // defaultValue.setValue((String) field.getConstant()); // } // else if (field.getConstant() instanceof Integer) // { // LiteralInteger defaultValue = (LiteralInteger) propertyObject.createDefaultValue("", propertyObject.getType(), UMLFactory.eINSTANCE.createLiteralInteger().eClass()); // defaultValue.setValue((Integer) field.getConstant()); // } // else if (field.getConstant() instanceof Boolean) // { // LiteralBoolean defaultValue = (LiteralBoolean) propertyObject.createDefaultValue("", propertyObject.getType(), UMLFactory.eINSTANCE.createLiteralBoolean().eClass()); // defaultValue.setValue((Boolean) field.getConstant()); // } return propertyObject; } /** * @param ajElement * @param child */ private void printChildInfo(IProgramElement ajElement, IProgramElement child) { String childType = child.getKind().toString(); String childHandle = child.getHandleIdentifier(); IJavaElement jChild = programElementToJavaElement(child); String jChildHandle = jChild.getHandleIdentifier(); //BEGIN TEMPORARY STUFF System.err.println(ajElement.getName() + " " + childType + " " + child.getName()); // System.out.println(" bytecode name:" + child.getBytecodeName()); // System.out.println(" bytecode sig:" + child.getBytecodeSignature()); // System.out.println(" corresponding type:" + child.getCorrespondingType(false)); // System.out.println(" fully qual'd corresponding type:" + child.getCorrespondingType(true)); // System.out.println(" declaring type:" + child.getDeclaringType()); // System.out.println(" details:" + child.getDetails()); // System.out.println(" formal comment:" + child.getFormalComment()); System.err.println(" Program Element handle:" + childHandle); System.err.println(" Java Element handle:" + jChildHandle); // System.out.println(" package name:" + child.getPackageName()); // System.out.println(" raw modifiers:" + child.getRawModifiers()); // System.out.println(" source signature:" + child.getSourceSignature()); // printList(child.getParameterNames(), "parm names"); // printList(child.getParameterSignatures(), "parm sigs"); // printList(child.getParameterSignaturesSourceRefs(), "parm sig source refs"); // printList(child.getParameterTypes(), "parm types"); // printList(child.getChildren(), "children"); //END TEMPORARY STUFF } /** * @param theList * @param header */ private void printList(List theList, String header) { if (theList == null) { System.err.println(" " + header + ": NULL"); } else { System.err.println(" " + header + ":"); if (theList.size() == 0) { System.err.println(" Empty set"); } else { for (Object object2 : theList) { if (object2 instanceof String) { System.err.println(" " + (String) object2); } else { System.err.println(" " + object2.toString()); } } } } } /** * @see org.topcased.java.reverse.Java2UMLConverter#initializeModel(org.eclipse.uml2.uml.Package) * @param model * @throws CoreException */ @Override protected void initializeModel(Package model) throws CoreException { profile = new AspectJUmlProfile(); model.applyProfile(profile.getAspectJProfile()); a2uInfo = new Aj2UmlInfo(); } /** * @see org.topcased.java.reverse.Java2UMLConverter#createTypeInPackage(org.eclipse.uml2.uml.Namespace, org.eclipse.jdt.core.IType) * @param packageObject * @param type * @return * @throws JavaModelException */ @Override protected Classifier createTypeInPackage(Namespace packageObject, IType type) throws JavaModelException { Classifier umlType = super.createTypeInPackage(packageObject, type); a2uInfo.addNodeToInfo(type, umlType); return umlType; } /** * @see org.topcased.java.reverse.AbstractJava2UMLConverter#createOperation(org.eclipse.uml2.uml.Element, org.eclipse.jdt.core.IMethod) * @param element * @param method * @return * @throws JavaModelException */ @Override protected Operation createOperation(Element element, IMethod method) throws JavaModelException { Operation umlOp = super.createOperation(element, method); a2uInfo.addNodeToInfo(method, umlOp); return umlOp; } /** * @see org.topcased.java.reverse.AbstractJava2UMLConverter#createProperty(org.eclipse.uml2.uml.Element, org.eclipse.jdt.core.IField) * @param element * @param field * @return * @throws JavaModelException */ @Override protected Property createProperty(Element element, IField field) throws JavaModelException { Property umlProp = super.createProperty(element, field); a2uInfo.addNodeToInfo(field, umlProp); return umlProp; } /** * @see org.topcased.java.reverse.AbstractJava2UMLConverter#findOrCreatePackage(org.eclipse.uml2.uml.Package, org.eclipse.jdt.core.IPackageFragment) * @param model * @param fragment * @return */ @Override protected Package findOrCreatePackage(Package model, IPackageFragment fragment) { Package umlPackage = super.findOrCreatePackage(model, fragment); a2uInfo.addNodeToInfo(fragment, umlPackage); return umlPackage; } /** * Adds the model's aspect-related relationships to the Package. * * @param model the AJ Model facade * @param packageObject the UML Package * @param fragment the AspectJ/Java model package associated with packageObject */ void addAspectRelationships(AJProjectModelFacade model, Package packageObject, IPackageFragment fragment) { // You can narrow this to include on certain kinds of relationships AJRelationshipType[] relsTypes = AJRelationshipManager.getAllRelationshipTypes(); // check first to see if there is a model // will return false if there has not yet been a successful build of this project if (model.hasModel()) { // all relationships for project // can also query for relationships on individual elements or compilation units List<IRelationship> rels = model.getRelationshipsForProject(relsTypes); for (IRelationship rel : rels) { // Source is an IProgramElement handle, which refers to a piece of the program in AspectJ's World String sourceJHandle = ajHandleToJavaHandle(rel.getSourceHandle()); NamedElement sourceElement = a2uInfo.get(sourceJHandle); for (String targetHandle : rel.getTargets()) { String targetJHandle = ajHandleToJavaHandle(targetHandle); NamedElement targetElement = a2uInfo.get(targetJHandle); try { System.err.println("Calling addAspectRelationship - rel = " + rel.getName()); System.err.println("==>Source: jHandle=" + sourceJHandle + ", sourceElement=" + sourceElement.getQualifiedName() + " (class " + sourceElement.getClass().getName() + ")"); System.err.println("==>Target: jHandle=" + targetJHandle + ", targetElement=" + targetElement.getQualifiedName() + " (class " + targetElement.getClass().getName() + ")"); addAspectRelationship(rel, sourceElement, targetElement); } catch (Exception e) { // TODO Auto-generated catch block System.err.println("Exception thrown by addAspectRelationship"); System.err.println("***rel = " + rel.getName()); System.err.println("***Source: jHandle=" + sourceJHandle + ", sourceElement=" + sourceElement.getQualifiedName()); System.err.println("***Target: jHandle=" + targetJHandle + ", targetElement=" + targetElement.getQualifiedName()); e.printStackTrace(); } } } } } /** * Adds an aspect-related relationship from the sourceElement to the targetElement. * The relationship is modeled as a attribute to the sourceElement's stereotype, * using the targetElement as the attribute's value. * * @param rel the aspect-related relationship from the AspectJ/Java Model * @param sourceElement UML Element containing the stereotype w/ the relationship * @param targetElement UML Element to be used as the relationship's value */ private void addAspectRelationship(IRelationship rel, NamedElement sourceElement, NamedElement targetElement) { /* * * If rel.getName() is "advises" * then make sure sourceElement is Advice, and set up sourceElement.advisedElement * else if rel.getName() is "declared on" * then make sure sourceElement is StaticCrossCuttingFeature, and set up sourceElement.onType * */ /* * I suspect the "add" property would do something like this: * * get the current property value * * (if there isn't one, create a new empty list of whatevers) * * add the targetElement * * set the property to the newly-revised list */ if (rel.getName().equals("advises")) { addStereotypeProperty("Advice", "advisedElement", sourceElement, targetElement); } else if (rel.getName().equals("declared on")) { System.err.println("StaticCrossCuttingFeature " + sourceElement.getQualifiedName() + " declared on " + targetElement.getQualifiedName()); addStereotypeProperty("StaticCrossCuttingFeature", "onType", sourceElement, targetElement); } } /** * Adds targetElement as the specified property for the specified stereotype, provided * that the stereotype has been applied to the sourceElement. Does nothing if the * specified stereotype hasn't been applied to the sourceElement. * * @param stereotypeName Name of the stereotype * @param propertyName Name of the property to be set * @param sourceElement Element to which property should be applied * @param targetElement New value of the property */ private void addStereotypeProperty(String stereotypeName, String propertyName, NamedElement sourceElement, NamedElement targetElement) { Stereotype stereotype = profile.getStereotype(stereotypeName); if (sourceElement.isStereotypeApplied(stereotype)) { Object propertyObj = sourceElement.getValue(stereotype, propertyName); List<NamedElement> propertyList; if (propertyObj instanceof List) { propertyList = (List<NamedElement>) propertyObj; } else { propertyList = new ArrayList<NamedElement>(); } propertyList.add(targetElement); // sourceElement.setValue(stereotype, propertyName, propertyList); } } private String printInfoOn(IProgramElement element) { String info = printNameTypeOf(element); IProgramElement parent = element.getParent(); if (parent != null) { info += ": child of " + printInfoOn(parent); } else { info += ": childless"; } return info; } /** * Returns the name and type of an IJavaElement. * @param element IJavaElement being examined * @return <i>element-name</i>(<i>element-type</i>) */ private String printNameTypeOf(IProgramElement element) { return element.getName() + "(" + element.getKind().toString() + ")[" + element.getHandleIdentifier() + "]"; } }