blob: 96d7af90a066b3153cf027c6775d44308921bfe6 [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 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* CEA LIST - Initial API and implementation
* Christian W. Damus (CEA) - bug 422257
* Eike Stepper (CEA) - bug 466520
*
*****************************************************************************/
package org.eclipse.papyrus.cdo.internal.ui.customization.properties.storage.action;
import static org.eclipse.papyrus.cdo.internal.ui.customization.properties.storage.CDOContextStorageProvider.CONTEXTS_PATH;
import static org.eclipse.papyrus.cdo.internal.ui.customization.properties.storage.CDOContextStorageProvider.CONTEXT_EXTENSION;
import static org.eclipse.papyrus.views.properties.toolsmiths.storage.actions.ContextStorageActionUtil.isRelative;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.LinkedList;
import java.util.List;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.SubMonitor;
import org.eclipse.emf.cdo.common.lob.CDOClob;
import org.eclipse.emf.cdo.eresource.CDOResourceFolder;
import org.eclipse.emf.cdo.eresource.CDOTextResource;
import org.eclipse.emf.cdo.explorer.CDOExplorerUtil;
import org.eclipse.emf.cdo.explorer.checkouts.CDOCheckout;
import org.eclipse.emf.cdo.explorer.checkouts.CDOCheckoutManager;
import org.eclipse.emf.cdo.transaction.CDOTransaction;
import org.eclipse.emf.cdo.util.CDOURIUtil;
import org.eclipse.emf.cdo.util.CDOUtil;
import org.eclipse.emf.cdo.view.CDOView;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.resource.URIConverter;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.operation.IRunnableContext;
import org.eclipse.jface.window.Window;
import org.eclipse.osgi.util.NLS;
import org.eclipse.papyrus.cdo.internal.core.CDOUtils;
import org.eclipse.papyrus.cdo.internal.ui.customization.properties.Activator;
import org.eclipse.papyrus.cdo.internal.ui.customization.properties.messages.Messages;
import org.eclipse.papyrus.cdo.internal.ui.customization.properties.storage.CDOTextURIHandler;
import org.eclipse.papyrus.cdo.internal.ui.dialogs.CheckoutSelectionDialog;
import org.eclipse.papyrus.infra.emf.utils.EMFHelper;
import org.eclipse.papyrus.infra.properties.catalog.PropertiesURIHandler;
import org.eclipse.papyrus.infra.properties.contexts.Context;
import org.eclipse.papyrus.infra.properties.contexts.Section;
import org.eclipse.papyrus.infra.properties.contexts.Tab;
import org.eclipse.papyrus.infra.properties.ui.util.PropertiesUtil;
import org.eclipse.papyrus.views.properties.toolsmiths.storage.actions.ContextStorageActionUtil;
import org.eclipse.papyrus.views.properties.toolsmiths.storage.actions.IContextCopyAction;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import com.google.common.base.Supplier;
import com.google.common.io.Closeables;
/**
* This is the CDOContextCopyAction type. Enjoy.
*/
public class CDOContextCopyAction extends AbstractCDOContextAction implements IContextCopyAction {
@Override
public String getLabel() {
return Messages.CDOContextCopyAction_0;
}
@Override
public String getToolTip() {
return Messages.CDOContextCopyAction_1;
}
@Override
public Context copy(Context source, String targetName, IProgressMonitor monitor) throws CoreException {
CDOCheckout checkout = selectCheckout(source);
if (checkout == null) {
// user cancelled
return null;
}
CDOTransaction transaction = checkout.openTransaction(new ResourceSetImpl());
SubMonitor sub = SubMonitor.convert(monitor);
Context result = null;
try {
CDOResourceFolder contextsFolder = transaction.getOrCreateResourceFolder(CONTEXTS_PATH);
String folderPath = new Path(contextsFolder.getPath()).append(targetName).toString();
String resourcePath = new Path(folderPath).append(targetName).addFileExtension(CONTEXT_EXTENSION).toString();
if (transaction.hasResource(folderPath)) { // actually checks for any kind of resource node at that path
throw new IOException(Messages.CDOContextCopyAction_2);
}
transaction.createResourceFolder(folderPath);
CDOTextResource targetResource = transaction.createTextResource(resourcePath);
// create a custom URI scheme that delegates XMI resource content to a CDOTextResource's CLOB content
URI targetModelURI = CDOTextURIHandler.createURI(targetResource.getURI());
ResourceSet resourceSet = transaction.getResourceSet();
// add the URI handler to load the context resource
CDOTextURIHandler.install(resourceSet);
// re-load the source context in the new resource set to scope the copy operation
Context sourceContext = (Context) EMFHelper.loadEMFModel(resourceSet, source.eResource().getURI());
IStatus copyResult = copyAll(sourceContext, targetResource, sub);
if (copyResult.isOK()) {
Context resultContext = (Context) EMFHelper.loadEMFModel(resourceSet, targetModelURI);
resultContext.setName(targetName);
resultContext.setPrototype(sourceContext);
resultContext.eResource().save(null);
long commitTime = System.currentTimeMillis();
transaction.commit();
CDOView sourceView = CDOUtil.getCDOObject(source).cdoView();
sourceView.waitForUpdate(commitTime, 30000L);
// load the new instance in the shared resource set
ResourceSet sourceResourceSet = sourceView.getResourceSet();
result = (Context) EMFHelper.loadEMFModel(sourceResourceSet, targetModelURI);
} else if (copyResult.getSeverity() != IStatus.CANCEL) {
throw new CoreException(copyResult);
}
} catch (Exception e) {
throw new CoreException(new Status(IStatus.ERROR, Activator.PLUGIN_ID, e.getLocalizedMessage(), e));
} finally {
CDOUtils.unload(transaction);
transaction.close();
EMFHelper.unload(transaction.getResourceSet());
sub.done();
}
return result;
}
protected CDOCheckout selectCheckout(Context context) {
CDOCheckout result = null;
CDOCheckoutManager mgr = CDOExplorerUtil.getCheckoutManager();
CDOCheckout[] checkouts = mgr.getCheckouts();
// default selection is the repository containing the context to be copied,
// if it is in a repository
CDOCheckout initialSelection = null;
URI uri = context.eResource().getURI();
if (CDOUtils.isCDOURI(uri)) {
initialSelection = CDOExplorerUtil.getCheckout(uri);
}
// otherwise, look for the first open repository
if (initialSelection == null) {
for (CDOCheckout next : checkouts) {
if (next.isOpen()) {
initialSelection = next;
break;
}
}
}
result = initialSelection;
if (checkouts.length > 1) {
final CDOCheckout[] innerResult = { initialSelection };
Display.getDefault().syncExec(new Runnable() {
@Override
public void run() {
Shell active = Display.getDefault().getActiveShell();
CheckoutSelectionDialog dlg = new CheckoutSelectionDialog(active, innerResult[0], new Supplier<IRunnableContext>() {
@Override
public IRunnableContext get() {
return new ProgressMonitorDialog(Display.getDefault().getActiveShell());
}
});
if (dlg.open() == Window.OK) {
innerResult[0] = dlg.getSelectedRepository();
} else {
innerResult[0] = null;
}
}
});
result = innerResult[0];
}
return (CDOCheckout) result;
}
private IStatus copyAll(Context source, CDOTextResource target, IProgressMonitor monitor) {
SubMonitor sub = SubMonitor.convert(monitor, 100);
ContextStorageActionUtil.initializeCopy(source, sub.newChild(10));
return doCopy(source, target, sub.newChild(90));
}
private IStatus doCopy(Context source, CDOTextResource target, IProgressMonitor monitor) {
IStatus result = Status.OK_STATUS;
final CDOResourceFolder targetFolder = target.getFolder();
final String targetName = target.getName();
try {
Resource sourceResource = source.eResource();
int resourcesToCopy = sourceResource.getResourceSet().getResources().size();
List<Context> contexts = new LinkedList<Context>();
for (Context context : PropertiesUtil.getDependencies(source)) {
if (isRelative(sourceResource, context.eResource())) {
contexts.add(context);
for (Tab tab : context.getTabs()) {
resourcesToCopy += tab.getSections().size();
}
}
}
monitor.beginTask(NLS.bind(Messages.CDOContextCopyAction_3, source.getName(), target.getName()), resourcesToCopy);
// copy the primary context
copy(sourceResource.getResourceSet(), sourceResource.getURI(), target);
monitor.worked(1);
// copy the dependent resources which are located in the same folder or in subfolders
for (Resource resource : sourceResource.getResourceSet().getResources()) {
if (monitor.isCanceled()) {
return Status.CANCEL_STATUS;
}
if ((resource != sourceResource) && isRelative(sourceResource, resource)) {
copy(resource, targetFolder, sourceResource, targetName);
}
monitor.worked(1);
}
// copy the XWT files (they haven't been loaded in the resource set)
for (Context context : contexts) {
for (Tab tab : context.getTabs()) {
for (Section section : tab.getSections()) {
if (monitor.isCanceled()) {
return Status.CANCEL_STATUS;
}
copy(section.getSectionFile(), targetFolder, sourceResource);
monitor.worked(1);
}
}
}
monitor.done();
} catch (IOException ex) {
Activator.log.error(ex);
result = new Status(IStatus.ERROR, Activator.PLUGIN_ID, "An error occurred during the copy of " + source.getName(), ex); //$NON-NLS-1$
monitor.done();
}
return result;
}
protected void copy(String xwtFileName, CDOResourceFolder targetFolder, Resource sourceResource) throws IOException {
CDOTextResource target = ((CDOTransaction) targetFolder.cdoView()).createTextResource(new Path(targetFolder.getPath()).append(xwtFileName).toString());
URI sourceURI = URI.createURI(xwtFileName).resolve(sourceResource.getURI());
copy(sourceResource.getResourceSet(), sourceURI, target);
}
protected void copy(ResourceSet sourceResourceSet, URI sourceURI, CDOTextResource target) throws IOException {
PropertiesURIHandler uriHandler = new PropertiesURIHandler();
if (uriHandler.canHandle(sourceURI)) {
sourceURI = uriHandler.getConvertedURI(sourceURI);
}
InputStream input = null;
try {
input = sourceResourceSet.getURIConverter().createInputStream(sourceURI);
String encoding = (input instanceof URIConverter.Readable) ? ((URIConverter.Readable) input).getEncoding() : "UTF-8"; //$NON-NLS-1$
Reader contents = new InputStreamReader(input, encoding);
target.setContents(new CDOClob(contents));
} catch (IOException ex) {
Activator.log.error(ex);
} finally {
if (input != null) {
Closeables.closeQuietly(input);
}
}
}
private void copy(Resource resource, CDOResourceFolder folder, Resource base, String targetName) throws IOException {
URI relativeURI = resource.getURI().deresolve(base.getURI());
if (relativeURI.toString().equals("")) { //$NON-NLS-1$
relativeURI = URI.createURI(targetName + ".ctx"); //$NON-NLS-1$
}
// append a dummy segment to ensure correct resolution (otherwise we will
// miss the last segment of the folder path)
URI uri = relativeURI.resolve(folder.getURI().appendSegment("dummy.ctx")); //$NON-NLS-1$
CDOTextResource target = ((CDOTransaction) folder.cdoView()).createTextResource(CDOURIUtil.extractResourcePath(uri));
copy(resource.getResourceSet(), resource.getURI(), target);
}
}