blob: 2a6b9a1a00804bbe568d900dd203d00397e7d734 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2010, 2021 Willink Transformations 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:
* E.D.Willink - Initial API and implementation
*******************************************************************************/
package org.eclipse.ocl.pivot.utilities;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;
import org.eclipse.core.resources.IProject;
import org.eclipse.emf.common.EMFPlugin;
import org.eclipse.emf.common.notify.Adapter;
import org.eclipse.emf.common.notify.Notifier;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EOperation;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
import org.eclipse.emf.ecore.xmi.impl.EMOFResourceFactoryImpl;
import org.eclipse.emf.ecore.xmi.impl.EcoreResourceFactoryImpl;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.ocl.pivot.CollectionType;
import org.eclipse.ocl.pivot.CompleteClass;
import org.eclipse.ocl.pivot.Constraint;
import org.eclipse.ocl.pivot.Element;
import org.eclipse.ocl.pivot.ExpressionInOCL;
import org.eclipse.ocl.pivot.Iteration;
import org.eclipse.ocl.pivot.LanguageExpression;
import org.eclipse.ocl.pivot.LoopExp;
import org.eclipse.ocl.pivot.NamedElement;
import org.eclipse.ocl.pivot.OCLExpression;
import org.eclipse.ocl.pivot.Operation;
import org.eclipse.ocl.pivot.OperationCallExp;
import org.eclipse.ocl.pivot.OppositePropertyCallExp;
import org.eclipse.ocl.pivot.PivotFactory;
import org.eclipse.ocl.pivot.PivotPackage;
import org.eclipse.ocl.pivot.PrimitiveType;
import org.eclipse.ocl.pivot.Property;
import org.eclipse.ocl.pivot.PropertyCallExp;
import org.eclipse.ocl.pivot.Slot;
import org.eclipse.ocl.pivot.Type;
import org.eclipse.ocl.pivot.Variable;
import org.eclipse.ocl.pivot.VoidType;
import org.eclipse.ocl.pivot.evaluation.EvaluationEnvironment;
import org.eclipse.ocl.pivot.evaluation.EvaluationVisitor;
import org.eclipse.ocl.pivot.evaluation.Executor;
import org.eclipse.ocl.pivot.evaluation.ModelManager;
import org.eclipse.ocl.pivot.ids.IdManager;
import org.eclipse.ocl.pivot.ids.IdResolver;
import org.eclipse.ocl.pivot.ids.OperationId;
import org.eclipse.ocl.pivot.internal.complete.CompleteEnvironmentInternal;
import org.eclipse.ocl.pivot.internal.complete.CompleteModelInternal;
import org.eclipse.ocl.pivot.internal.complete.StandardLibraryInternal;
import org.eclipse.ocl.pivot.internal.context.ClassContext;
import org.eclipse.ocl.pivot.internal.context.ModelContext;
import org.eclipse.ocl.pivot.internal.context.OperationContext;
import org.eclipse.ocl.pivot.internal.context.PropertyContext;
import org.eclipse.ocl.pivot.internal.ecore.EcoreASResourceFactory;
import org.eclipse.ocl.pivot.internal.evaluation.AbstractCustomizable;
import org.eclipse.ocl.pivot.internal.evaluation.BasicOCLExecutor;
import org.eclipse.ocl.pivot.internal.evaluation.ExecutorInternal;
import org.eclipse.ocl.pivot.internal.library.ImplementationManager;
import org.eclipse.ocl.pivot.internal.library.executor.LazyEcoreModelManager;
import org.eclipse.ocl.pivot.internal.manager.FlowAnalysis;
import org.eclipse.ocl.pivot.internal.manager.PivotMetamodelManager;
import org.eclipse.ocl.pivot.internal.manager.TemplateParameterSubstitutionVisitor;
import org.eclipse.ocl.pivot.internal.messages.PivotMessagesInternal;
import org.eclipse.ocl.pivot.internal.resource.ASResourceFactory;
import org.eclipse.ocl.pivot.internal.resource.ASResourceFactoryRegistry;
import org.eclipse.ocl.pivot.internal.resource.ContentTypeFirstResourceFactoryRegistry;
import org.eclipse.ocl.pivot.internal.resource.EnvironmentFactoryAdapter;
import org.eclipse.ocl.pivot.internal.resource.ICSI2ASMapping;
import org.eclipse.ocl.pivot.internal.resource.StandaloneProjectMap;
import org.eclipse.ocl.pivot.internal.utilities.EnvironmentFactoryInternal;
import org.eclipse.ocl.pivot.internal.utilities.External2AS;
import org.eclipse.ocl.pivot.internal.utilities.GlobalEnvironmentFactory;
import org.eclipse.ocl.pivot.internal.utilities.OCLInternal;
import org.eclipse.ocl.pivot.internal.utilities.PivotUtilInternal;
import org.eclipse.ocl.pivot.internal.utilities.Technology;
import org.eclipse.ocl.pivot.messages.StatusCodes;
import org.eclipse.ocl.pivot.options.PivotValidationOptions;
import org.eclipse.ocl.pivot.resource.ProjectManager;
import org.eclipse.ocl.pivot.util.PivotPlugin;
import org.eclipse.ocl.pivot.values.ObjectValue;
/**
* Partial implementation of the {@link EnvironmentFactoryInternal} interface, useful
* for subclassing to define the Pivot binding for a metamodel.
*/
public abstract class AbstractEnvironmentFactory extends AbstractCustomizable implements EnvironmentFactoryInternal.EnvironmentFactoryInternalExtension
{
/**
* @since 1.4
*/
public static final @NonNull TracingOption ENVIRONMENT_FACTORY_ATTACH = new TracingOption(PivotPlugin.PLUGIN_ID, "environmentFactory/attach");
private boolean traceEvaluation;
protected final @NonNull ProjectManager projectManager;
protected final @NonNull ResourceSet externalResourceSet;
private final @NonNull ResourceSet asResourceSet;
protected final boolean externalResourceSetWasNull;
private /*@LazyNonNull*/ PivotMetamodelManager metamodelManager = null;
private final @NonNull CompleteEnvironmentInternal completeEnvironment;
private final @NonNull StandardLibraryInternal standardLibrary;
private @Nullable ICSI2ASMapping csi2asMapping;
/**
* The known packages.
*/
private final @NonNull CompleteModelInternal completeModel;
private /*@LazyNonNull*/ IdResolver idResolver;
/**
* Count of the number of OCL instances that are using the EnvironmentFactory. auto-disposes on count down to zero.
* -ve once disposed.
*/
private int attachCount = 0;
/**
* Debug lust of the System.identityHashCode of each active owners of an attach
*
* System.identityHashCode avoids problmes with finalized attachOwners.
*/
private List<@NonNull Integer> attachOwners = new ArrayList<>();
private @NonNull Technology technology = ASResourceFactoryRegistry.INSTANCE.getTechnology();
/**
* Configuration of validation preferences.
*/
private /*LazyNonNull*/ Map<Object, StatusCodes.Severity> validationKey2severity = null;
/**
* Leak debugging aid. Set non-null to diagnose EnvironmentFactory construction and finalization.
*
* @since 1.14
*/
public static WeakHashMap<@NonNull AbstractEnvironmentFactory, @Nullable Object> liveEnvironmentFactories = null;
/**
* @since 1.7
*/
public static int CONSTRUCTION_COUNT = 0;
@Deprecated /* @deprecated supply null asResourceSet argument */
protected AbstractEnvironmentFactory(@NonNull ProjectManager projectManager, @Nullable ResourceSet externalResourceSet) {
this(projectManager, externalResourceSet, null);
}
/**
* @since 1.10
*/
protected AbstractEnvironmentFactory(@NonNull ProjectManager projectManager, @Nullable ResourceSet externalResourceSet, @Nullable ResourceSet asResourceSet) {
CONSTRUCTION_COUNT++;
if (liveEnvironmentFactories != null) {
liveEnvironmentFactories.put(this, null);
PivotUtilInternal.debugPrintln("Create " + NameUtil.debugSimpleName(this)
+ " " + NameUtil.debugSimpleName(externalResourceSet) + " " + NameUtil.debugSimpleName(asResourceSet));
}
if (!EMFPlugin.IS_ECLIPSE_RUNNING) { // This is the unique start point for OCL so
PivotStandaloneSetup.doSetup(); // do the non-UI initialization (guarded in doSetup())
}
this.projectManager = projectManager;
if (asResourceSet == null) {
asResourceSet = createASResourceSet();
}
this.asResourceSet = asResourceSet;
if (externalResourceSet != null) {
this.externalResourceSetWasNull = false;
this.externalResourceSet = externalResourceSet;
ASResourceFactoryRegistry.INSTANCE.configureResourceSets(null, asResourceSet);
}
else {
this.externalResourceSetWasNull = true;
this.externalResourceSet = externalResourceSet = new ResourceSetImpl();
projectManager.initializeResourceSet(externalResourceSet);
Map<String, Object> extensionToFactoryMap = externalResourceSet.getResourceFactoryRegistry().getExtensionToFactoryMap();
extensionToFactoryMap.put("ecore", new EcoreResourceFactoryImpl()); //$NON-NLS-1$
extensionToFactoryMap.put("emof", new EMOFResourceFactoryImpl()); //$NON-NLS-1$
ASResourceFactoryRegistry.INSTANCE.configureResourceSets(asResourceSet, externalResourceSet);
}
if (ENVIRONMENT_FACTORY_ATTACH.isActive()) {
ENVIRONMENT_FACTORY_ATTACH.println("[" + Thread.currentThread().getName() + "] Create(" + attachCount + ") " + NameUtil.debugSimpleName(this) + " => " + NameUtil.debugSimpleName(externalResourceSet));
}
adapt(externalResourceSet);
this.completeEnvironment = createCompleteEnvironment();
this.standardLibrary = completeEnvironment.getOwnedStandardLibrary();
this.completeModel = completeEnvironment.getOwnedCompleteModel();
PivotUtil.initializeLoadOptionsToSupportSelfReferences(getResourceSet());
ThreadLocalExecutor.attachEnvironmentFactory(this);
}
@Override
public @NonNull EnvironmentFactoryAdapter adapt(@NonNull Notifier notifier) {
List<Adapter> eAdapters = ClassUtil.nonNullEMF(notifier.eAdapters());
EnvironmentFactoryAdapter adapter = ClassUtil.getAdapter(EnvironmentFactoryAdapter.class, eAdapters);
if (adapter != null) {
if (adapter.getEnvironmentFactory() != this) {
adapter = null;
}
}
if (adapter == null) {
adapter = new EnvironmentFactoryAdapter(this, notifier);
eAdapters.add(adapter);
}
return adapter;
}
@Override
public void addExternal2AS(@NonNull External2AS external2as) {
Resource resource = external2as.getResource();
if ((resource != null) && ClassUtil.isRegistered(resource)) {
ResourceSet externalResourceSet2 = getResourceSet();
projectManager.useGeneratedResource(resource, externalResourceSet2);
}
getMetamodelManager().addExternal2AS(external2as);
}
/**
* Add all resources in ResourceSet to the externalResourceSet.
*/
@Override
public void addExternalResources(@NonNull ResourceSet resourceSet) {
ResourceSet externalResourceSet = getResourceSet();
if (externalResourceSet instanceof ResourceSetImpl) {
Map<URI, Resource> uriResourceMap = ((ResourceSetImpl)externalResourceSet).getURIResourceMap();
if (uriResourceMap != null) {
for (Resource eResource : resourceSet.getResources()) {
URI uri = eResource.getURI();
if (uri != null) {
uriResourceMap.put(uri, eResource);
}
}
if (resourceSet instanceof ResourceSetImpl) {
Map<URI, Resource> contextResourceMap = ((ResourceSetImpl)resourceSet).getURIResourceMap();
if ((contextResourceMap != null) && (contextResourceMap != uriResourceMap)) {
for (URI uri : contextResourceMap.keySet()) {
uriResourceMap.put(uri, contextResourceMap.get(uri));
}
}
}
}
}
}
@Override
public void analyzeExpressions(@NonNull EObject eRootObject,
@NonNull Set<@NonNull CompleteClass> allInstancesCompleteClasses, @NonNull Set<@NonNull Property> implicitOppositeProperties) {
Type oclElementType = standardLibrary.getOclElementType();
OperationId allInstancesOperationId = oclElementType.getTypeId().getOperationId(0, "allInstances", IdManager.getParametersId());
for (EObject eObject : new TreeIterable(eRootObject, true)) {
if (eObject instanceof OppositePropertyCallExp) {
OppositePropertyCallExp oppositePropertyCallExp = (OppositePropertyCallExp)eObject;
Property navigableProperty = oppositePropertyCallExp.getReferredProperty();
if ((navigableProperty != null) && !navigableProperty.isIsComposite()) {
implicitOppositeProperties.add(navigableProperty);
}
}
else if (eObject instanceof OperationCallExp) {
OperationCallExp operationCallExp = (OperationCallExp)eObject;
Operation referredOperation = operationCallExp.getReferredOperation();
if (referredOperation != null) {
OperationId operationId = referredOperation.getOperationId();
if (operationId == allInstancesOperationId) {
OCLExpression source = operationCallExp.getOwnedSource();
if (source != null) {
Type asType = source.getTypeValue();
if (asType == null) {
asType = source.getType();
}
if (asType instanceof org.eclipse.ocl.pivot.Class) {
assert !(asType instanceof PrimitiveType);
assert !(asType instanceof CollectionType);
CompleteClass completeClass = completeModel.getCompleteClass(asType);
allInstancesCompleteClasses.add(completeClass);
}
}
}
}
}
}
}
@Override
public synchronized void attach(@NonNull Object attachOwner) {
EnvironmentFactoryInternal environmentFactory = ThreadLocalExecutor.basicGetEnvironmentFactory();
assert (environmentFactory == null) || (environmentFactory == this) : "[" + Thread.currentThread().getName() + "] " + NameUtil.debugSimpleName(this) + " should be " + NameUtil.debugSimpleName(environmentFactory);
if (isDisposed()) {
if (ENVIRONMENT_FACTORY_ATTACH.isActive()) {
ENVIRONMENT_FACTORY_ATTACH.println("[" + Thread.currentThread().getName() + "] Attach(" + attachCount + ") " + NameUtil.debugSimpleName(this) + " " + NameUtil.debugSimpleName(attachOwner));
}
throw new IllegalStateException(getClass().getName() + " disposed");
}
attachCount++;
attachOwners.add(System.identityHashCode(attachOwner));
if (ENVIRONMENT_FACTORY_ATTACH.isActive()) {
ENVIRONMENT_FACTORY_ATTACH.println("[" + Thread.currentThread().getName() + "] Attach(" + (attachCount-1) + ":" + attachCount + ") " + NameUtil.debugSimpleName(this) + " " + NameUtil.debugSimpleName(attachOwner));
}
}
protected @Nullable PivotMetamodelManager basicGetMetamodelManager() {
return metamodelManager;
}
@Override
public void configureLoadFirstStrategy() {
configureLoadStrategy(StandaloneProjectMap.LoadFirstStrategy.INSTANCE, StandaloneProjectMap.MapToFirstConflictHandler.INSTANCE);
}
@Override
public void configureLoadStrategy(ProjectManager.@NonNull IResourceLoadStrategy packageLoadStrategy, ProjectManager.@Nullable IConflictHandler conflictHandler) {
ResourceSet externalResourceSet = getResourceSet();
projectManager.configure(externalResourceSet, packageLoadStrategy, conflictHandler);
}
@Override
public @NonNull ResourceSetImpl createASResourceSet() {
ResourceSetImpl asResourceSet = new ResourceSetImpl();
asResourceSet.setResourceFactoryRegistry(new ContentTypeFirstResourceFactoryRegistry(asResourceSet));
// StandaloneProjectMap.initializeURIResourceMap(asResourceSet);
EPackage.Registry packageRegistry = asResourceSet.getPackageRegistry();
// packageRegistry.put(PivotPackage.eNS_URI, PivotPackage.eINSTANCE);
projectManager.initializeResourceSet(asResourceSet);
packageRegistry.put(PivotPackage.eNS_URI, PivotPackage.eINSTANCE);
return asResourceSet;
}
@Override
public @NonNull CompleteEnvironmentInternal createCompleteEnvironment() {
CompleteEnvironmentInternal completeEnvironment = (CompleteEnvironmentInternal)PivotFactory.eINSTANCE.createCompleteEnvironment();
completeEnvironment.init(this);
return completeEnvironment;
}
@Override
public @NonNull EvaluationEnvironment createEvaluationEnvironment(@NonNull NamedElement executableObject, @NonNull ModelManager modelManager) {
Executor executor = ThreadLocalExecutor.basicGetExecutor();
assert executor == null;
executor = createExecutor(modelManager);
// Executor executor = ThreadLocalExecutor.basicGetExecutor();
assert executor != null;
ExecutorInternal interpretedExecutor = executor.basicGetInterpretedExecutor();
assert interpretedExecutor != null;
assert interpretedExecutor.getModelManager() == modelManager;
return interpretedExecutor.initializeEvaluationEnvironment(executableObject);
}
/** @deprecated no longer used */
@Deprecated
@Override
public @NonNull EvaluationEnvironment createEvaluationEnvironment(@NonNull EvaluationEnvironment parent, @NonNull NamedElement executableObject) {
throw new UnsupportedOperationException();
}
@Override
public @NonNull EvaluationVisitor createEvaluationVisitor(@Nullable Object context, @NonNull ExpressionInOCL expression, @Nullable ModelManager modelManager) {
ThreadLocalExecutor.setExecutor(null); // Eliminate obsolete dropping from previous EvaluationVisitor
if (modelManager == null) {
// let the evaluation environment create one
modelManager = createModelManager(context);
}
// can determine a more appropriate context from the context
// variable of the expression, to account for stereotype constraints
// context = HelperUtil.getConstraintContext(rootEnvironment, context, expression);
ExecutorInternal executorInternal = createExecutor(modelManager);
EvaluationEnvironment evaluationEnvironment = executorInternal.initializeEvaluationEnvironment(expression);
Variable contextVariable = expression.getOwnedContext();
if (contextVariable != null) {
IdResolver idResolver = getIdResolver();
Object value = idResolver.boxedValueOf(context);
evaluationEnvironment.add(contextVariable, value);
}
for (Variable parameterVariable : expression.getOwnedParameters()) {
if (parameterVariable != null) {
evaluationEnvironment.add(parameterVariable, null);
}
}
return executorInternal.getEvaluationVisitor();
}
@Override
public @NonNull EvaluationVisitor createEvaluationVisitor(@NonNull EvaluationEnvironment evaluationEnvironment) {
ExecutorInternal executor = ((EvaluationEnvironment.EvaluationEnvironmentExtension)evaluationEnvironment).getExecutor();
return executor.getEvaluationVisitor();
}
/**
* @since 1.1
*/
@Override
public @NonNull ExecutorInternal createExecutor(@NonNull ModelManager modelManager) {
Executor executor = ThreadLocalExecutor.basicGetExecutor();
ExecutorInternal interpretedExecutor = executor != null ? executor.basicGetInterpretedExecutor() : null;
if (executor == null) {
// interpretedExecutor = new BasicOCLExecutor(this, modelManager);
// executor.setInterpretedExecutor(interpretedExecutor);
}
else {
assert executor.getModelManager() == modelManager;
if (executor != interpretedExecutor) {
executor.setInterpretedExecutor(interpretedExecutor);
}
}
if (interpretedExecutor == null) {
interpretedExecutor = new BasicOCLExecutor(this, modelManager);
if (executor == null) {
ThreadLocalExecutor.setExecutor(interpretedExecutor);
}
else {
executor.setInterpretedExecutor(interpretedExecutor);
}
}
/* if (executor != null) {
ExecutorInternal interpretedExecutor = executor.basicGetInterpretedExecutor();
// assert interpretedExecutor == null;
}
BasicOCLExecutor interpretedExecutor = new BasicOCLExecutor(this, modelManager);
if (executor == null) {
ThreadLocalExecutor.setExecutor(interpretedExecutor);
}
else {
executor.setInterpretedExecutor(interpretedExecutor);
} */
return interpretedExecutor;
}
/**
* @since 1.7
*/
@Override
public @NonNull FlowAnalysis createFlowAnalysis(@NonNull OCLExpression contextExpression) {
return new FlowAnalysis(this, contextExpression);
}
@Override
public @NonNull IdResolver createIdResolver() {
return technology.createIdResolver(this);
}
@Override
public @NonNull ImplementationManager createImplementationManager() {
return new ImplementationManager(this);
}
@Override
public @NonNull PivotMetamodelManager createMetamodelManager() {
assert metamodelManager == null;
metamodelManager = new PivotMetamodelManager(this, asResourceSet);
assert metamodelManager != null;
return metamodelManager;
}
protected @NonNull ModelManager createModelManager() {
return ModelManager.NULL;
}
/**
* {@inheritDoc}
*/
@Override
public @NonNull ModelManager createModelManager(@Nullable Object object) {
if (object instanceof ObjectValue) {
object = ((ObjectValue) object).getObject();
}
if (object instanceof EObject) {
return new LazyEcoreModelManager((EObject)object);
}
return ModelManager.NULL;
}
@Override
public @NonNull OCLInternal createOCL() {
return new OCLInternal(this);
}
@Deprecated /* @deprecated not used - use createParserContext(@NonNull Element) */
@Override
public @NonNull ParserContext createParserContext(@Nullable EObject context) throws ParserException {
if (context instanceof Element) {
ParserContext parserContext = createParserContext((Element)context);
if (parserContext != null) {
return parserContext;
}
}
return new ModelContext(this, null);
}
/**
* Return a ParserContext suitable for parsing OCL expressions in the context of a pivot element.
*
* @since 1.4
*/
@Override
public @Nullable ParserContext createParserContext(@NonNull Element element) {
Element pivotElement = element;
if (element instanceof ExpressionInOCL) {
EObject pivotContainer = pivotElement.eContainer();
if (pivotContainer instanceof Operation) { // Operation.bodyExpression
Operation pivotOperation = (Operation) pivotContainer;
return new OperationContext(this, null, pivotOperation, null);
}
if (pivotContainer instanceof Property) {
Property pivotProperty = (Property) pivotContainer;
return new PropertyContext(this, null, pivotProperty);
}
if (pivotContainer instanceof Constraint) { // Operation.pre/postCondition
EObject pivotContainerContainer = pivotContainer.eContainer();
if (pivotContainerContainer instanceof Operation) {
Operation pivotOperation = (Operation) pivotContainerContainer;
String resultName = null;
if (pivotOperation.getOwnedPostconditions().contains(pivotContainer)) {
Type resultType = pivotOperation.getType();
if ((resultType != null) && !(resultType instanceof VoidType)) {
resultName = PivotConstants.RESULT_NAME;
}
}
return new OperationContext(this, null, pivotOperation, resultName);
}
if (pivotContainerContainer instanceof org.eclipse.ocl.pivot.Class) {
org.eclipse.ocl.pivot.Class pivotType = (org.eclipse.ocl.pivot.Class) pivotContainerContainer;
return new ClassContext(this, null, pivotType, null);
}
}
if (pivotContainer instanceof Slot) {
Property asDefiningFeature = ((Slot)pivotContainer).getDefiningProperty();
if (asDefiningFeature != null) {
org.eclipse.ocl.pivot.Class pivotType = asDefiningFeature.getOwningClass();
if (pivotType != null) {
return new ClassContext(this, null, pivotType, null);
}
}
}
}
//
// The JUnit tests are satisfied by the new code above. The following provides legacy support, perhaps satisfying unusual invocations
//
if (pivotElement instanceof Constraint) {
EObject pivotContainer = pivotElement.eContainer();
if (pivotContainer instanceof Operation) {
Operation pivotOperation = (Operation) pivotContainer;
String resultName = null;
if (pivotOperation.getOwnedPostconditions().contains(pivotElement)) {
Type resultType = pivotOperation.getType();
if ((resultType != null) && !(resultType instanceof VoidType)) {
resultName = PivotConstants.RESULT_NAME;
}
}
return new OperationContext(this, null, pivotOperation, resultName);
}
}
if (pivotElement instanceof Property) {
return new PropertyContext(this, null, (Property) pivotElement);
}
else if (pivotElement instanceof Operation) {
return new OperationContext(this, null, (Operation) pivotElement, null);
}
else if (pivotElement instanceof OppositePropertyCallExp) {
Property referredOppositeProperty = ((OppositePropertyCallExp) pivotElement).getReferredProperty();
if (referredOppositeProperty != null) {
Property referredProperty = referredOppositeProperty.getOpposite();
if (referredProperty != null) {
return new PropertyContext(this, null, referredProperty);
}
}
}
else if (pivotElement instanceof PropertyCallExp) {
Property referredProperty = ((PropertyCallExp) pivotElement).getReferredProperty();
if (referredProperty != null) {
return new PropertyContext(this, null, referredProperty);
}
}
else if (pivotElement instanceof OperationCallExp) {
Operation referredOperation = ((OperationCallExp) pivotElement).getReferredOperation();
if (referredOperation != null) {
return new OperationContext(this, null, referredOperation, null);
}
}
else if (pivotElement instanceof LoopExp) {
Iteration referredIteration = ((LoopExp) pivotElement).getReferredIteration();
if (referredIteration != null) {
return new OperationContext(this, null, referredIteration, null);
}
}
// else if (pivotElement instanceof Stereotype) {
// Stereotype pivotStereotype = (Stereotype) pivotElement;
// return new ClassContext(this, null, pivotStereotype);
// }
// else if (pivotElement instanceof org.eclipse.ocl.pivot.Class) {
// org.eclipse.ocl.pivot.Class pivotClass = (org.eclipse.ocl.pivot.Class) pivotElement;
//// Metaclass<?> metaClass = getMetaclass(pivotClass);
// return new ClassContext(this, null, pivotClass);
// }
else { // Class, Stereotype, State
for (EObject eObject = element; eObject != null; eObject = eObject.eContainer()) {
if ((eObject instanceof org.eclipse.ocl.pivot.Class) && (((org.eclipse.ocl.pivot.Class)eObject).getOwningPackage() != null)) { // StateMachines etc do not have Packages
return new ClassContext(this, null, (org.eclipse.ocl.pivot.Class)eObject, null);
}
}
}
return null;
}
/**
* @since 1.1
*/
@Override
public @NonNull TemplateParameterSubstitutionVisitor createTemplateParameterSubstitutionVisitor(
@Nullable Type selfType, @Nullable Type selfTypeValue) {
return new TemplateParameterSubstitutionVisitor(this, selfType, selfTypeValue);
}
protected @NonNull HashMap<Object, StatusCodes.Severity> createValidationKey2severityMap() {
return PivotValidationOptions.createValidationKey2severityMap();
}
@Override
public synchronized void detach(@NonNull Object attachOwner) {
if (ENVIRONMENT_FACTORY_ATTACH.isActive()) {
ENVIRONMENT_FACTORY_ATTACH.println("[" + Thread.currentThread().getName() + "] Detach(" + attachCount + ":" + (attachCount-1) + ") " + NameUtil.debugSimpleName(this) + " " + NameUtil.debugSimpleName(attachOwner));
}
if (isDisposed()) {
return; // Ignore detach after dispose
}
if (attachCount == 0) {
throw new IllegalStateException(getClass().getName() + " not attached");
}
boolean wasRemoved = attachOwners.remove(Integer.valueOf(System.identityHashCode(attachOwner)));
assert wasRemoved;
if (--attachCount <= 0) {
dispose();
}
}
@Override
public void detachRedundantThreadLocal() {
if ((attachCount == 1) && (ThreadLocalExecutor.basicGetEnvironmentFactory() == this)) {
ThreadLocalExecutor.detachEnvironmentFactory(this);
}
}
@Override
public void dispose() {
if (ENVIRONMENT_FACTORY_ATTACH.isActive()) {
ENVIRONMENT_FACTORY_ATTACH.println("[" + Thread.currentThread().getName() + "] Dispose(" + attachCount + ") " + NameUtil.debugSimpleName(this));
}
if (isDisposed()) {
throw new IllegalStateException(getClass().getName() + " already disposed");
}
attachCount = -1;
disposeInternal();
}
protected void disposeInternal() {
assert isDisposed();
// ThreadLocalExecutor.removeEnvironmentFactory(this); -- maybe wrong thread if GCed - wait for lazy isDisposwed() test
boolean isGlobal = this == GlobalEnvironmentFactory.basicGetInstance();
if (metamodelManager != null) {
metamodelManager.dispose();
metamodelManager = null;
}
EList<Adapter> externalResourceSetAdapters = externalResourceSet.eAdapters();
if (externalResourceSetWasNull || isGlobal) {
// System.out.println("dispose CS " + ClassUtil.debugSimpleName(externalResourceSet));
projectManager.unload(externalResourceSet);
externalResourceSetAdapters.remove(projectManager);
// StandaloneProjectMap.dispose(externalResourceSet2);
externalResourceSet.setPackageRegistry(null);
externalResourceSet.setResourceFactoryRegistry(null);
externalResourceSet.setURIConverter(null);
if (externalResourceSet instanceof ResourceSetImpl) {
((ResourceSetImpl)externalResourceSet).setURIResourceMap(null);
}
for (Resource resource : new ArrayList<Resource>(externalResourceSet.getResources())) {
if (Thread.currentThread().getContextClassLoader() == null) { // If finalizing, avoid NPE from EPackageRegistryImpl$Delegator.deegateRegistry()
// This guard is needed to ensure that clear doesn't make the resource become loaded.
//
if (!resource.getContents().isEmpty())
{
resource.getContents().clear();
}
resource.getErrors().clear();
resource.getWarnings().clear();
/* if (idToEObjectMap != null)
{
idToEObjectMap.clear();
}
if (eObjectToIDMap != null)
{
eObjectToIDMap.clear();
}
if (eObjectToExtensionMap != null)
{
eObjectToExtensionMap.clear();
} */
}
else {
resource.unload();
}
resource.eAdapters().clear();
}
externalResourceSetAdapters.clear();
// externalResourceSet = null;
}
else {
for (Adapter adapter : externalResourceSetAdapters) {
if ((adapter instanceof EnvironmentFactoryAdapter) && (((EnvironmentFactoryAdapter)adapter).getEnvironmentFactory() == this)) {
externalResourceSetAdapters.remove(adapter);
break;
}
}
}
if (idResolver != null) {
idResolver.dispose();
idResolver = null;
}
if (csi2asMapping != null) {
csi2asMapping.dispose();
csi2asMapping = null;
}
// completeEnvironment = null;
// standardLibrary = null;
// completeModel = null;
// if (ENVIRONMENT_FACTORY_ATTACH.isActive()) {
// ENVIRONMENT_FACTORY_ATTACH.println("[" + Thread.currentThread().getName() + "] disposeInternal " + NameUtil.debugSimpleName(this) + " => " + NameUtil.debugSimpleName(PivotUtilInternal.findEnvironmentFactory(externalResourceSet)));
// }
projectManager.unload(asResourceSet);
projectManager.unload(externalResourceSet);
ThreadLocalExecutor.detachEnvironmentFactory(this);
// System.gc();
// System.runFinalization();
}
@Override
protected void finalize() throws Throwable {
// PivotUtilInternal.debugPrintln("Finalize " + NameUtil.debugSimpleName(this));
if (liveEnvironmentFactories != null) {
PivotUtilInternal.debugPrintln("Finalize " + NameUtil.debugSimpleName(this));
List<@NonNull EnvironmentFactory> keySet = new ArrayList<>(liveEnvironmentFactories.keySet());
if (!keySet.isEmpty()) {
StringBuilder s = new StringBuilder();
s.append(" live");
for (@NonNull EnvironmentFactory environmentFactory : keySet) {
s.append(" @" + Integer.toHexString(environmentFactory.hashCode()));
}
System.out.println(s.toString());
}
}
}
/**
* Return the pivot model class for className with the Pivot Model.
*/
@Override
public org.eclipse.ocl.pivot.@Nullable Class getASClass(@NonNull String className) {
return getMetamodelManager().getASClass(className);
}
/**
* @since 1.4
*/
@Override
public @Nullable <T extends Element> T getASOf(@NonNull Class<T> pivotClass, @Nullable EObject eObject) throws ParserException {
if (eObject != null) {
Resource eResource = eObject.eResource();
ASResourceFactory bestHelper = eResource != null ? ASResourceFactoryRegistry.INSTANCE.getASResourceFactory(eResource) : EcoreASResourceFactory.getInstance();
// ASResourceFactory bestHelper = ASResourceFactoryRegistry.INSTANCE.getResourceFactory(eObject);
if (bestHelper != null) {
return bestHelper.getASElement(this, pivotClass, eObject);
}
}
return null;
}
/**
* @since 1.10
*/
public @NonNull ResourceSet getASResourceSet() {
return asResourceSet;
}
/**
* The abstract environment factory implementation is adaptable. The
* default implementation adapts to and interface actually implemented by
* the receiver.
* <p>
* Subclasses may override or extend this implementation.
* </p>
*/
@Override
@SuppressWarnings("unchecked")
public <T> @Nullable T getAdapter(java.lang.Class<T> adapterType) {
@Nullable T result;
if (adapterType.isAssignableFrom(getClass())) {
result = (T) this;
} else {
result = null;
}
return result;
}
/**
* Obtains client metamodel's classifier for the specified
* <code>context</code> object, which may be an instance of a classifier
* in the user model or may actually be a classifier in the user model.
*
* @param context a context object or classifier
* @return the user model's classifier for this context object, or the
* context itself if it is a classifier
*/
protected org.eclipse.ocl.pivot.@NonNull Class getClassifier(@NonNull Object context) {
PivotMetamodelManager metamodelManager = getMetamodelManager();
org.eclipse.ocl.pivot.Class dClass = getIdResolver().getStaticTypeOfValue(null, context);
return metamodelManager.getPrimaryClass(dClass);
}
@Override
public @NonNull CompleteEnvironmentInternal getCompleteEnvironment() {
return completeEnvironment; //completeModel.getCompleteEnvironment();
}
@Override
public @NonNull CompleteModelInternal getCompleteModel() {
return completeModel;
}
@Override
public @Nullable ICSI2ASMapping getCSI2ASMapping() {
return csi2asMapping;
}
@Override
public @Nullable String getDoSetupName(@NonNull URI uri) {
String fileExtension = uri.fileExtension();
if (PivotConstants.ESSENTIAL_OCL_FILE_EXTENSION.equals(fileExtension)) {
return "EssentialOCLStandaloneSetup.doSetup()";
}
else if (PivotConstants.OCL_FILE_EXTENSION.equals(fileExtension)) {
return "CompleteOCLStandaloneSetup.doSetup()";
}
else if (PivotConstants.OCLINECORE_FILE_EXTENSION.equals(fileExtension)) {
return "OCLinEcoreStandaloneSetup.doSetup()";
}
else if (PivotConstants.OCLSTDLIB_FILE_EXTENSION.equals(fileExtension)) {
return "OCLstdlibStandaloneSetup.doSetup()";
}
return null;
}
@Override
public @NonNull IdResolver getIdResolver() {
IdResolver idResolver2 = idResolver;
if (idResolver2 == null) {
idResolver = idResolver2 = createIdResolver();
}
return idResolver2;
}
@Override
public @NonNull PivotMetamodelManager getMetamodelManager() {
PivotMetamodelManager metamodelManager2 = metamodelManager;
if (metamodelManager2 == null) {
metamodelManager = metamodelManager2 = createMetamodelManager();
}
return metamodelManager2;
}
@Override
protected @Nullable EnvironmentFactoryInternal getParent() {
return null;
}
/**
* Return the ProjectMap used to resolve EPackages.
*/
@Override
public @NonNull ProjectManager getProjectManager() {
return projectManager;
}
@Override
public @NonNull ResourceSet getResourceSet() {
return externalResourceSet;
}
@Override
public StatusCodes.@Nullable Severity getSeverity(@Nullable Object validationKey) {
Map<Object, StatusCodes.Severity> validationKey2severity2 = validationKey2severity;
if (validationKey2severity2 == null) {
validationKey2severity = validationKey2severity2 = createValidationKey2severityMap();
}
return validationKey2severity2.get(validationKey);
}
@Override
public @NonNull StandardLibraryInternal getStandardLibrary() {
return standardLibrary;
}
@Override
public @NonNull Technology getTechnology() {
return technology;
}
@Override
public boolean isDisposed() {
return attachCount < 0;
}
/**
* Queries whether tracing of evaluation is enabled. Tracing
* logs the progress of evaluation to the console, which may
* be of use in diagnosing problems.
* <p>
* In an Eclipse environment, tracing is also enabled by turning on the
* <tt>org.eclipse.ocl/debug/evaluation</tt> debug option.
* </p>
*
* @return whether evaluation tracing is enabled
*
* @see #setEvaluationTracingEnabled(boolean)
* @since 1.1
*/
@Override
public boolean isEvaluationTracingEnabled() {
return traceEvaluation;
}
@Override
public EPackage loadEPackage(@NonNull EPackage ePackage) {
return externalResourceSet.getPackageRegistry().getEPackage(ePackage.getNsURI());
}
@Override
public @Nullable Element loadResource(@NonNull Resource resource, @Nullable URI uri) throws ParserException {
ASResourceFactory bestFactory = ASResourceFactoryRegistry.INSTANCE.getASResourceFactory(resource);
if (bestFactory != null) {
ResourceSet resourceSet = resource.getResourceSet();
if ((resourceSet != null) && (resourceSet != externalResourceSet)) {
addExternalResources(resourceSet);
}
return bestFactory.importFromResource(this, resource, uri);
}
throw new ParserException("Cannot create pivot from '" + uri + "'");
// logger.warn("Cannot convert to pivot for package with URI '" + uri + "'");
}
/**
* Return the compiled query for a specification resolving a String body into a non-null bodyExpression.
* Throws a ParserException if conversion fails.
*
* @since 1.4
*/
@Override
public @NonNull ExpressionInOCL parseSpecification(@NonNull LanguageExpression specification) throws ParserException {
if ((specification instanceof ExpressionInOCL) && ((ExpressionInOCL)specification).getOwnedBody() != null) {
return (ExpressionInOCL)specification;
}
EObject contextElement = ClassUtil.nonNullState(specification.eContainer());
String expression = specification.getBody();
if (expression == null) {
throw new ParserException(PivotMessagesInternal.MissingSpecificationBody_ERROR_, NameUtil.qualifiedNameFor(contextElement), PivotUtilInternal.getSpecificationRole(specification));
}
// expression = PivotUtilInternal.getBodyExpression(expression);
ParserContext parserContext = createParserContext(specification);
if (parserContext == null) {
throw new ParserException(PivotMessagesInternal.UnknownContextType_ERROR_, NameUtil.qualifiedNameFor(contextElement), PivotUtilInternal.getSpecificationRole(specification));
}
parserContext.setRootElement(specification);
return parserContext.parse(contextElement, expression);
}
/**
* @since 1.17
*/
@Override
public void preDispose() {
if (attachCount >= 2) {
if (ThreadLocalExecutor.THREAD_LOCAL_ENVIRONMENT_FACTORY.isActive()) {
ThreadLocalExecutor.THREAD_LOCAL_ENVIRONMENT_FACTORY.println("[" + Thread.currentThread().getName() + "] gc()-" + 0);
}
System.gc();
try {
Thread.sleep(100);
} catch (InterruptedException e) {}
}
}
public void resetSeverities() {
validationKey2severity = null;
}
@Override
public void setCSI2ASMapping(ICSI2ASMapping csi2asMapping) {
this.csi2asMapping = csi2asMapping;
}
/**
* Sets whether tracing of evaluation is enabled. Tracing logs
* the progress of parsing to the console, which may be of use in diagnosing
* problems.
* <p>
* In an Eclipse environment, tracing is also enabled by turning on the
* <tt>org.eclipse.ocl/debug/evaluation</tt> debug option.
* </p>
*
* param b whether evaluation tracing is enabled
*
* @see #isEvaluationTracingEnabled()
*/
@Override
public void setEvaluationTracingEnabled(boolean b) {
traceEvaluation = b;
}
@Override
public void setProject(@Nullable IProject project) {}
/**
* Configure safe navigation validation severities.
*/
@Override
public void setSafeNavigationValidationSeverity(StatusCodes.@NonNull Severity severity) {
for (EOperation key : PivotValidationOptions.safeValidationOperation2severityOption.keySet()) {
if (key != null) {
setSeverity(key, severity);
}
}
}
@Override
public synchronized StatusCodes.@Nullable Severity setSeverity(/*@NonNull*/ Object validationKey, StatusCodes.@Nullable Severity severity) {
Map<Object, StatusCodes.Severity> validationKey2severity2 = validationKey2severity;
if (validationKey2severity2 == null) {
validationKey2severity = validationKey2severity2 = createValidationKey2severityMap();
}
return validationKey2severity2.put(validationKey, severity);
}
}