| /***************************************************************************** |
| * 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$ |
| } |
| } |
| } |