| /******************************************************************************* |
| * Copyright (c) 2013 Vienna University of Technology. |
| * 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: |
| * Alexander Bergmayr (Vienna University of Technology) - initial API and implementation |
| * |
| * Initially developed in the context of ARTIST EU project www.artist-project.eu |
| *******************************************************************************/ |
| package org.eclipse.upr.platform.java.cm2up; |
| |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| |
| import org.apache.commons.lang.StringUtils; |
| import org.eclipse.emf.ecore.EObject; |
| import org.eclipse.gmt.modisco.java.AbstractTypeDeclaration; |
| import org.eclipse.gmt.modisco.java.Annotation; |
| import org.eclipse.gmt.modisco.java.AnnotationTypeDeclaration; |
| import org.eclipse.gmt.modisco.java.AnnotationTypeMemberDeclaration; |
| import org.eclipse.gmt.modisco.java.ArrayInitializer; |
| import org.eclipse.gmt.modisco.java.BooleanLiteral; |
| import org.eclipse.gmt.modisco.java.CharacterLiteral; |
| import org.eclipse.gmt.modisco.java.Expression; |
| import org.eclipse.gmt.modisco.java.NumberLiteral; |
| import org.eclipse.gmt.modisco.java.PrefixExpression; |
| import org.eclipse.gmt.modisco.java.SingleVariableAccess; |
| import org.eclipse.gmt.modisco.java.StringLiteral; |
| import org.eclipse.gmt.modisco.java.TypeDeclaration; |
| import org.eclipse.gmt.modisco.java.TypeLiteral; |
| import org.eclipse.gmt.modisco.java.emf.JavaPackage; |
| import org.eclipse.m2m.atl.core.IModel; |
| import org.eclipse.uml2.uml.Element; |
| import org.eclipse.uml2.uml.Enumeration; |
| import org.eclipse.uml2.uml.PrimitiveType; |
| import org.eclipse.uml2.uml.Property; |
| import org.eclipse.uml2.uml.Stereotype; |
| import org.eclipse.uml2.uml.Type; |
| import org.eclipse.uml2.uml.UMLPackage; |
| import org.eclipse.upr.platform.trace.Trace; |
| import org.eclipse.upr.platform.trace.TraceLink; |
| import org.eclipse.upr.platform.trace.TracePackage; |
| |
| /** |
| * @author Alexander Bergmayr |
| * |
| */ |
| public class CodeModel2UMLProfilePostProcessor { |
| |
| /** |
| * |
| */ |
| private static Map<EObject, TraceLink> profileModel2CodeModeltraceMap = new HashMap<EObject, TraceLink>(); |
| |
| /** |
| * |
| */ |
| private static Map<EObject, EObject> codeModel2ProfileModeltraceMap = new HashMap<EObject, EObject>(); |
| |
| /** |
| * |
| * @param codeModel |
| * @param profileModel |
| * @param traceModel |
| */ |
| public static void runPostProcessing(IModel codeModel, IModel profileModel, |
| IModel traceModel) { |
| // init the trace map |
| initProfileModel2CodeModelTraceMap(traceModel); |
| initCodeModel2ProfileModelTraceMap(traceModel); |
| |
| // set default values |
| setDefaultValues(); |
| |
| // helper collection to find property duplicates |
| Collection<String> properties = new ArrayList<String>(); |
| |
| // helper collection that stores the elements to destroy |
| Collection<Element> umlRemovals = new ArrayList<Element>(); |
| Set<TraceLink> traceRemovals = new HashSet<TraceLink>(); |
| |
| // check the stereotypes for duplicates -> Property, Association, |
| // Operation |
| Set<? extends Object> stereotypes = profileModel |
| .getElementsByType(UMLPackage.eINSTANCE.getStereotype()); |
| |
| for (Object obj : stereotypes) { |
| Stereotype stereotype = (Stereotype) obj; |
| |
| // TODO: maybe work with validators here !! |
| for (Property property : stereotype.getAllAttributes()) { |
| if (properties.contains(property.getName())) { |
| |
| // the extension member ends of the Extension |
| for (Property extensionEnd : property.getAssociation() |
| .getMemberEnds()) { |
| umlRemovals.add(extensionEnd); |
| |
| // if we remove an Operation extension, we should remove |
| // the constructor |
| // constraint as well |
| if (property.getType().getName().equalsIgnoreCase("Operation")) { |
| umlRemovals.add(stereotype.getOwnedRule("constructorConstraint")); |
| } |
| |
| // if we remove a Property extension, we should remove |
| // the method |
| // constraint as well |
| if (property.getType().getName().equalsIgnoreCase("Property")) { |
| umlRemovals.add(stereotype.getOwnedRule("methodConstraint")); |
| } |
| |
| traceRemovals.add(profileModel2CodeModeltraceMap.get(extensionEnd)); |
| } |
| |
| // the Extension |
| umlRemovals.add(property.getAssociation()); |
| traceRemovals.add(profileModel2CodeModeltraceMap.get(property |
| .getAssociation())); |
| |
| // TODO: we need to remove constraints regarding operations |
| // as well! |
| } else { |
| properties.add(property.getName()); |
| } |
| } |
| |
| // clear the collection of properties for the next stereotype |
| properties.clear(); |
| } |
| |
| // remove the trace links |
| for (TraceLink traceLink : traceRemovals) { |
| Trace trace = (Trace) traceLink.eContainer(); |
| trace.getTraceLinks().remove(traceLink); |
| } |
| |
| // remove the uml elements |
| for (Element element : umlRemovals) { |
| element.destroy(); |
| } |
| } |
| |
| private static void setDefaultValues() { |
| for (EObject eObj : codeModel2ProfileModeltraceMap.keySet()) { |
| if (eObj instanceof AnnotationTypeMemberDeclaration) { |
| AnnotationTypeMemberDeclaration member = (AnnotationTypeMemberDeclaration) eObj; |
| |
| if (member.getDefault() != null) { |
| Object value = getValueFromExpression(member.getDefault()); |
| |
| if (value != null) { |
| EObject umlElement = codeModel2ProfileModeltraceMap.get(member); |
| |
| if (umlElement != null) { |
| Property umlProperty = (Property) umlElement; |
| |
| // TODO: We need to properly deal with "empty" values, e.g., {} |
| if(!(value.toString().equalsIgnoreCase("[]") || |
| value.toString().equalsIgnoreCase("\"\""))) { |
| |
| if(!isNumericPrimitiveType(umlProperty.getType()) || |
| (isNumericPrimitiveType(umlProperty.getType()) && StringUtils.isNumeric(value.toString()))) { |
| |
| |
| if(umlProperty.getType() instanceof Enumeration && umlProperty.isMultivalued()) { |
| // remove brackets |
| value = value.toString().substring(1, value.toString().length() -1); |
| } |
| umlProperty.setDefault(value.toString()); |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| private static boolean isNumericPrimitiveType(Type type) { |
| boolean isNumeric = false; |
| |
| if(type instanceof PrimitiveType) { |
| PrimitiveType primType = (PrimitiveType) type; |
| |
| if(primType.getName().equalsIgnoreCase("long") || primType.getName().equalsIgnoreCase("int") || |
| primType.getName().equalsIgnoreCase("double") || primType.getName().equalsIgnoreCase("float")) { |
| isNumeric = true; |
| } |
| } |
| |
| return isNumeric; |
| } |
| |
| /** |
| * |
| * |
| * @param umlElement |
| * @param valueExpression |
| * @return the UML value for a given Java expression. |
| */ |
| private static Object getValueFromExpression( |
| /* Element umlElement, */Expression valueExpression) { |
| // TODO: their might still be cases that are not yet covered. |
| Object value = null; |
| |
| // multi-valued expression |
| if (valueExpression.eClass().getClassifierID() == JavaPackage.ARRAY_INITIALIZER) { |
| ArrayInitializer arrayInitializer = (ArrayInitializer) valueExpression; |
| List<Object> values = new ArrayList<Object>(); |
| |
| for (Expression expression : arrayInitializer.getExpressions()) { |
| |
| if (expression.eClass().getClassifierID() == JavaPackage.ANNOTATION) { |
| Annotation javaAnnotation = (Annotation) expression; |
| |
| AnnotationTypeDeclaration annotationType = (AnnotationTypeDeclaration) javaAnnotation |
| .getType().getType(); |
| value = annotationType.getName(); |
| // Stereotype umlStereotype = |
| // this.getElementFromProfile(annotationType, |
| // Stereotype.class); |
| // if(umlStereotype != null && umlElement != null) { |
| // |
| // EClass stereotypeDefinition = |
| // this.getStereotypeDefinition(umlElement, umlStereotype); |
| // if(stereotypeDefinition != null) { |
| // EObject stereotypeInstance = |
| // EcoreUtil.create(stereotypeDefinition); |
| // this.setValues(javaAnnotation, umlElement, |
| // stereotypeInstance); |
| // values.add(stereotypeInstance); |
| // |
| // // stats |
| // this.reportStereotypeApplication(umlStereotype); |
| // notRecognizedAnnotationCounter--; |
| // } |
| // } |
| // else { |
| // System.out.println("... null value"); |
| // } |
| } |
| |
| if (expression.eClass().getClassifierID() == JavaPackage.SINGLE_VARIABLE_ACCESS) { |
| values |
| .add(getValueFromSingleVariableAccess((SingleVariableAccess) expression)); |
| } |
| |
| } |
| return values; |
| } |
| |
| // EnumerationLiteral |
| else if (valueExpression.eClass().getClassifierID() == JavaPackage.SINGLE_VARIABLE_ACCESS) { |
| // SingleVariableAccess singleVariableAccess = |
| // (SingleVariableAccess) valueExpression; |
| value = getValueFromSingleVariableAccess((SingleVariableAccess) valueExpression); |
| } |
| |
| else if (valueExpression.eClass().getClassifierID() == JavaPackage.TYPE_LITERAL) { |
| TypeLiteral typeLiteral = (TypeLiteral) valueExpression; |
| |
| if (typeLiteral.getType().getType() instanceof TypeDeclaration) { |
| TypeDeclaration type = (TypeDeclaration) typeLiteral.getType() |
| .getType(); |
| value = type.getName(); |
| } |
| |
| else if (typeLiteral.getType().getType() instanceof AnnotationTypeDeclaration) { |
| AnnotationTypeDeclaration annotationType = (AnnotationTypeDeclaration) typeLiteral |
| .getType().getType(); |
| value = annotationType.getName(); |
| } else if (typeLiteral.getType().getType().eClass().getClassifierID() == JavaPackage.PRIMITIVE_TYPE_VOID) { |
| value = "void.class"; |
| } |
| } |
| |
| else if (valueExpression.eClass().getClassifierID() == JavaPackage.ANNOTATION) { |
| Annotation javaAnnotation = (Annotation) valueExpression; |
| |
| AbstractTypeDeclaration annotationType = (AbstractTypeDeclaration) javaAnnotation |
| .getType().getType(); |
| value = annotationType.getName(); |
| } |
| |
| else if (valueExpression.eClass().getClassifierID() == JavaPackage.PREFIX_EXPRESSION) { |
| PrefixExpression prefix = (PrefixExpression) valueExpression; |
| value = prefix.getOperator().toString() |
| .concat(getValueFromExpression(prefix.getOperand()).toString()); |
| |
| } |
| |
| // primitive literal |
| else { |
| if (valueExpression.eClass().getClassifierID() == JavaPackage.STRING_LITERAL) { |
| value = ((StringLiteral) valueExpression).getEscapedValue(); |
| } else if (valueExpression.eClass().getClassifierID() == JavaPackage.CHARACTER_LITERAL) { |
| value = ((CharacterLiteral) valueExpression).getEscapedValue(); |
| } else if (valueExpression.eClass().getClassifierID() == JavaPackage.BOOLEAN_LITERAL) { |
| value = ((BooleanLiteral) valueExpression).isValue(); |
| } else if (valueExpression.eClass().getClassifierID() == JavaPackage.NUMBER_LITERAL) { |
| value = ((NumberLiteral) valueExpression).getTokenValue(); |
| } |
| } |
| |
| return value; |
| } |
| |
| private static Object getValueFromSingleVariableAccess( |
| SingleVariableAccess valueExpression) { |
| if(valueExpression != null && valueExpression.getVariable() != null) { |
| return valueExpression.getVariable().getName(); |
| } |
| else return ""; |
| |
| // Object value = null; |
| // // if the variable isn't a proxy, we should find it in the trace |
| // if(!valueExpression.getVariable().isProxy()) { |
| // // |
| // if(valueExpression.getVariable().eClass().getClassifierID() == |
| // JavaPackage.VARIABLE_DECLARATION_FRAGMENT) { |
| // if(valueExpression.getVariable().getInitializer() != null) { |
| // value = getValueFromExpression(/*null,*/ |
| // valueExpression.getVariable().getInitializer()); |
| // } |
| // else { |
| // value = valueExpression.getVariable().getName(); |
| // } |
| // } |
| // |
| // // else try to find the value in the trace map |
| // Object umlValue = |
| // codeModel2ProfileModeltraceMap.get(valueExpression.getVariable()); |
| // value = umlValue; |
| // } |
| // else { |
| // // let's have a look in the profile |
| // // Element umlValue = |
| // this.getElementFromProfile(valueExpression.getVariable(), |
| // Element.class); |
| // // value = umlValue; |
| // value = valueExpression.getVariable().getName(); |
| // } |
| // |
| // return value; |
| } |
| |
| private static void initProfileModel2CodeModelTraceMap(IModel traceModel) { |
| // Trace t = (Trace) traceModel.getContents().get(0); |
| Set<? extends Object> traceLinks = traceModel |
| .getElementsByType(TracePackage.eINSTANCE.getTraceLink()); |
| for (Object obj : traceLinks) { |
| TraceLink traceLink = (TraceLink) obj; |
| |
| for (EObject eObj : traceLink.getTargetElements()) { |
| if (profileModel2CodeModeltraceMap.containsKey(eObj)) |
| System.out.println("override!"); |
| profileModel2CodeModeltraceMap.put(eObj, traceLink); |
| } |
| } |
| } |
| |
| private static void initCodeModel2ProfileModelTraceMap(IModel traceModel) { |
| Set<? extends Object> traceLinks = traceModel |
| .getElementsByType(TracePackage.eINSTANCE.getTraceLink()); |
| for (Object obj : traceLinks) { |
| TraceLink tl = (TraceLink) obj; |
| |
| if (codeModel2ProfileModeltraceMap.containsKey(tl.getSourceElements() |
| .get(0)) |
| && tl.getSourceElements().get(0).eClass().getClassifierID() == JavaPackage.ANNOTATION_TYPE_DECLARATION) { |
| |
| if (tl.getTargetElements().get(0) instanceof Stereotype) { |
| codeModel2ProfileModeltraceMap.put(tl.getSourceElements().get(0), tl |
| .getTargetElements().get(0)); |
| } |
| } else { |
| // TODO: we have to extend the trace map as we may get a list of |
| // targets in the future |
| codeModel2ProfileModeltraceMap.put(tl.getSourceElements().get(0), tl |
| .getTargetElements().get(0)); |
| } |
| } |
| } |
| |
| } |