/******************************************************************************* * Copyright (c) 2006, 2009 IBM Corporation 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: * IBM - Initial API and implementation *******************************************************************************/ package org.eclipse.ocl.internal; import java.util.Map; import java.util.Set; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IConfigurationElement; import org.eclipse.core.runtime.IExtension; import org.eclipse.core.runtime.IExtensionDelta; import org.eclipse.core.runtime.IExtensionRegistry; import org.eclipse.core.runtime.IRegistryChangeEvent; import org.eclipse.core.runtime.IRegistryChangeListener; import org.eclipse.core.runtime.Platform; import org.eclipse.emf.common.util.BasicEList; import org.eclipse.emf.common.util.Diagnostic; import org.eclipse.emf.common.util.EList; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EPackage; import org.eclipse.ocl.Environment; import org.eclipse.ocl.EnvironmentFactory; import org.eclipse.ocl.Environment.Registry; import org.eclipse.ocl.expressions.OCLExpression; import org.eclipse.ocl.internal.l10n.OCLMessages; import org.eclipse.ocl.utilities.TypedElement; import org.eclipse.ocl.utilities.UMLReflection; /** * Implementation of the environment registry. * * @author cdamus */ public class EnvironmentRegistryImpl implements Registry { private final EList<Object> environments = new BasicEList<Object>(); private static final String PT_ENVIRONMENTS = "environments"; //$NON-NLS-1$ private static final String E_ENVIRONMENT_FACTORY = "environmentFactory"; //$NON-NLS-1$ private static final String A_CLASS = "class"; //$NON-NLS-1$ private static final String E_PACKAGE = "package"; //$NON-NLS-1$ private static final String A_NS_URI = "nsURI"; //$NON-NLS-1$ public <PK, C, O, P, EL, PM, S, COA, SSA, CT, CLS, E> Environment<PK, C, O, P, EL, PM, S, COA, SSA, CT, CLS, E> getEnvironmentFor( OCLExpression<C> expression) { return getEnvironmentFor(expression.getType()); } @SuppressWarnings("unchecked") public <PK, C, O, P, EL, PM, S, COA, SSA, CT, CLS, E> Environment<PK, C, O, P, EL, PM, S, COA, SSA, CT, CLS, E> getEnvironmentFor( Object abstractSyntaxElement) { if (abstractSyntaxElement instanceof TypedElement<?>) { return getEnvironmentFor(((TypedElement<?>) abstractSyntaxElement).getType()); } for (int i = 0; i < environments.size(); i++) { Object next = environments.get(i); if (next instanceof EnvironmentDescriptor) { EnvironmentDescriptor descriptor = (EnvironmentDescriptor) next; if (descriptor.matches(abstractSyntaxElement)) { // instantiate the descriptor now next = descriptor.instantiate(); environments.set(i, next); } } if (next instanceof Environment<?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?>) { Environment<?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?> env = (Environment<?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?>) next; UMLReflection<?, ?, ?, ?, ?, ?, ?, ?, ?, ?> uml = env.getUMLReflection(); if (uml.isClassifier(abstractSyntaxElement) || uml.isOperation(abstractSyntaxElement) || uml.isProperty(abstractSyntaxElement)) { return (Environment<PK, C, O, P, EL, PM, S, COA, SSA, CT, CLS, E>) next; } } } return null; } public void registerEnvironment( Environment<?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?> environment) { if (!environments.contains(environment)) { environments.add(environment); } } public void deregisterEnvironment( Environment<?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?> environment) { environments.remove(environment); } /** * Utility class that reads the Eclipse extension registry to find registered * OCL environments. * * @author cdamus * * @since 1.1 */ class RegistryReader implements IRegistryChangeListener { private final String namespace; private IExtensionRegistry extensionRegistry; private final Map<String, EnvironmentDescriptor> descriptors = new java.util.HashMap<String, EnvironmentDescriptor>(); RegistryReader(OCLPlugin plugin) { // FIXME namespace = "org.eclipse.ocl"; //$NON-NLS-1$ //plugin.getSymbolicName(); } void readRegistry() { if (extensionRegistry == null) { extensionRegistry = Platform.getExtensionRegistry(); readRegistryImpl(); } } private void readRegistryImpl() { extensionRegistry.addRegistryChangeListener(this, namespace); IExtension[] extensions = extensionRegistry.getExtensionPoint( namespace, PT_ENVIRONMENTS).getExtensions(); for (IExtension extension : extensions) { read(extension); } } private void read(IExtension extension) { IConfigurationElement[] elements = extension.getConfigurationElements(); for (IConfigurationElement element : elements) { if (E_ENVIRONMENT_FACTORY.equals(element.getName())) { readEnvironmentFactory(element); } else { OCLPlugin.log(Diagnostic.ERROR, 1, OCLMessages.bind( OCLMessages.EnvRegistry_unknownElement_ERROR_, getExtensionID(extension), element.getName()), null); } } } private void readEnvironmentFactory(final IConfigurationElement element) { String className = element.getAttribute(A_CLASS); if (className != null) { EnvironmentDescriptor descriptor = new EnvironmentDescriptor() { @Override EnvironmentFactory<?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?> createFactory() { try { return (EnvironmentFactory<?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?>) element.createExecutableExtension(A_CLASS); } catch (CoreException e) { OCLPlugin.getInstance().log(e); return null; } }}; descriptors.put(className, descriptor); environments.add(descriptor); for (IConfigurationElement pkg : element.getChildren(E_PACKAGE)) { readPackage(descriptor, pkg); } } else { OCLPlugin.log(Diagnostic.ERROR, 1, OCLMessages.bind( OCLMessages.EnvRegistry_missingClass_ERROR_, getExtensionID(element)), null); } } private void readPackage(EnvironmentDescriptor descriptor, IConfigurationElement element) { String nsURI = element.getAttribute(A_NS_URI); if (nsURI != null) { descriptor.addPackageURI(nsURI); } else { OCLPlugin.log(Diagnostic.ERROR, 1, OCLMessages.bind( OCLMessages.EnvRegistry_missingNsURI_ERROR_, getExtensionID(element)), null); } } private void remove(IExtension extension) { IConfigurationElement[] elements = extension.getConfigurationElements(); for (IConfigurationElement element : elements) { if (E_ENVIRONMENT_FACTORY.equals(element.getName())) { removeEnvironmentFactory(element); } } } private void removeEnvironmentFactory(IConfigurationElement element) { String className = element.getAttribute(A_CLASS); if (className != null) { EnvironmentDescriptor descriptor = descriptors.get(className); if (descriptor != null) { descriptor.dispose(); } } } public void registryChanged(IRegistryChangeEvent event) { for (IExtensionDelta delta : event.getExtensionDeltas( namespace, PT_ENVIRONMENTS)) { switch (delta.getKind()) { case IExtensionDelta.ADDED: read(delta.getExtension()); break; case IExtensionDelta.REMOVED: remove(delta.getExtension()); break; } } } } /** * Descriptor for a lazily-instantiated OCL environment, loaded from the * Eclipse extension registry. * * @author cdamus * * @since 1.1 */ private abstract class EnvironmentDescriptor { private final Set<String> packageURIs = new java.util.HashSet<String>(); private Environment<?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?> env; EnvironmentDescriptor() { super(); } void addPackageURI(String packageURI) { packageURIs.add(packageURI); } boolean matches(Object object) { boolean result = object instanceof EObject; if (result) { EPackage epackage = ((EObject) object).eClass().getEPackage(); result = (epackage != null) && packageURIs.contains(epackage.getNsURI()); } return result; } Environment<?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?> instantiate() { if (env == null) { EnvironmentFactory<?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?> factory = createFactory(); env = factory.createEnvironment(); } return env; } void dispose() { if (env != null) { // I have been instantiated, so remove my environment from // the list environments.remove(env); } // make sure that I'm not in the environments list, either environments.remove(this); } abstract EnvironmentFactory<?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?> createFactory(); } /** * Obtains the ID of the extension defining the specified element, * or the defining plug-in ID if the extension has none. * * @param element an element * @return an identifier for the extension */ private String getExtensionID(IConfigurationElement element) { return getExtensionID(element.getDeclaringExtension()); } /** * Obtains the ID of the specified extension, * or the defining plug-in ID if the extension has none. * * @param extension an extension * @return an identifier for the extension */ private String getExtensionID(IExtension extension) { String result = extension.getUniqueIdentifier(); if (result == null) { result = extension.getNamespaceIdentifier(); } return result; } }