/******************************************************************************* * Copyright (c) 2006-2012 * Software Technology Group, Dresden University of Technology * DevBoost GmbH, Berlin, Amtsgericht Charlottenburg, HRB 140026 * * 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: * Software Technology Group - TU Dresden, Germany; * DevBoost GmbH - Berlin, Germany * - initial API and implementation ******************************************************************************/ package org.reuseware.coconut.reuseextension.evaluator.ocl; import java.lang.reflect.Method; import org.eclipse.emf.common.util.BasicEList; import org.eclipse.emf.common.util.EList; import org.eclipse.emf.ecore.EAnnotation; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EClassifier; import org.eclipse.emf.ecore.EEnumLiteral; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EOperation; import org.eclipse.emf.ecore.EPackage; import org.eclipse.emf.ecore.EParameter; import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.emf.ecore.EcoreFactory; import org.eclipse.emf.ecore.EcorePackage; import org.eclipse.ocl.EnvironmentFactory; import org.eclipse.ocl.ecore.CallOperationAction; import org.eclipse.ocl.ecore.Constraint; import org.eclipse.ocl.ecore.EcoreEnvironment; import org.eclipse.ocl.ecore.SendSignalAction; import org.eclipse.ocl.util.TypeUtil; /** * OCL Ecore environment enhanced with: * (1) complete Java String API * (2) eContainer() operation for all elements * (3) getValue() operation for EFeatureMapEntry. */ public class EnhancedEcoreEnvironment extends EcoreEnvironment { protected EList<EOperation> customOperations = new BasicEList<EOperation>(); // this constructor is used to initialize the root environment EnhancedEcoreEnvironment(EPackage.Registry registry) { super(registry); defineStringOperations(); defineContainerOperation(); defineToStringOperation(); defineGetValueOperation(); } // this constructor is used to initialize child environments EnhancedEcoreEnvironment(EnhancedEcoreEnvironment parent) { super(parent); // get the parent's custom operations customOperations.clear(); customOperations.addAll(parent.customOperations); } // override this to provide visibility of the inherited protected method @Override protected void setFactory( EnvironmentFactory<EPackage, EClassifier, EOperation, EStructuralFeature, EEnumLiteral, EParameter, EObject, CallOperationAction, SendSignalAction, Constraint, EClass, EObject> factory) { super.setFactory(factory); } private void defineContainerOperation() { EOperation newOperation = EcoreFactory.eINSTANCE.createEOperation(); newOperation.setName("eContainer"); newOperation.setEType(EcorePackage.Literals.EOBJECT); EAnnotation annotation = EcoreFactory.eINSTANCE.createEAnnotation(); annotation.setSource("EContainerOperation"); newOperation.getEAnnotations().add(annotation); addHelperOperation(getOCLStandardLibrary().getOclAny(), newOperation); } private void defineToStringOperation() { EOperation newOperation = EcoreFactory.eINSTANCE.createEOperation(); newOperation.setName("toString"); newOperation.setEType(getOCLStandardLibrary().getString()); EAnnotation annotation = EcoreFactory.eINSTANCE.createEAnnotation(); annotation.setSource("toStringOperation"); newOperation.getEAnnotations().add(annotation); addHelperOperation(getOCLStandardLibrary().getInteger(), newOperation); } private void defineGetValueOperation() { EOperation newOperation = EcoreFactory.eINSTANCE.createEOperation(); newOperation.setName("getValue"); newOperation.setEType(EcorePackage.Literals.EJAVA_OBJECT); EAnnotation annotation = EcoreFactory.eINSTANCE.createEAnnotation(); annotation.setSource("getValueOperation"); newOperation.getEAnnotations().add(annotation); addHelperOperation(EcorePackage.Literals.EFEATURE_MAP_ENTRY, newOperation); } // use the AbstractEnvironment's mechanism for defining "additional operations" // to add our custom operation to OCL's String primitive type private void defineStringOperations() { //iterate over the String API for (Method stringMethod : String.class.getDeclaredMethods()) { if (isDefinedInOCL(stringMethod)) { continue; } EOperation newOperation = EcoreFactory.eINSTANCE.createEOperation(); boolean usable = true; String name = stringMethod.getName(); Class<?> javaType = stringMethod.getReturnType(); newOperation.setName(name); EClassifier eType = javaTypeToEType(javaType); if (eType == null) { usable = false; continue; } else { newOperation.setEType(eType); int pIndex = 0; for (Class<?> pJavaType : stringMethod.getParameterTypes()) { EParameter parm = EcoreFactory.eINSTANCE.createEParameter(); parm.setName("p" + pIndex); EClassifier pEType = javaTypeToEType(pJavaType); if (pEType == null) { usable = false; break; } parm.setEType(pEType); newOperation.getEParameters().add(parm); pIndex++; } } if (usable) { // annotate it so that we will recognize it in the evaluation environment EAnnotation annotation = EcoreFactory.eINSTANCE.createEAnnotation(); annotation.setSource("JavaMethod"); newOperation.getEAnnotations().add(annotation); // define it as an additional operation on OCL String addHelperOperation(getOCLStandardLibrary().getString(), newOperation); } } } private boolean isDefinedInOCL(Method stringMethod) { if (stringMethod.getName().equals("substring") && stringMethod.getParameterTypes().length == 2) { return true; } //TODO should we add more here? return false; } private EClassifier javaTypeToEType(Class<?> javaType) { EClassifier eClassifier = null; boolean isArray = javaType.isArray(); if (isArray) { javaType = javaType.getComponentType(); } if (javaType == String.class) { eClassifier = getOCLStandardLibrary().getString(); } else if (javaType == CharSequence.class) { eClassifier = getOCLStandardLibrary().getString(); } else if (javaType == int.class) { eClassifier = getOCLStandardLibrary().getInteger(); } else if (javaType == boolean.class) { eClassifier = getOCLStandardLibrary().getBoolean(); } if (isArray && eClassifier != null) { eClassifier = TypeUtil.resolveSequenceType(this, eClassifier); } return eClassifier; } }