blob: 0577d7416862de2cf63fa06cbf177301bd159bcb [file] [log] [blame]
/*******************************************************************************
* 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));
}
}
}
}