/******************************************************************************* * Copyright (c) 2011, 2015 Willink Transformations 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: * E.D.Willink - initial API and implementation *******************************************************************************/ package org.eclipse.ocl.pivot.internal.library; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.List; import org.apache.log4j.Logger; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EReference; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.Nullable; import org.eclipse.ocl.pivot.Element; import org.eclipse.ocl.pivot.ElementExtension; import org.eclipse.ocl.pivot.ExpressionInOCL; import org.eclipse.ocl.pivot.Feature; import org.eclipse.ocl.pivot.Property; import org.eclipse.ocl.pivot.Stereotype; import org.eclipse.ocl.pivot.TupleType; import org.eclipse.ocl.pivot.Type; import org.eclipse.ocl.pivot.ids.TuplePartId; import org.eclipse.ocl.pivot.internal.manager.PivotMetamodelManager; import org.eclipse.ocl.pivot.internal.utilities.EnvironmentFactoryInternal; import org.eclipse.ocl.pivot.internal.utilities.Technology; import org.eclipse.ocl.pivot.library.LibraryFeature; import org.eclipse.ocl.pivot.library.LibraryProperty; import org.eclipse.ocl.pivot.library.UnsupportedOperation; import org.eclipse.ocl.pivot.resource.ASResource; import org.eclipse.ocl.pivot.util.DerivedConstants; /** * ImplementationManager encapsulates the knowledge about known feature implementations. */ public class ImplementationManager { private static final Logger logger = Logger.getLogger(ImplementationManager.class); protected final @NonNull EnvironmentFactoryInternal environmentFactory; protected final @NonNull Technology technology; private final @NonNull PivotMetamodelManager metamodelManager; /** * ClassLoaders that may be able to load a library implementation. */ private List<@NonNull ClassLoader> classLoaders = null; public ImplementationManager(@NonNull EnvironmentFactoryInternal environmentFactory) { this.environmentFactory = environmentFactory; this.technology = environmentFactory.getTechnology(); this.metamodelManager = environmentFactory.getMetamodelManager(); } public void addClassLoader(@NonNull ClassLoader classLoader) { List<ClassLoader> classLoaders = getClassLoaders(); if (!classLoaders.contains(classLoader)) { classLoaders.add(classLoader); } } public @NonNull List<@NonNull ClassLoader> getClassLoaders() { List<@NonNull ClassLoader> classLoaders2 = classLoaders; if (classLoaders2 == null) { classLoaders2 = classLoaders = new ArrayList<@NonNull ClassLoader>(); ClassLoader classLoader = metamodelManager.getClass().getClassLoader(); assert classLoader != null; classLoaders2.add(classLoader); } return classLoaders2; } /* protected @NonNull LibraryOperation getOperationImplementation(@NonNull Operation operation) { LibraryFeature implementation = metamodelManager.getImplementation(operation); String implementationClassName = operation.getImplementationClass(); if (implementationClassName != null) { if (!implementation.getClass().getName().equals(implementationClassName)) { try { implementation = loadImplementation(operation); if (implementation instanceof LibraryOperation) { return (LibraryOperation)implementation; } } catch (Exception e) { logger.error("Failed to load implementation of '" + operation + "'", e); } return UnsupportedOperation.INSTANCE; } } ExpressionInOCL specification = metamodelManager.getBodyExpression(operation); if (specification != null) { return new ConstrainedOperation(specification); } return UnsupportedOperation.INSTANCE; } */ public @NonNull LibraryProperty getPropertyImplementation(@Nullable Element asNavigationExp, @Nullable Object sourceValue, @NonNull Property property) { LibraryFeature implementation = property.getImplementation(); String implementationClassName = property.getImplementationClass(); if (implementationClassName != null) { if ((implementation == null) || !implementation.getClass().getName().equals(implementationClassName)) { try { implementation = loadImplementation(property); if (implementation instanceof LibraryProperty) { return (LibraryProperty) implementation; } } catch (Exception e) { logger.error("Failed to load implementation of '" + property + "'", e); } return UnsupportedOperation.INSTANCE; } } Type type = property.getType(); if ((type instanceof Stereotype) && property.getName().startsWith(DerivedConstants.STEREOTYPE_EXTENSION_PREFIX)) { return technology.createExtensionPropertyImplementation(environmentFactory, property); } // if (property.getOwningType() instanceof Stereotype) { // return new BaseProperty(property); // } ExpressionInOCL specification = metamodelManager.getDefaultExpression(property); if (property.isIsDerived() && (specification != null)) { return new ConstrainedProperty(property); } Property opposite = property.getOpposite(); if ((opposite != null) && opposite.isIsComposite()) { if (property.eContainer() instanceof Stereotype) { return technology.createBasePropertyImplementation(environmentFactory, property); } if (type != null) { EObject eTarget = opposite.getESObject(); if (eTarget instanceof EReference) { return new CompositionProperty((EReference) eTarget, opposite.getPropertyId()); } if (eTarget != null) { Resource resource = opposite.eResource(); if (resource instanceof ASResource) { ASResource asResource = (ASResource)resource; EReference eReference = asResource.getASResourceFactory().getEReference(asResource, eTarget); if (eReference != null) { return new CompositionProperty(eReference, opposite.getPropertyId()); } } } /* eTarget = type.getETarget(); if (eTarget != null) { EClass eOwningClass = eTarget.eClass(); EClass eOwnedClass = property.getOwningType().getETarget().eClass(); EList<EStructuralFeature> ownerStructuralFeatures = eOwningClass.getEAllStructuralFeatures(); EList<EStructuralFeature> ownedStructuralFeatures = eOwnedClass.getEAllStructuralFeatures(); EStructuralFeature eFeature = EcoreUtils.getNamedElement(ownerStructuralFeatures, opposite.getName()); if (eFeature instanceof EReference) { return new CompositionProperty((EReference) eFeature, opposite.getPropertyId()); } } */ } } if (property.isIsImplicit()) { return new ImplicitNonCompositionProperty(property); } if (property.getOwningClass() instanceof TupleType) { TupleType tupleType = (TupleType)property.getOwningClass(); String name = property.getName(); assert name != null; TuplePartId tuplePartId = tupleType.getTypeId().getPartId(name); assert tuplePartId != null; return new TuplePartProperty(tuplePartId); } if (property.isIsStatic()) { return new StaticProperty(property); } if ((property.getOwningClass() instanceof ElementExtension) // direct access to extension property || (property.getOwningClass() instanceof Stereotype)) { // indirect access from a Stereotype operation return technology.createStereotypePropertyImplementation(environmentFactory, property); } return technology.createExplicitNavigationPropertyImplementation(environmentFactory, asNavigationExp, sourceValue, property); } public void dispose() { classLoaders = null; } /** * Return the implementation of a feature. * * @param feature to be implemented. * @return the implementation, or null if the feature has no implementation * as is the case for a normal model feature * @throws ClassNotFoundException if the implementation class realising * the implementation is not loadable * @throws NoSuchFieldException if the implementation class realising * the implementation does not provide a static INSTANCE field * @throws SecurityException if the implementation class is not accessible * @throws IllegalAccessException if the implementation class is not accessible * @throws IllegalArgumentException if the implementation class is not accessible */ public @Nullable LibraryFeature loadImplementation(@NonNull Feature feature) throws ClassNotFoundException, SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException { LibraryFeature implementation = feature.getImplementation(); if (implementation == null) { String implementationClassName = feature.getImplementationClass(); if (implementationClassName != null) { Class<?> theClass = null; ClassLoader featureClassLoader = feature.getClass().getClassLoader(); if (featureClassLoader != null) { addClassLoader(featureClassLoader); } ClassNotFoundException e = null; for (@NonNull ClassLoader classLoader : getClassLoaders()) { try { theClass = classLoader.loadClass(implementationClassName); e = null; break; } catch (ClassNotFoundException e1) { if (e == null) { e = e1; } } } if (e != null) { throw e; } if (theClass != null) { Field field = theClass.getField("INSTANCE"); implementation = (LibraryFeature) field.get(null); } } } return implementation; } }