/******************************************************************************* * Copyright (c) 2008-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 com.sap.furcas.modeladaptation.emf.adaptation; import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.EClassifier; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.resource.ResourceSet; import org.eclipse.ocl.ecore.opposites.OppositeEndFinder; import com.sap.furcas.runtime.common.exceptions.DeferredActionResolvingException; import com.sap.furcas.runtime.common.exceptions.ModelAdapterException; import com.sap.furcas.runtime.common.exceptions.ReferenceSettingException; import com.sap.furcas.runtime.common.interfaces.IBareModelAdapter; import com.sap.furcas.runtime.common.interfaces.IMetaModelLookup; import com.sap.furcas.runtime.common.interfaces.IModelElementProxy; import com.sap.furcas.runtime.common.util.MessageUtil; import com.sap.furcas.runtime.common.util.TCSSpecificOCLEvaluator; import com.sap.furcas.runtime.parser.PartitionAssignmentHandlerBase; /** * Facade for the creation of EMF model elements. * * This class merely checks for invalid arguments and then delegates functionality (for readability) * to {@link EMFModelAdapterDelegate}. */ public class EMFModelAdapter implements IBareModelAdapter { private final EMFModelAdapterDelegate delegate; public static final String OCL_QUERY_PREFIX = "OCL:"; private static Set<String> javaLangPrimitiveClassnames = new HashSet<String>(); static { javaLangPrimitiveClassnames.add("Boolean"); javaLangPrimitiveClassnames.add("Integer"); javaLangPrimitiveClassnames.add("Long"); javaLangPrimitiveClassnames.add("Double"); javaLangPrimitiveClassnames.add("Float"); javaLangPrimitiveClassnames.add("String"); } /** * Creates a new ModelAdapter which creates EMF model elements. * * @param resourceSet A resourceSet to work on * @param partitioningHandler A partitioning handler that shall be used to partition created elements by adding * them to an appropriate resource. The resources should be contained in the given resourceSet. * @param metamodelLookup A {@link IMetaModelLookup} configured for all the metamodels this modeladapter is supposed to work on. * @param additionalQueryScope A list of additional URIs that shall be looked at when references are * resolved or when existing model elements are queres. The queryScope by default already includes the * URI of the root element * and the visible URIs of the give resource set. In most cases the scope can therefore remain * empty. */ public EMFModelAdapter(ResourceSet resourceSet, PartitionAssignmentHandlerBase partitioningHandler, IMetaModelLookup<EObject> metamodelLookup, Set<URI> additionalQueryScope, TCSSpecificOCLEvaluator oclEvaluator, OppositeEndFinder oppositeEndFinder) { delegate = new EMFModelAdapterDelegate(resourceSet, partitioningHandler, metamodelLookup, additionalQueryScope, oclEvaluator, oppositeEndFinder); } @Override public Object createElement(List<String> typeName) throws ModelAdapterException { assertIsValidTypeName(typeName); try { return delegate.createElement(typeName); } catch (RuntimeException re) { throw new RuntimeException("Exception while creating Element of type " + typeName, re); } } @Override public Object createEnumLiteral(List<String> enumName, String name) throws ModelAdapterException { assertIsValidTypeName(enumName); try { return (delegate.createEnumLiteral(enumName, name)).getInstance(); } catch (RuntimeException re) { throw new RuntimeException("Exception while creating Enum Literal named '" + name + "' of type " + MessageUtil.asModelName(enumName), re); } } @Override public Object get(Object modelElementOrProxy, String propertyName) throws ModelAdapterException { assertArgumentsAreNotNull(modelElementOrProxy, propertyName); EObject modelElement = unwrapModelElementProxyIfAny(modelElementOrProxy); try { if (propertyName.contains(".")) { // path notation prop1.prop2.prop3 Object value = null; for (String part : propertyName.split("\\.")) { value = delegate.get(modelElement, part); if (value == null || !(value instanceof EObject)) { break; } else { modelElement = (EObject) value; } } return value; } else { return delegate.get(modelElement, propertyName); } } catch (RuntimeException re) { throw new RuntimeException("Exception while getting property " + getCutToString(modelElement) + "." + propertyName, re); } } @Override public void set(Object modelElement, String propertyName, Object value) throws ModelAdapterException { assertArgumentsAreNotNull(modelElement, propertyName); if (value == null) { // don't need to call set to set to null, as this is for injection only return; } if (modelElement instanceof StructureTypeMockObject) { StructureTypeMockObject mock = (StructureTypeMockObject) modelElement; mock.setField(propertyName, value); } else { EObject eObject = unwrapModelElementProxyIfAny(modelElement); try { delegate.set(eObject, propertyName, value); } catch (RuntimeException re) { throw new RuntimeException("Exception while setting " + eObject.getClass() + "." + propertyName + " to " + getCutToString(value) + " : " + re.getMessage(), re); } } } @Override public void set(Object sourceModelElementOrProxy, String propertyName, Object value, int index) throws ModelAdapterException { assertArgumentsAreNotNull(sourceModelElementOrProxy, propertyName); if (value == null) { // don't need to call set to set to null, as this is for injection only return; } if (sourceModelElementOrProxy instanceof StructureTypeMockObject) { StructureTypeMockObject mock = (StructureTypeMockObject) sourceModelElementOrProxy; mock.setField(propertyName, value); } else { EObject modelElement = unwrapModelElementProxyIfAny(sourceModelElementOrProxy); try { delegate.set(modelElement, propertyName, value, index); } catch (RuntimeException re) { throw new RuntimeException("Exception while setting " + modelElement.getClass() + "." + propertyName + " to " + getCutToString(value) + " : " + re.getMessage(), re); } } } @Override public void unset(Object sourceModelElementOrProxy, String propertyName, Object value) throws ModelAdapterException { assertArgumentsAreNotNull(sourceModelElementOrProxy, propertyName); if (sourceModelElementOrProxy instanceof StructureTypeMockObject) { StructureTypeMockObject mock = (StructureTypeMockObject) sourceModelElementOrProxy; mock.unsetField(propertyName); } else { EObject modelElement = unwrapModelElementProxyIfAny(sourceModelElementOrProxy); try { delegate.unset(modelElement, propertyName, value); } catch (RuntimeException re) { throw new RuntimeException("Exception while unsetting " + modelElement.getClass() + "." + propertyName + " to " + getCutToString(value) + " : " + re.getMessage(), re); } } } @Override public Object setReferenceWithLookup(Object sourceModelElementOrProxy, String referencePropertyName, List<String> targetType, String targetKeyName, Object targetKeyValue) throws ModelAdapterException, ReferenceSettingException { assertArgumentsAreNotNull(sourceModelElementOrProxy, referencePropertyName, targetType, targetKeyName); EObject modelElement = unwrapModelElementProxyIfAny(sourceModelElementOrProxy); try { return delegate.setReferenceWithLookup(modelElement, referencePropertyName, targetType, targetKeyName, targetKeyValue, null); } catch (RuntimeException re) { throw new RuntimeException("RuntimeException while setting Reference " + sourceModelElementOrProxy + "." + referencePropertyName + " to modelelement of type " + targetType + " with " + targetKeyName + "=" + targetKeyValue, re); } } @Override public Object setReferenceWithContextLookup(Object sourceModelElementOrProxy, String referencePropertyName, List<String> targetType, String targetKeyName, Object targetKeyValue, Object contextObject) throws ModelAdapterException, ReferenceSettingException { assertArgumentsAreNotNull(sourceModelElementOrProxy, referencePropertyName, targetType); EObject sourceModelElement = unwrapModelElementProxyIfAny(sourceModelElementOrProxy); if (contextObject instanceof IModelElementProxy) { contextObject = ((IModelElementProxy) contextObject).getRealObject(); } if (!((contextObject instanceof EObject) || contextObject instanceof Collection<?> || isPrimitive(contextObject))) { throw new IllegalArgumentException("Illegal Model Element type " + contextObject.getClass() + ", EObject required"); } try { return delegate.setReferenceWithLookup(sourceModelElement, referencePropertyName, targetType, targetKeyName, targetKeyValue, contextObject); } catch (RuntimeException re) { throw new RuntimeException("RuntimeException while setting Reference " + sourceModelElement + "." + referencePropertyName + " to modelelement of type " + targetType + " with " + targetKeyName + "=" + targetKeyValue, re); } } /** * Checks if <tt>o</tt>'s Java type qualifies as a primitive type in MOF. In particular, those types are {@link Boolean}, * {@link String}, {@link Float}, {@link Long}, {@link Integer} and {@link Double}. */ private boolean isPrimitive(Object o) { return (o.getClass().getPackage().getName().equals("java.lang") && javaLangPrimitiveClassnames.contains(o.getClass().getSimpleName())); } @Override public Object setReferenceWithOCLQuery(Object sourceModelElementOrProxy, String referencePropertyName, Object keyValue, String oclQuery, Object contextObjectOrProxy, Object currentForeachElementOrProxy) throws ModelAdapterException, ReferenceSettingException { assertArgumentsAreNotNull(sourceModelElementOrProxy, referencePropertyName, oclQuery); EObject sourceModelElement = unwrapModelElementProxyIfAny(sourceModelElementOrProxy); oclQuery = verifyOCLQuery(oclQuery, keyValue); EObject contextObject = contextObjectOrProxy == null ? null : unwrapModelElementProxyIfAny(contextObjectOrProxy); EObject currentForeachElement = currentForeachElementOrProxy == null ? null : unwrapModelElementProxyIfAny(currentForeachElementOrProxy); try { return delegate.setReferenceWithOCLQuery(sourceModelElement, referencePropertyName, keyValue, oclQuery, contextObject, currentForeachElement); } catch (RuntimeException re) { throw new RuntimeException("RuntimeException while setting Reference " + sourceModelElementOrProxy + "." + referencePropertyName + " via via OCL " + oclQuery + " with ? as " + keyValue, re); } } @Override public Collection<?> evaluateOCLQuery(Object sourceModelElementOrProxy, Object keyValue, String oclQuery, Object contextObjectOrProxy) throws ModelAdapterException { assertArgumentsAreNotNull(oclQuery); EObject sourceModelElement = unwrapModelElementProxyIfAny(sourceModelElementOrProxy); oclQuery = verifyOCLQuery(oclQuery, keyValue); EObject contextObject = contextObjectOrProxy == null ? null : unwrapModelElementProxyIfAny(contextObjectOrProxy); try { return delegate.evaluateOCLQuery(sourceModelElement, keyValue, oclQuery, contextObject); } catch (RuntimeException re) { throw new RuntimeException("RuntimeException while evaluation OCL " + oclQuery + " with ? as " + keyValue, re); } } @Override public Collection<Object> queryElement(List<String> typeName, Map<String, List<Object>> attributes) throws ModelAdapterException { assertIsValidTypeName(typeName); try { return delegate.queryElement(typeName, attributes); } catch (RuntimeException e) { throw new RuntimeException("Failed to query element with name " + typeName, e); } } @Override public boolean instanceOf(Object modelElement, Object metaType) throws ModelAdapterException { assertArgumentsAreNotNull(modelElement, metaType); if (!(modelElement instanceof EObject)) { throw new IllegalArgumentException("Unknown Model Element type " + modelElement.getClass()); } if (!(metaType instanceof EClassifier)) { throw new IllegalArgumentException("Unknown meta type " + metaType.getClass()); } try { return delegate.instanceOf((EObject) modelElement, (EClassifier) metaType); } catch (RuntimeException re) { throw new RuntimeException("Exception while checking " + modelElement + " instanceOf " + metaType, re); } } @Override public Object getMetaType(List<String> typeName) throws ModelAdapterException { assertIsValidTypeName(typeName); return delegate.getMetaType(typeName); } @Override public boolean hasDeferredActions() { return delegate.hasDeferredActions(); } @Override public Map<Object, Object> performAllDeferredActions() throws DeferredActionResolvingException { return delegate.performAllDeferredActions(); } private static EObject unwrapModelElementProxyIfAny(Object modelElementOrProxy) throws IllegalArgumentException { if (modelElementOrProxy instanceof EObject) { return (EObject) modelElementOrProxy; } else if (modelElementOrProxy instanceof IModelElementProxy) { return (EObject) ((IModelElementProxy) modelElementOrProxy).getRealObject(); } else { throw new IllegalArgumentException("Unknown Model Element type " + modelElementOrProxy.getClass()); } } private static void assertIsValidTypeName(List<String> enumName) { if (enumName == null || enumName.size() == 0) { throw new IllegalArgumentException("typeName was null or empty: " + enumName); } else { for (String namePart : enumName) { if (namePart == null || namePart.trim().equals("")) { throw new IllegalArgumentException("typeName part was null or empty: " + enumName); } } } } private static void assertArgumentsAreNotNull(Object... arguments) throws IllegalArgumentException { for (Object arg : arguments) { if (arg == null) { throw new IllegalArgumentException("A given argument was null"); } } } private String verifyOCLQuery(String oclQuery, Object keyValue) throws ReferenceSettingException { if (keyValue instanceof EObject || keyValue instanceof StructureTypeMockObject) { throw new ReferenceSettingException("Queries by non-primitive References not possible: " + oclQuery); } if (oclQuery.startsWith(OCL_QUERY_PREFIX)) { return oclQuery.substring(OCL_QUERY_PREFIX.length()); } else { return oclQuery; } } private static String getCutToString(Object object) { if (object == null) { return null; } String toString = object.toString(); String[] tokens = toString.split("\\s"); return tokens[0]; } }