blob: f80f24f1ff0e38c5f0a4747a8bbc2d5c7af620d6 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2006, 2018 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v20.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;
}
}