/******************************************************************************* * Copyright (c) 2010, 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: * C.Damus, K.Hussey, E.D.Willink - Initial API and implementation *******************************************************************************/ package org.eclipse.ocl.pivot.internal.delegate; import java.util.List; import java.util.Map; import org.eclipse.emf.common.EMFPlugin; import org.eclipse.emf.common.notify.Adapter; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EClassifier; import org.eclipse.emf.ecore.EModelElement; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EOperation; import org.eclipse.emf.ecore.EPackage; import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.emf.ecore.EValidator; import org.eclipse.emf.ecore.impl.ValidationDelegateRegistryImpl; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.emf.ecore.resource.ResourceSet; import org.eclipse.emf.ecore.util.QueryDelegate; import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.Nullable; import org.eclipse.ocl.common.delegate.DelegateResourceSetAdapter; import org.eclipse.ocl.common.delegate.VirtualDelegateMapping; import org.eclipse.ocl.common.internal.options.CommonOptions; import org.eclipse.ocl.pivot.Element; import org.eclipse.ocl.pivot.internal.utilities.GlobalEnvironmentFactory; import org.eclipse.ocl.pivot.utilities.ClassUtil; import org.eclipse.ocl.pivot.utilities.EnvironmentFactory; import org.eclipse.ocl.pivot.utilities.LabelUtil; import org.eclipse.ocl.pivot.utilities.MetamodelManager; import org.eclipse.ocl.pivot.utilities.OCL; import org.eclipse.ocl.pivot.utilities.ParserException; import org.eclipse.ocl.pivot.utilities.PivotConstants; /** * An implementation of a delegate domain for an OCL enhanced package. The domain * maintains an OCL facade to be shared by all delegates within the package. */ public class OCLDelegateDomain implements DelegateDomain, GlobalEnvironmentFactory.Listener { public static class FactoryFactory { public static final @NonNull FactoryFactory INSTANCE = new FactoryFactory(); public @NonNull OCLDelegateDomainFactory createDelegateDomainFactory() { return new OCLDelegateDomainFactory(); } public @NonNull OCLInvocationDelegateFactory createInvocationDelegateFactory(@NonNull String oclDelegateURI) { return new OCLInvocationDelegateFactory(oclDelegateURI); } public @NonNull OCLQueryDelegateFactory createQueryDelegateFactory(@NonNull String oclDelegateURI) { return new OCLQueryDelegateFactory(oclDelegateURI); } public @NonNull OCLSettingDelegateFactory createSettingDelegateFactory(@NonNull String oclDelegateURI) { return new OCLSettingDelegateFactory(oclDelegateURI); } public @NonNull OCLValidationDelegateFactory createValidationDelegateFactory(@NonNull String oclDelegateURI) { return new OCLValidationDelegateFactory(oclDelegateURI); } } protected static class PivotOnlyRegistry extends ValidationDelegateRegistryImpl { private static final long serialVersionUID = 1L; public static final @NonNull PivotOnlyRegistry INSTANCE = new PivotOnlyRegistry(); @Override public ValidationDelegate getValidationDelegate(String uri) { return OCLValidationDelegateFactory.Global.INSTANCE; } } protected static class PivotOnlyVirtualDelegateMapping extends VirtualDelegateMapping { public static final @NonNull PivotOnlyVirtualDelegateMapping INSTANCE = new PivotOnlyVirtualDelegateMapping(); protected PivotOnlyVirtualDelegateMapping() { super("x", "y", "z"); } @Override public @Nullable String getDefaultValue() { return PivotConstants.OCL_DELEGATE_URI_PIVOT; } @Override public @Nullable String getPreferredValue() { return PivotConstants.OCL_DELEGATE_URI_PIVOT; } } // FIXME workaround BUG 485093 giving a false non-null analysis @SuppressWarnings("null") private static @NonNull DelegateResourceSetAdapter getDelegateResourceSetAdapter(@NonNull ResourceSet resourceSet) { return DelegateResourceSetAdapter.getAdapter(resourceSet); } /** * @since 1.1 */ // FIXME workaround BUG 485093 giving a false non-null analysis public static <T> T getDelegateResourceSetRegistry(EModelElement modelElement, @NonNull Class<@NonNull T> registryClass, T defaultRegistry) { Resource resource = modelElement.eResource(); if (resource == null) { return defaultRegistry; } ResourceSet resourceSet = resource.getResourceSet(); if (resourceSet == null) { return defaultRegistry; } DelegateResourceSetAdapter adapter = getDelegateResourceSetAdapter(resourceSet); @Nullable T registry = getDelegateResourceSetAdapterRegistry(adapter, registryClass); return registry != null ? registry : defaultRegistry; } // FIXME workaround BUG 485093 giving a false non-null analysis private static <T> @Nullable T getDelegateResourceSetAdapterRegistry(@NonNull DelegateResourceSetAdapter adapter, @NonNull Class<T> registryClass) { return adapter.getRegistry(registryClass); } /** * Initialize the resourceSet registries, if non-null, or the global registries, if null, * to support usage of the Pivot OCL Delegate Evaluator for the Pivot OCL Delegate URI. */ public static void initialize(@Nullable ResourceSet resourceSet) { initialize(resourceSet, PivotConstants.OCL_DELEGATE_URI_PIVOT); } /** * Initialize the resourceSet registries, if non-null, or the global registries, if null, * to support usage of the Pivot OCL Delegate Evaluator for the oclDelegateURI. */ public static void initialize(@Nullable ResourceSet resourceSet, @NonNull String oclDelegateURI) { lazyInitializeGlobals(oclDelegateURI, true); if (resourceSet != null) { lazyInitializeLocals(resourceSet, oclDelegateURI, true, null); } } public static void initializePivotOnlyDiagnosticianContext(@NonNull Map<Object, Object> context) { context.put(org.eclipse.emf.ecore.EValidator.ValidationDelegate.Registry.class, PivotOnlyRegistry.INSTANCE); context.put(EValidator.SubstitutionLabelProvider.class, LabelUtil.SUBSTITUTION_LABEL_PROVIDER); } public static void initializePivotOnlyDiagnosticianResourceSet(@NonNull ResourceSet resourceSet) { DelegateResourceSetAdapter adapter = getDelegateResourceSetAdapter(resourceSet); putDelegateResourceSetRegistry(adapter, org.eclipse.ocl.pivot.internal.delegate.ValidationDelegate.Registry.class, PivotOnlyRegistry.INSTANCE); putDelegateResourceSetRegistry(adapter, VirtualDelegateMapping.class, PivotOnlyVirtualDelegateMapping.INSTANCE); } /** * Initialize the local resourceSet delegate registries to support the oclDelegateURI. * A non-null delegateFactoryFactory may be specified for test purposes to intercept factory creation. */ public static void lazyInitializeLocals(@NonNull ResourceSet resourceSet, @NonNull String oclDelegateURI, boolean forceInitialization, @Nullable FactoryFactory delegateFactoryFactory) { if (delegateFactoryFactory == null) { delegateFactoryFactory = FactoryFactory.INSTANCE; } FactoryFactory delegateFactoryFactory2 = ClassUtil.nonNullState(delegateFactoryFactory); // Try to avoid spurious build failure // Install a DelegateResourceSetAdapter to supervise local registries and resource post-loading @SuppressWarnings("null")@NonNull DelegateResourceSetAdapter adapter = DelegateResourceSetAdapter.getAdapter(resourceSet); VirtualDelegateMapping delegationMode = CommonOptions.DEFAULT_DELEGATION_MODE; if (forceInitialization || (getDelegateResourceSetAdapterRegistry(adapter, VirtualDelegateMapping.class) == null)) { putDelegateResourceSetRegistry(adapter, VirtualDelegateMapping.class, new VirtualDelegateMapping(delegationMode.getPluginId(), delegationMode.getKey(), delegationMode.getPreferredValue())); } // Install a local DelegateDomain.Factory DelegateDomain.Factory.Registry.Impl delegateDomainFactory = new DelegateDomain.Factory.Registry.Impl(); if (forceInitialization || !delegateDomainFactory.containsKey(oclDelegateURI)) { delegateDomainFactory.put(oclDelegateURI, delegateFactoryFactory2.createDelegateDomainFactory()); } if (forceInitialization || (getDelegateResourceSetAdapterRegistry(adapter, DelegateDomain.Factory.Registry.class) == null)) { putDelegateResourceSetRegistry(adapter, DelegateDomain.Factory.Registry.class, delegateDomainFactory); } // Install a local ValidationDelegate.Factory ValidationDelegate.Factory.Registry validationDelegateFactoryRegistry = new ValidationDelegate.Factory.Registry.Impl(); if (forceInitialization || !validationDelegateFactoryRegistry.containsKey(oclDelegateURI)) { validationDelegateFactoryRegistry.put(oclDelegateURI, delegateFactoryFactory2.createValidationDelegateFactory(oclDelegateURI)); } if (forceInitialization || (getDelegateResourceSetAdapterRegistry(adapter, ValidationDelegate.Factory.Registry.class) == null)) { putDelegateResourceSetRegistry(adapter, ValidationDelegate.Factory.Registry.class, validationDelegateFactoryRegistry); } // Install a local SettingDelegate.Factory EStructuralFeature.Internal.SettingDelegate.Factory.Registry settingDelegateFactoryRegistry = new EStructuralFeature.Internal.SettingDelegate.Factory.Registry.Impl(); if (forceInitialization || !settingDelegateFactoryRegistry.containsKey(oclDelegateURI)) { settingDelegateFactoryRegistry.put(oclDelegateURI, delegateFactoryFactory2.createSettingDelegateFactory(oclDelegateURI)); } if (forceInitialization || (getDelegateResourceSetAdapterRegistry(adapter, EStructuralFeature.Internal.SettingDelegate.Factory.Registry.class) == null)) { putDelegateResourceSetRegistry(adapter, EStructuralFeature.Internal.SettingDelegate.Factory.Registry.class, settingDelegateFactoryRegistry); } // Install a local InvocationDelegate.Factory EOperation.Internal.InvocationDelegate.Factory.Registry invocationDelegateFactoryRegistry = new EOperation.Internal.InvocationDelegate.Factory.Registry.Impl(); if (forceInitialization || !invocationDelegateFactoryRegistry.containsKey(oclDelegateURI)) { invocationDelegateFactoryRegistry.put(oclDelegateURI, delegateFactoryFactory2.createInvocationDelegateFactory(oclDelegateURI)); } if (forceInitialization || (getDelegateResourceSetAdapterRegistry(adapter, EOperation.Internal.InvocationDelegate.Factory.Registry.class) == null)) { putDelegateResourceSetRegistry(adapter, EOperation.Internal.InvocationDelegate.Factory.Registry.class, invocationDelegateFactoryRegistry); } // Install a local QueryDelegate.Factory QueryDelegate.Factory.Registry queryDelegateFactoryRegistry = new QueryDelegate.Factory.Registry.Impl(); if (forceInitialization || !queryDelegateFactoryRegistry.containsKey(oclDelegateURI)) { queryDelegateFactoryRegistry.put(oclDelegateURI, delegateFactoryFactory2.createQueryDelegateFactory(oclDelegateURI)); } if (forceInitialization || (getDelegateResourceSetAdapterRegistry(adapter, QueryDelegate.Factory.Registry.class) == null)) { putDelegateResourceSetRegistry(adapter, QueryDelegate.Factory.Registry.class, queryDelegateFactoryRegistry); } } /** * Initialize any currently uninitialized global delegate registries to support the oclDelegateURI. */ public static void lazyInitializeGlobals(@NonNull String oclDelegateURI, boolean forceInitialization) { if (!EMFPlugin.IS_ECLIPSE_RUNNING) { // Install the 'plugin' registrations EOperation.Internal.InvocationDelegate.Factory.Registry invocationRegistry = EOperation.Internal.InvocationDelegate.Factory.Registry.INSTANCE; if (forceInitialization || !invocationRegistry.containsKey(oclDelegateURI)) { invocationRegistry.put(oclDelegateURI, new OCLInvocationDelegateFactory.Global()); } EStructuralFeature.Internal.SettingDelegate.Factory.Registry settingRegistry = EStructuralFeature.Internal.SettingDelegate.Factory.Registry.INSTANCE; if (forceInitialization || !settingRegistry.containsKey(oclDelegateURI)) { settingRegistry.put(oclDelegateURI, new OCLSettingDelegateFactory.Global()); } EValidator.ValidationDelegate.Registry validationRegistry = EValidator.ValidationDelegate.Registry.INSTANCE; if (forceInitialization || !validationRegistry.containsKey(oclDelegateURI)) { validationRegistry.put(oclDelegateURI, new OCLValidationDelegateFactory.Global()); } QueryDelegate.Factory.Registry queryRegistry = QueryDelegate.Factory.Registry.INSTANCE; if (forceInitialization || !queryRegistry.containsKey(oclDelegateURI)) { queryRegistry.put(oclDelegateURI, new OCLQueryDelegateFactory.Global()); } } } // FIXME workaround BUG 485093 giving a false non-null analysis private static @Nullable <T> T putDelegateResourceSetRegistry(@NonNull DelegateResourceSetAdapter adapter, @NonNull Class<T> registryClass, @NonNull T newRegistry) { return adapter.putRegistry(registryClass, newRegistry); } protected final @NonNull String uri; protected final @NonNull EPackage ePackage; protected OCL ocl = null; // Lazily initialized and re-initialized // FIXME Introduce a lightweight function (? a lambda function) to avoid the need for a CompleteEnvironment for queries // private Map<CompletePackage, org.eclipse.ocl.pivot.Package> queryPackages = null; // private Map<CompleteType, org.eclipse.ocl.pivot.Class> queryTypes = null; /** * Initializes me with my delegate URI and package. * * @param delegateURI * the delegate namespace I handle * @param ePackage * the package that I handle * * @throws ParserException * if the operation's OCL body expression is invalid */ public OCLDelegateDomain(@NonNull String delegateURI, @NonNull EPackage ePackage) { this.uri = delegateURI; this.ePackage = ePackage; } @Override public void environmentFactoryDisposed(@NonNull EnvironmentFactory environmentFactory) { reset(); } /* private @NonNull EnvironmentFactory getEnvironmentFactory() { Resource res = ePackage.eResource(); EnvironmentFactory envFactory = null; if (res != null) { MetamodelManager metamodelManager = null; ResourceSet resourceSet = res.getResourceSet(); if (resourceSet != null) { EnvironmentFactoryResourceSetAdapter rsAdapter = EnvironmentFactoryResourceSetAdapter.findAdapter(resourceSet); if (rsAdapter != null) { metamodelManager = rsAdapter.getMetamodelManager(); } // it's a dynamic package. Use the local package registry // EPackage.Registry packageRegistry = resourceSet.getPackageRegistry(); if (metamodelManager != null) { envFactory = metamodelManager.getEnvironmentFactory(); } else { envFactory = OCL.Internal.createEnvironmentFactory(null); } DelegateResourceAdapter.getAdapter(res); } } if (envFactory == null) { // the shared instance uses the static package registry envFactory = OCL.Internal.getGlobalEnvironmentFactory(); } return envFactory; } */ public final @NonNull MetamodelManager getMetamodelManager() { return getOCL().getMetamodelManager(); } public @NonNull OCL getOCL() { OCL ocl2 = ocl; if (ocl2 == null) { // Delegates are an application-independent extension of EMF // so we must use the neutral/global context see Bug 338501 // EnvironmentFactory environmentFactory = getEnvironmentFactory(); GlobalEnvironmentFactory environmentFactory = GlobalEnvironmentFactory.getInstance(); ocl2 = ocl = environmentFactory.createOCL(); environmentFactory.addListener(this); } return ocl2; } public <T extends Element> @Nullable T getPivot(@NonNull Class<T> requiredClass, @NonNull EObject eObject) { MetamodelManager metamodelManager = getOCL().getMetamodelManager(); try { return metamodelManager.getASOf(requiredClass, eObject); } catch (ParserException e) { return null; } } @Override public final @NonNull String getURI() { return uri; } @Override public synchronized void reset() { OCL ocl2 = ocl; if (ocl2 != null) { ocl = null; for (EClassifier eClassifier : ePackage.getEClassifiers()) { List<Adapter> eClassifierAdapters = eClassifier.eAdapters(); for (Adapter adapter : eClassifierAdapters) { if (adapter instanceof DelegateEClassifierAdapter) { eClassifierAdapters.remove(adapter); break; } } if (eClassifier instanceof EClass) { EClass eClass = (EClass) eClassifier; for (EOperation eOperation : eClass.getEOperations()) { ((EOperation.Internal) eOperation).setInvocationDelegate(null); } for (EStructuralFeature eStructuralFeature : eClass.getEStructuralFeatures()) { ((EStructuralFeature.Internal) eStructuralFeature).setSettingDelegate(null); } } } GlobalEnvironmentFactory environmentFactory = (GlobalEnvironmentFactory) ocl2.getEnvironmentFactory(); environmentFactory.removeListener(this); ocl2.dispose(); } } @Override public String toString() { return ePackage.getName() + " : " + getURI(); //$NON-NLS-1$ } }