blob: d66e8731f3e2cf8b33e7e533600edd2fb3a12288 [file] [log] [blame]
/*****************************************************************************
* Copyright (c) 2013, 2017 CEA LIST 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:
* CEA LIST - Initial API and implementation
* Christian W. Damus (CEA) - bug 429242
* Christian W. Damus (CEA) - bug 422257
* Eike Stepper (CEA) - bug 466520
*
*****************************************************************************/
package org.eclipse.papyrus.cdo.internal.core.importer;
import java.util.Collection;
import java.util.Set;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.SubMonitor;
import org.eclipse.emf.cdo.explorer.CDOExplorerUtil;
import org.eclipse.emf.cdo.explorer.checkouts.CDOCheckout;
import org.eclipse.emf.cdo.transaction.CDOTransaction;
import org.eclipse.emf.cdo.util.CommitException;
import org.eclipse.emf.common.util.BasicDiagnostic;
import org.eclipse.emf.common.util.Diagnostic;
import org.eclipse.emf.common.util.DiagnosticChain;
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.resource.impl.ResourceSetImpl;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.papyrus.cdo.core.importer.IModelImportMapping;
import org.eclipse.papyrus.cdo.core.importer.IModelImporter;
import org.eclipse.papyrus.cdo.core.importer.IModelTransferConfiguration;
import org.eclipse.papyrus.cdo.core.importer.IModelTransferNode;
import org.eclipse.papyrus.cdo.core.importer.IModelTransferOperation;
import org.eclipse.papyrus.cdo.internal.core.Activator;
import org.eclipse.papyrus.cdo.internal.core.CDOUtils;
import org.eclipse.papyrus.cdo.internal.core.controlmode.CDOControlModeParticipant;
import org.eclipse.papyrus.cdo.internal.core.l10n.Messages;
import org.eclipse.papyrus.cdo.internal.core.resource.CDOSashModelProvider;
import org.eclipse.papyrus.infra.core.sashwindows.di.DiPackage;
import org.eclipse.papyrus.infra.core.sashwindows.di.PageList;
import org.eclipse.papyrus.infra.core.sashwindows.di.SashModel;
import org.eclipse.papyrus.infra.core.sashwindows.di.SashWindowsMngr;
import org.eclipse.papyrus.infra.core.sashwindows.di.util.DiUtils;
import org.eclipse.papyrus.infra.emf.utils.EMFHelper;
import com.google.common.collect.Sets;
/**
* This is the ModelImporter type. Enjoy.
*/
public class ModelImporter implements IModelImporter {
protected static final ContentType DI_CONTENT = new ContentType("DI"); //$NON-NLS-1$
protected static final ContentType UML_CONTENT = new ContentType("UML"); //$NON-NLS-1$
protected static final ContentType NOTATION_CONTENT = new ContentType("Notation"); //$NON-NLS-1$
protected static final ContentType UNKNOWN_CONTENT = new ContentType("unknown"); //$NON-NLS-1$
public ModelImporter() {
super();
}
@Override
public Diagnostic importModels(final IModelImportMapping mapping) {
BasicDiagnostic result = new BasicDiagnostic();
add(result, mapping.getConfiguration().validate());
add(result, mapping.validate());
if (result.getSeverity() < Diagnostic.ERROR) {
add(result, mapping.getConfiguration().getOperationContext().run(new IModelTransferOperation() {
@Override
public Diagnostic run(IProgressMonitor monitor) {
return doImport(mapping, monitor);
}
}));
}
return result;
}
protected Diagnostic doImport(IModelImportMapping mapping, IProgressMonitor monitor) {
BasicDiagnostic result = new BasicDiagnostic();
IModelTransferConfiguration configuration = mapping.getConfiguration();
// by the time the configuration has analyzed every model to be
// imported, all proxies have been resolved that can be. So,
// there's no need for a further EcoreUtil.resolveAll() or such
// 1/resource for import and 1/resource for sub-unit proxies
// 1 for each transaction commit, 1 for saving affected non-imported models, and 1 for clean-up
SubMonitor sub = SubMonitor.convert(monitor, Messages.ModelImporter_4, configuration.getModelsToTransfer().size() + 4);
CDOCheckout checkout = mapping.getCheckout();
CDOTransaction transaction = checkout.openTransaction(new ResourceSetImpl());
ResourceSet destination = transaction.getResourceSet();
try {
for (IModelTransferNode model : configuration.getModelsToTransfer()) {
add(result, importModel(model, configuration.getResourceSet(), mapping.getMapping(model), transaction, sub.newChild(1)));
}
try {
transaction.commit(sub.newChild(1));
// save sash resources (if any)
for (Resource next : destination.getResources()) {
// sash resource would have been saved by commit if it were a CDO URI
if (DependencyAdapter.isDIResource(next) && !CDOUtils.isCDOURI(next.getURI())) {
next.save(null);
}
}
} catch (Exception e) {
result.add(new BasicDiagnostic(IStatus.ERROR, Activator.PLUGIN_ID, 0, Messages.ModelImporter_5, new Object[] { e }));
}
// can't create CDO-style proxies until the resources have been committed, because only then
// will the objects be persisted and have OIDs to reference
boolean hasSubUnits = false;
for (IModelTransferNode model : configuration.getModelsToTransfer()) {
if (createSubUnitProxies(model, mapping.getMapping(model), transaction, sub.newChild(1))) {
hasSubUnits = true;
}
}
if (hasSubUnits) {
try {
transaction.commit(sub.newChild(1));
} catch (CommitException e) {
result.add(new BasicDiagnostic(IStatus.ERROR, Activator.PLUGIN_ID, 0, Messages.ModelImporter_5, new Object[] { e }));
}
} else {
sub.worked(1); // nothing to commit but still count progress
}
try {
saveNonimportedModels(mapping, transaction, sub.newChild(1));
} catch (Exception e) {
result.add(new BasicDiagnostic(IStatus.ERROR, Activator.PLUGIN_ID, 0, Messages.ModelImporter_6, new Object[] { e }));
}
} finally {
EMFHelper.unload(configuration.getResourceSet());
CDOUtils.unload(transaction);
transaction.close();
EMFHelper.unload(destination);
sub.worked(1);
}
sub.done();
return result;
}
protected Diagnostic importModel(IModelTransferNode model, ResourceSet rset, IPath toPath, CDOTransaction transaction, IProgressMonitor monitor) {
BasicDiagnostic result = new BasicDiagnostic();
IPath basePath = toPath.removeFileExtension();
SubMonitor sub = SubMonitor.convert(monitor, model.getName(), model.getResourceURIs().size());
for (URI next : model.getResourceURIs()) {
Resource destination = transaction.getOrCreateResource(basePath.addFileExtension(next.fileExtension()).toString());
Resource source = rset.getResource(next, true);
if (model.getConfiguration().isStripSashModelContent() && DependencyAdapter.isDIResource(source)) {
// import *.di content into the *.sash
CDOCheckout checkout = CDOExplorerUtil.getCheckout(transaction);
URI sashURI = new CDOSashModelProvider().initialize(checkout).getSashModelURI(destination.getURI());
ResourceSet dset = destination.getResourceSet();
Resource sashResource = dset.getURIConverter().exists(sashURI, null) ? dset.getResource(sashURI, true) : null;
if (sashResource == null) {
sashResource = dset.createResource(sashURI);
}
destination = sashResource;
}
add(result, importResource(source, destination));
sub.worked(1);
}
sub.done();
return result;
}
protected boolean createSubUnitProxies(IModelTransferNode model, IPath toPath, CDOTransaction transaction, IProgressMonitor monitor) {
boolean result;
IPath basePath = toPath.removeFileExtension();
URI uri = model.getPrimaryResourceURI();
SubMonitor sub = SubMonitor.convert(monitor, model.getName(), 1);
Resource destination = transaction.getResource(basePath.addFileExtension(uri.fileExtension()).toString());
CDOControlModeParticipant.IUpdate update = new CDOControlModeParticipant().getProxyCrossReferencesUpdate(destination);
result = !update.isEmpty();
update.apply(); // no harm in applying an empty update
sub.worked(1);
sub.done();
return result;
}
protected Diagnostic importResource(Resource source, Resource destination) {
if (!destination.getContents().isEmpty()) {
ContentType contentType = getContentType(source);
if (contentType == DI_CONTENT) {
mergeDIContent(source, destination);
} else {
// just append the additional content
destination.getContents().addAll(source.getContents());
}
} else {
destination.getContents().addAll(source.getContents());
}
return Diagnostic.OK_INSTANCE;
}
/**
* Determines the content-type of a resource for the purpose of combining
* content.
*
* @param resource
* a resource to be combined with existing content
*
* @return the content type
*/
protected ContentType getContentType(Resource resource) {
ContentType result = UNKNOWN_CONTENT;
for (EObject next : resource.getContents()) {
EPackage ePackage = next.eClass().getEPackage();
if (ePackage == DiPackage.eINSTANCE) {
result = DI_CONTENT;
break;
}
if (ePackage.getName().equalsIgnoreCase("uml")) { //$NON-NLS-1$
result = UML_CONTENT;
break;
}
if (ePackage.getName().equalsIgnoreCase("notation")) { //$NON-NLS-1$
result = NOTATION_CONTENT;
break;
}
}
return result;
}
protected void mergeDIContent(Resource source, Resource destination) {
// snip out the source window manager and get its counterpart
SashWindowsMngr srcMngr = DiUtils.lookupSashWindowsMngr(source);
EcoreUtil.remove(srcMngr);
SashWindowsMngr dstMngr = DiUtils.lookupSashWindowsMngr(destination);
// merge the window manager contents
if (dstMngr == null) {
destination.getContents().add(0, srcMngr);
} else {
SashModel dstModel = dstMngr.getSashModel();
SashModel srcModel = srcMngr.getSashModel();
if (dstModel == null) {
dstMngr.setSashModel(srcModel);
} else {
dstModel.getWindows().addAll(srcModel.getWindows());
if (dstModel.getCurrentSelection() == null) {
dstModel.setCurrentSelection(srcModel.getCurrentSelection());
}
}
PageList dstPages = dstMngr.getPageList();
PageList srcPages = srcMngr.getPageList();
if (dstPages == null) {
dstMngr.setPageList(srcPages);
} else {
dstPages.getAvailablePage().addAll(srcPages.getAvailablePage());
}
}
// and add all of the tables and other content
destination.getContents().addAll(source.getContents());
}
protected Diagnostic saveNonimportedModels(IModelImportMapping mapping, CDOTransaction transaction, IProgressMonitor monitor) {
IModelTransferConfiguration configuration = mapping.getConfiguration();
BasicDiagnostic result = new BasicDiagnostic();
Collection<IModelTransferNode> imported = configuration.getModelsToTransfer();
Set<IModelTransferNode> nonImported = Sets.newHashSet();
for (IModelTransferNode next : configuration.getModelsToTransfer()) {
for (IModelTransferNode dependent : next.getDependents()) {
if (!imported.contains(dependent)) {
nonImported.add(dependent);
}
}
}
if (!nonImported.isEmpty()) {
SubMonitor sub = SubMonitor.convert(monitor, Messages.ModelImporter_9, nonImported.size());
ResourceSet rset = configuration.getResourceSet();
try {
for (IModelTransferNode next : nonImported) {
for (URI uri : next.getResourceURIs()) {
Resource resource = rset.getResource(uri, false);
// if the resource is modified, then we imported it, so
// don't save
if ((resource != null) && !resource.isModified()) {
try {
resource.save(null);
} catch (Exception e) {
add(result, new BasicDiagnostic(IStatus.ERROR, Activator.PLUGIN_ID, 0, Messages.ModelImporter_10, new Object[] { e }));
}
}
}
sub.worked(1);
}
} finally {
sub.done();
}
}
return result;
}
private static void add(DiagnosticChain diagnostics, Diagnostic diagnostic) {
if (diagnostic.getSeverity() > Diagnostic.OK) {
diagnostics.merge(diagnostic);
}
}
//
// Nested types
//
protected static class ContentType {
private final String name;
protected ContentType(String name) {
this.name = name;
}
public final String getName() {
return name;
}
@Override
public int hashCode() {
return getName().hashCode();
}
@Override
public boolean equals(Object obj) {
return (obj instanceof ContentType) && ((ContentType) obj).getName().equals(getName());
}
@Override
public String toString() {
return getName() + " content"; //$NON-NLS-1$
}
}
}