blob: 77d0514e61d184e6e3ef1de087f6c32b826f3ab4 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2010, 2018 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.examples.build.utilities;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.log4j.Logger;
import org.eclipse.emf.common.util.TreeIterator;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
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.util.EcoreUtil;
import org.eclipse.emf.mwe.core.WorkflowContext;
import org.eclipse.emf.mwe.core.issues.Issues;
import org.eclipse.emf.mwe.core.monitor.ProgressMonitor;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.ocl.pivot.CompleteClass;
import org.eclipse.ocl.pivot.Constraint;
import org.eclipse.ocl.pivot.LanguageExpression;
import org.eclipse.ocl.pivot.Library;
import org.eclipse.ocl.pivot.Model;
import org.eclipse.ocl.pivot.Operation;
import org.eclipse.ocl.pivot.Property;
import org.eclipse.ocl.pivot.internal.ecore.as2es.AS2Ecore;
import org.eclipse.ocl.pivot.internal.ecore.es2as.Ecore2AS;
import org.eclipse.ocl.pivot.internal.library.StandardLibraryContribution;
import org.eclipse.ocl.pivot.internal.manager.MetamodelManagerInternal;
import org.eclipse.ocl.pivot.internal.manager.Orphanage;
import org.eclipse.ocl.pivot.internal.resource.StandaloneProjectMap;
import org.eclipse.ocl.pivot.internal.utilities.EnvironmentFactoryInternal;
import org.eclipse.ocl.pivot.internal.utilities.OCLInternal;
import org.eclipse.ocl.pivot.internal.utilities.PivotUtilInternal;
import org.eclipse.ocl.pivot.model.OCLstdlib;
import org.eclipse.ocl.pivot.resource.ASResource;
import org.eclipse.ocl.pivot.resource.CSResource;
import org.eclipse.ocl.pivot.resource.ProjectManager;
import org.eclipse.ocl.pivot.resource.ProjectManager.IResourceDescriptor;
import org.eclipse.ocl.pivot.utilities.ClassUtil;
import org.eclipse.ocl.pivot.utilities.MetamodelManager;
import org.eclipse.ocl.pivot.utilities.PivotUtil;
import org.eclipse.ocl.pivot.utilities.XMIUtil;
import org.eclipse.ocl.xtext.completeocl.CompleteOCLStandaloneSetup;
import com.google.common.collect.Sets;
/**
* Merges a specified <tt>uri</tt> into a designated <tt>modelSlot</tt>.
*/
public class ConstraintMerger extends AbstractProjectComponent
{
private Logger log = Logger.getLogger(getClass());
protected @NonNull List<@NonNull String> ecoreURIs = new ArrayList<>();
protected String libraryURI = null;
protected @NonNull List<@NonNull String> oclURIs = new ArrayList<>();
protected String invariantPrefix;
public ConstraintMerger() {
OCLstdlib.install();
CompleteOCLStandaloneSetup.doSetup();
}
public void addEcoreURI(String ecoreURI) {
assert ecoreURI != null;
ecoreURIs.add(ecoreURI);
}
public void addOclURI(String oclURI) {
assert oclURI != null;
oclURIs.add(oclURI);
}
@Override
public void checkConfiguration(Issues issues) {
super.checkConfiguration(issues);
if (ecoreURIs.size() <= 0) {
issues.addError(this, "no ecoreURI specified.");
}
if (oclURIs.size() <= 0) {
issues.addError(this, "no oclURI specified.");
}
}
@Override
public void invokeInternal(WorkflowContext ctx, ProgressMonitor arg1, Issues arg2) {
ResourceSet resourceSet = getResourceSet();
StandaloneProjectMap.IProjectDescriptor projectDescriptor = ClassUtil.nonNullState(getProjectDescriptor());
// Resource ecoreResource = (Resource) ctx.get(getModelSlot());
// EPackage ecorePivotPackage = (EPackage) ecoreResource.getContents().get(0);
// final String pivotNsURI = ClassUtil.nonNullState(ecorePivotPackage.getNsURI());
OCLInternal ocl = OCLInternal.newInstance(resourceSet);
EnvironmentFactoryInternal environmentFactory = ocl.getEnvironmentFactory();
MetamodelManagerInternal metamodelManager = ocl.getMetamodelManager();
ResourceSet asResourceSet = metamodelManager.getASResourceSet();
// ocl.getResourceSet().getResources().add(ecoreResource); // Don't load another copy
String libraryURI2 = libraryURI;
if (libraryURI2 != null) {
ocl.getStandardLibrary().setDefaultStandardLibraryURI(libraryURI2);
StandardLibraryContribution.REGISTRY.put(libraryURI2, new OCLstdlib.Loader());
}
//
try {
for (@NonNull String ecoreURI : ecoreURIs) {
URI uri = projectDescriptor.getPlatformResourceURI(ecoreURI);
log.info("Loading " + uri);
Resource ecoreResource = resourceSet.getResource(uri, true);
EcoreUtil.resolveAll(ecoreResource);
ResourceUtils.checkResource(ecoreResource);
for (EObject eObject : ecoreResource.getContents()) {
if (eObject instanceof EPackage) {
EPackage ePackage = (EPackage) eObject;
ClassUtil.getMetamodelAnnotation(ePackage); // Install EAnnotation
}
}
Ecore2AS ecore2as = Ecore2AS.getAdapter(ecoreResource, environmentFactory);
Model pivotModel = ecore2as.getASModel();
ASResource asResource = ClassUtil.nonNullState((ASResource)pivotModel.eResource());
ResourceUtils.checkResource(asResource);
}
EcoreUtil.resolveAll(resourceSet);
ResourceUtils.checkResourceSet(resourceSet);
Set<@NonNull Resource> primaryASResources = Sets.newHashSet(ClassUtil.nullFree(asResourceSet.getResources()));
//
for (@NonNull String oclURI : oclURIs) {
URI uri = projectDescriptor.getPlatformResourceURI(oclURI);
log.info("Merging " + uri);
CSResource csResource = ocl.getCSResource(uri);
ResourceUtils.checkResourceSet(asResourceSet);
@SuppressWarnings("unused") Resource oclResource = csResource.getASResource();
}
ResourceUtils.checkResourceSet(asResourceSet);
//
Set<@NonNull Resource> modifiedPrimaryASResources = new HashSet<>();
Map<@NonNull CompleteClass, @NonNull List<org.eclipse.ocl.pivot.Class>> completeClass2mergeTypes = new HashMap<>();
for (Resource secondaryASResource : asResourceSet.getResources()) {
if (!primaryASResources.contains(secondaryASResource)) {
for (TreeIterator<EObject> tit = secondaryASResource.getAllContents(); tit.hasNext(); ) {
EObject eObject = tit.next();
if (eObject instanceof Library) {
tit.prune();
}
else if (eObject instanceof Orphanage) {
tit.prune();
}
else if (eObject instanceof org.eclipse.ocl.pivot.Class) {
org.eclipse.ocl.pivot.Class mergeType = (org.eclipse.ocl.pivot.Class)eObject;
CompleteClass completeClass = metamodelManager.getCompleteClass(mergeType);
List<org.eclipse.ocl.pivot.Class> mergeTypes = completeClass2mergeTypes.get(completeClass);
if (mergeTypes == null) {
mergeTypes = new ArrayList<>();
completeClass2mergeTypes.put(completeClass, mergeTypes);
}
mergeTypes.add(mergeType);
tit.prune();
}
}
}
}
for (@NonNull CompleteClass completeClass : completeClass2mergeTypes.keySet()) {
List<org.eclipse.ocl.pivot.Class> mergeTypes = completeClass2mergeTypes.get(completeClass);
assert mergeTypes != null;
boolean merged = false;
for (org.eclipse.ocl.pivot.@NonNull Class partialClass : PivotUtil.getPartialClasses(completeClass)) {
Resource primaryASResource = PivotUtil.getResource(partialClass);
if (primaryASResources.contains(primaryASResource)) {
modifiedPrimaryASResources.add(primaryASResource);
for (org.eclipse.ocl.pivot.@NonNull Class mergeType : mergeTypes) {
mergeType(metamodelManager, partialClass, mergeType);
}
merged = true;
break;
}
}
if (!merged) {
// FIXME migrate class
}
}
//
Map<@NonNull String, @Nullable Object> options = new HashMap<>();
options.put(AS2Ecore.OPTION_SUPPRESS_DUPLICATES, true);
options.put(AS2Ecore.OPTION_INVARIANT_PREFIX, invariantPrefix);
ProjectManager projectManager = StandaloneProjectMap.findAdapter(resourceSet);
resourceSet.getResources().clear();
for (@NonNull Resource modifiedPrimaryASResource : modifiedPrimaryASResources) {
Model asModel = PivotUtil.getModel(modifiedPrimaryASResource);
String externalURI = asModel.getExternalURI();
URI ecoreURI = URI.createURI(externalURI);
// Resource oldEcoreResource = resourceSet.getResource(ecoreURI, false);
// if (oldEcoreResource != null) {
//
// }
if (projectManager != null) {
IResourceDescriptor resourceDescriptor = null;
resourceDescriptor = projectManager.getResourceDescriptor(ecoreURI);
if (resourceDescriptor != null) {
resourceDescriptor.unload(resourceSet);
resourceDescriptor.configure(resourceSet,
StandaloneProjectMap.CreateStrategy.INSTANCE,
StandaloneProjectMap.MapToFirstConflictHandlerWithLog.INSTANCE);
}
}
Resource newEcoreResource = AS2Ecore.createResource(environmentFactory, modifiedPrimaryASResource, ecoreURI, options);
// projectDescriptor.configure(ecoreResource2.getResourceSet(), StandaloneProjectMap.LoadBothStrategy.INSTANCE, null);
XMIUtil.assignIds(newEcoreResource, new XMIUtil.StructuralENamedElementIdCreator(), null);
Map<Object, Object> saveOptions = XMIUtil.createSaveOptions();
XMIUtil.retainLineWidth(saveOptions, newEcoreResource);
newEcoreResource.save(saveOptions); //getSaveOptions());
// resourceSet.getResources().remove(ecoreResource2);
}
ocl.dispose();
} catch (IOException e) {
throw new RuntimeException("Problems running " + getClass().getSimpleName(), e);
}
}
protected void mergeType(@NonNull MetamodelManager metamodelManager, org.eclipse.ocl.pivot.@NonNull Class primaryType, org.eclipse.ocl.pivot.@NonNull Class mergeType) {
List<Constraint> mergeInvariants = mergeType.getOwnedInvariants();
List<Constraint> primaryInvariants = primaryType.getOwnedInvariants();
for (Constraint mergeInvariant : new ArrayList<>(mergeInvariants)) {
mergeInvariant.setIsCallable(true);
PivotUtilInternal.resetContainer(mergeInvariant);
primaryInvariants.add(mergeInvariant);
}
List<Property> mergeProperties = mergeType.getOwnedProperties();
if (mergeProperties.size() > 0) {
List<Property> primaryProperties = primaryType.getOwnedProperties();
for (@SuppressWarnings("null")@NonNull Property mergeProperty : new ArrayList<>(mergeProperties)) {
Property primaryProperty = metamodelManager.getPrimaryProperty(mergeProperty);
if (primaryProperty != mergeProperty) { // If merge needed
LanguageExpression pivotDefaultExpression = mergeProperty.getOwnedExpression();
LanguageExpression primaryDefaultExpression = primaryProperty.getOwnedExpression();
if ((primaryDefaultExpression == null) && (pivotDefaultExpression != null)) {
primaryProperty.setOwnedExpression(pivotDefaultExpression);
}
}
else // Else simple promotion
{
// boolean b1 = primaryProperty.isIsImplicit();
// boolean b2 = mergeProperty.isIsImplicit();
PivotUtilInternal.resetContainer(mergeProperty);
primaryProperties.add(mergeProperty);
}
}
}
List<Operation> mergeOperations = mergeType.getOwnedOperations();
if (mergeOperations.size() > 0) {
List<Operation> primaryOperations = primaryType.getOwnedOperations();
for (@SuppressWarnings("null")@NonNull Operation mergeOperation : new ArrayList<>(mergeOperations)) {
Operation primaryOperation = metamodelManager.getPrimaryOperation(mergeOperation);
if (primaryOperation != mergeOperation) { // If merge needed
LanguageExpression pivotBodyExpression = mergeOperation.getBodyExpression();
LanguageExpression primaryBodyExpression = primaryOperation.getBodyExpression();
if ((primaryBodyExpression == null) && (pivotBodyExpression != null)) {
PivotUtilInternal.resetContainer(pivotBodyExpression);
primaryOperation.setBodyExpression(pivotBodyExpression);
}
}
else // Else simple promotion
{
PivotUtilInternal.resetContainer(mergeOperation);
primaryOperations.add(mergeOperation);
}
}
}
}
// public void setUri(String uri) {
// this.uri = uri;
// }
/**
* Define a prefix such as "validate" for all invariant operation names.
*/
public void setInvariantPrefix(String invariantPrefix) {
this.invariantPrefix = invariantPrefix;
}
/**
* Define a URI to bw loade as the OCL Standard Library.
*/
public void setLibraryURI(String libraryURI) {
this.libraryURI = libraryURI;
}
}