/******************************************************************************* * Copyright (c) 2009, 2010 SAP AG and others. * 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: * SAP AG - initial API and implementation ******************************************************************************/ package de.hpi.sam.bp2009.solution.oclToAst.impl; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Map.Entry; import java.util.logging.Level; import java.util.logging.Logger; import org.eclipse.emf.common.util.Diagnostic; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.EAnnotation; import org.eclipse.emf.ecore.EAttribute; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EClassifier; import org.eclipse.emf.ecore.EModelElement; import org.eclipse.emf.ecore.ENamedElement; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EOperation; import org.eclipse.emf.ecore.EPackage; import org.eclipse.emf.ecore.EReference; import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.emf.ecore.EcoreFactory; import org.eclipse.emf.ecore.EcorePackage; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.emf.ecore.resource.ResourceSet; import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl; import org.eclipse.emf.ecore.util.EcoreUtil; import org.eclipse.emf.ecore.xmi.impl.EcoreResourceFactoryImpl; import org.eclipse.emf.query.index.IndexFactory; import org.eclipse.ocl.ParserException; import org.eclipse.ocl.SemanticException; import org.eclipse.ocl.ecore.OCL; import org.eclipse.ocl.ecore.OCL.Helper; import org.eclipse.ocl.ecore.OCLExpression; import org.eclipse.ocl.ecore.delegate.InvocationBehavior; import org.eclipse.ocl.ecore.delegate.OCLDelegateDomain; import org.eclipse.ocl.ecore.delegate.SettingBehavior; import org.eclipse.ocl.ecore.delegate.ValidationBehavior; import org.eclipse.ocl.utilities.UMLReflection; import com.sap.ocl.oppositefinder.query2.EcoreHelper; import de.hpi.sam.bp2009.solution.oclToAst.EAnnotationOCLParser; import de.hpi.sam.bp2009.solution.oclToAst.ErrorMessage; import de.hpi.sam.bp2009.solution.queryContextScopeProvider.impl.ProjectDependencyQueryContextProvider; import de.hpi.sam.bp2009.solution.scopeProvider.impl.ProjectBasedScopeProviderImpl; /** * The {@link OCL} object created and used by this annotations parser is constructed with an {@link OclAstEcoreEnvironmentFactory} * as environment factory, using a {@link ProjectDependencyQueryContextProvider} as query context provider. */ public class EAnnotationOCLParserImpl implements EAnnotationOCLParser { private ResourceChanger rc = new ResourceChanger(); private List<ErrorMessage> messages = new ArrayList<ErrorMessage>(); private ResourceSet resourceSet = new ResourceSetImpl(); private EPackage.Registry registry = EPackage.Registry.INSTANCE; /** * Loads the resource specified by the given uri with the default {@link EcoreResourceFactoryImpl}, parse all matching * EAnnotations and saves the resource. It will be created only one resource set for all loaded resources * * @param fileUri */ @Override public void convertAnnotations(URI fileUri) { /* * Load the resource using the URI. Factory get inferred by the ResourceFactoryRegistry */ Resource r = null; try { r = resourceSet.getResource(fileUri, true); EcoreHelper.getInstance().addResourceToDefaultIndex(IndexFactory.getInstance(), r); r.load(null); } catch (Exception e) { e.printStackTrace(); getAllOccurredErrorMessages().add(new ErrorMessageImpl(e, "Error during Resource load." + fileUri, r)); return; } Collection<EPackage> saltPackages = new HashSet<EPackage>(); /* * collect all EPackages inScope */ ProjectBasedScopeProviderImpl scopi = new ProjectBasedScopeProviderImpl(r); for (EObject o : scopi.getForwardScopeAsEObjects()) { if (o instanceof EPackage) { saltPackages.add((EPackage) o); } } for (EObject o : scopi.getBackwardScopeAsEObjects()) { if (o instanceof EPackage) { saltPackages.add((EPackage) o); } } this.setRegistry(new OclAstRegistry(EPackage.Registry.INSTANCE, saltPackages)); /* * enable lookups from the resource set */ resourceSet.setPackageRegistry(this.getRegistry()); for (EObject sPkg : r.getContents()) { if (sPkg instanceof EPackage) { handlePackage((EPackage) sPkg); } } } private void handlePackage(EPackage sPkg) { /* * change the current resource to the ecore from the loaded packages */ Resource rs = sPkg.eResource(); if (((EPackage) sPkg).getEAnnotation(OCL_TYPES) != null) { ((EPackage) sPkg).getEAnnotation(OCL_TYPES).getContents().clear(); } System.out.println("Converting package " + sPkg.getName() + " with nsURI " + sPkg.getNsURI()); traversalConvertOclAnnotations(sPkg); try { rs.save(null); } catch (IOException e) { getAllOccurredErrorMessages().add(new ErrorMessageImpl(e, "Error during Resource save.", sPkg)); } } /* * (non-Javadoc) * * @see de.hpi.sam.bp2009.solution.oclToAst.EAnnotationOCLParser#convertOclAnnotation(org.eclipse.emf.ecore.EModelElement) */ public void convertOclAnnotation(EModelElement modelElement) { EAnnotation anno = modelElement.getEAnnotation(OCLDelegateDomain.OCL_DELEGATE_URI); if (anno == null) return; anno.getContents().clear(); for (Entry<String, String> detail : anno.getDetails()) { String expr = detail.getValue(); String typ = detail.getKey(); if (expr == null) return; OCL ocl = org.eclipse.ocl.examples.impactanalyzer.util.OCL.newInstance(this.getRegistry()); Helper helper = ocl.createOCLHelper(); setCorrectContext(helper, modelElement); OCLExpression constraint = createConstraint(modelElement, expr, typ, helper); if (constraint == null) return; anno.getContents().add(constraint); /* * Iterate the AST, search for OCL specific types, and add them to the resource of the EAnnotation */ constraint.accept(rc); EPackage p = getRootPackage(modelElement); if (p != null) { addOclTypesAnnotationToPackage(rc.getSet(), p); } else { getAllOccurredErrorMessages() .add(new ErrorMessageImpl(new IllegalArgumentException(), "No Package as root element available", modelElement)); } } } private OCLExpression createConstraint(EModelElement modelElement, String expr, String typ, Helper helper) { OCLExpression constraint = null; // try { // if (UMLReflection.DERIVATION.equals(typ)) { // constraint = helper.createDerivedValueExpression(expr); // } else if (UMLReflection.INITIAL.equals(typ)) { // constraint = helper.createInitialValueExpression(expr); // } else if (UMLReflection.BODY.equals(typ)) { // constraint = helper.createBodyCondition(expr); // } else if (UMLReflection.POSTCONDITION.equals(typ)) { // constraint = helper.createPostcondition(expr); // } else if (UMLReflection.PRECONDITION.equals(typ)) { // constraint = helper.createPrecondition(expr); // } else if (UMLReflection.DEFINITION.equals(typ)) { // constraint = helper.createConstraint(ConstraintKind.DEFINITION, expr); // } else /* as default value, an invariant is expected */{ // constraint = helper.createInvariant(expr); // constraint.setName(typ); // } // } catch (ParserException e1) { // parserExceptionHandling(modelElement, expr, e1); // } try{ if (UMLReflection.DERIVATION.equals(typ) || UMLReflection.INITIAL.equals(typ)) { constraint = SettingBehavior.INSTANCE.getFeatureBody(helper.getOCL(), (EStructuralFeature) modelElement); } else if (UMLReflection.BODY.equals(typ)) { constraint = InvocationBehavior.INSTANCE.getOperationBody(helper.getOCL(), (EOperation) modelElement); // } else if (UMLReflection.POSTCONDITION.equals(typ)) { // constraint = helper.createPostcondition(expr); // } else if (UMLReflection.PRECONDITION.equals(typ)) { // constraint = helper.createPrecondition(expr); // } else if (UMLReflection.DEFINITION.equals(typ)) { // constraint = helper.createConstraint(ConstraintKind.DEFINITION, expr); } else /* as default value, an invariant is expected */{ constraint = ValidationBehavior.INSTANCE.getInvariant((EClassifier) modelElement, typ, helper.getOCL()); constraint.setName(typ); } } catch(Exception e){ SemanticException semExep = null; if (e.getCause() instanceof SemanticException){ semExep = (SemanticException) e.getCause(); } parserExceptionHandling(modelElement, expr, semExep); } if (constraint == null){ } return constraint; } private void setCorrectContext(Helper helper, EModelElement modelElement) { switch (modelElement.eClass().getClassifierID()) { case EcorePackage.ECLASSIFIER: case EcorePackage.ECLASS: case EcorePackage.EDATA_TYPE: helper.setContext((EClassifier) modelElement); break; case EcorePackage.EATTRIBUTE: EAttribute at = (EAttribute) modelElement; helper.setAttributeContext(at.getEContainingClass(), at); break; case EcorePackage.EREFERENCE: EReference ref = (EReference) modelElement; helper.setAttributeContext(ref.getEContainingClass(), ref); break; case EcorePackage.EOPERATION: EOperation op = (EOperation) modelElement; helper.setOperationContext(op.getEContainingClass(), op); break; default: helper.setInstanceContext(modelElement); break; } } private void parserExceptionHandling(EModelElement modelElement, String expression, ParserException e1) { String errorMessage = "Ocl expression parsing failed on element " + getQualifiedName(modelElement) + " " + modelElement.toString() + ":\n for ocl expression:\n" + expression + "\n with parser error: \n" + e1.getMessage() + "\n"; if (e1.getDiagnostic() != null) { for (Diagnostic c : e1.getDiagnostic().getChildren()) { errorMessage += c.getMessage() + "\n"; } } Logger logger = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME); logger.log(Level.SEVERE, errorMessage); getAllOccurredErrorMessages().add(new ErrorMessageImpl(e1, "Error during Query parsing", expression)); } private String getQualifiedName(EObject modelElement) { StringBuilder result = new StringBuilder(); if (modelElement instanceof ENamedElement) { result.append(((ENamedElement) modelElement).getName()); if (modelElement.eContainer() != null) { result.insert(0, '.'); result.insert(0, getQualifiedName(modelElement.eContainer())); } } return result.toString(); } /* * (non-Javadoc) * * @see de.hpi.sam.bp2009.solution.oclToAst.EAnnotationOCLParser#getAllOccurredErrorMessages() */ @Override public Collection<ErrorMessage> getAllOccurredErrorMessages() { return messages; } /* * (non-Javadoc) * * @see * de.hpi.sam.bp2009.solution.oclToAst.EAnnotationOCLParser#traversalConvertOclAnnotations(org.eclipse.emf.ecore.EPackage) */ @Override public void traversalConvertOclAnnotations(EPackage pkg) { // // to convert annotations with 'old' uri into annotations with new uri // EAnnotation anno = pkg.getEAnnotation("http://www.eclipse.org/emf/2002/Ecore"); // if (anno != null){ // for (Entry<String, String> entry: anno.getDetails()){ // entry.setValue(OCLDelegateDomain.OCL_DELEGATE_URI); // } // } for (EClassifier cls : pkg.getEClassifiers()) { convertOclAnnotation(cls); if (cls instanceof EClass) { for (EOperation op : ((EClass) cls).getEOperations()) convertOclAnnotation(op); for (EAttribute at : ((EClass) cls).getEAttributes()) convertOclAnnotation(at); } } for (EPackage p : pkg.getESubpackages()) traversalConvertOclAnnotations(p); } /** * Adds all given oclTypes to the oclTypes annotation of the given package * * @param collection * all types to add * @param p * the package to get the annotation */ private void addOclTypesAnnotationToPackage(Collection<EObject> col, EPackage p) { Collection<EObject> collection = new HashSet<EObject>(col); EAnnotation annotation = p.getEAnnotation(OCL_TYPES); if (annotation == null) { annotation = EcoreFactory.eINSTANCE.createEAnnotation(); annotation.setSource(OCL_TYPES); } else { // to remove all OCL_Types annotations from model // EcoreUtil.remove(annotation); collection.addAll(annotation.getContents()); annotation.getContents().clear(); } annotation.getContents().addAll(collection); p.getEAnnotations().add(annotation); /* * after resolving, all names of BagTypes are set due to a bug in the BagTypeImpl this is necessary */ for (EObject o : collection) { EcoreUtil.getURI(o); } } /** * Calculates the root package for a given element * * @param modelElement * get the root package for this * @return the root package */ private EPackage getRootPackage(EModelElement modelElement) { EPackage p = null; EObject current = modelElement; while (current != null) { if (current instanceof EPackage) { p = (EPackage) current; break; } current = current.eContainer(); } return p; } private void setRegistry(EPackage.Registry registry) { this.registry = registry; } private EPackage.Registry getRegistry() { return registry; } } // EAnnotationOCLParserImpl