| /***************************************************************************** |
| * 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); |
| } |
| } |