/******************************************************************************* * Copyright (c) 2011 Red Hat, Inc. * All rights reserved. * This program is 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: * Red Hat, Inc. - initial API and implementation ******************************************************************************/ package org.eclipse.bpmn2.modeler.ui.wizards; import java.io.IOException; import java.io.PrintWriter; import java.io.StringWriter; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import org.eclipse.core.resources.IWorkspaceRunnable; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.emf.common.command.CommandStack; import org.eclipse.emf.common.util.EList; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.common.util.WrappedException; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.emf.ecore.resource.ResourceSet; import org.eclipse.emf.transaction.RecordingCommand; import org.eclipse.emf.transaction.Transaction; import org.eclipse.emf.transaction.TransactionalEditingDomain; import org.eclipse.emf.transaction.impl.TransactionalEditingDomainImpl; import org.eclipse.graphiti.mm.pictograms.Diagram; import org.eclipse.graphiti.ui.editor.DiagramEditorFactory; public class FileService { public static TransactionalEditingDomain createEmfFileForDiagram(URI diagramResourceUri, final Diagram diagram) { // Create a resource set and EditingDomain final TransactionalEditingDomain editingDomain = DiagramEditorFactory.createResourceSetAndEditingDomain(); final ResourceSet resourceSet = editingDomain.getResourceSet(); // Create a resource for this file. final Resource resource = resourceSet.createResource(diagramResourceUri); final CommandStack commandStack = editingDomain.getCommandStack(); commandStack.execute(new RecordingCommand(editingDomain) { @Override protected void doExecute() { resource.setTrackingModification(true); resource.getContents().add(diagram); } }); save(editingDomain, Collections.<Resource, Map<?, ?>> emptyMap()); return editingDomain; } private static void save(TransactionalEditingDomain editingDomain, Map<Resource, Map<?, ?>> options) { saveInWorkspaceRunnable(editingDomain, options); } private static void saveInWorkspaceRunnable(final TransactionalEditingDomain editingDomain, final Map<Resource, Map<?, ?>> options) { final Map<URI, Throwable> failedSaves = new HashMap<URI, Throwable>(); final IWorkspaceRunnable wsRunnable = new IWorkspaceRunnable() { @Override public void run(final IProgressMonitor monitor) throws CoreException { final Runnable runnable = new Runnable() { @Override public void run() { Transaction parentTx; if (editingDomain != null && (parentTx = ((TransactionalEditingDomainImpl) editingDomain).getActiveTransaction()) != null) { do { if (!parentTx.isReadOnly()) { throw new IllegalStateException( "FileService.save() called from within a command (likely produces a deadlock)"); //$NON-NLS-1$ } } while ((parentTx = ((TransactionalEditingDomainImpl) editingDomain) .getActiveTransaction().getParent()) != null); } final EList<Resource> resources = editingDomain.getResourceSet().getResources(); // Copy list to an array to prevent // ConcurrentModificationExceptions // during the saving of the dirty resources Resource[] resourcesArray = new Resource[resources.size()]; resourcesArray = resources.toArray(resourcesArray); final Set<Resource> savedResources = new HashSet<Resource>(); for (int i = 0; i < resourcesArray.length; i++) { // In case resource modification tracking is // switched on, we can check if a resource // has been modified, so that we only need to same // really changed resources; otherwise // we need to save all resources in the set final Resource resource = resourcesArray[i]; if (resource.isModified()) { try { resource.save(options.get(resource)); savedResources.add(resource); } catch (final Throwable t) { failedSaves.put(resource.getURI(), t); } } } } }; try { editingDomain.runExclusive(runnable); } catch (final InterruptedException e) { throw new RuntimeException(e); } editingDomain.getCommandStack().flush(); } }; try { ResourcesPlugin.getWorkspace().run(wsRunnable, null); if (!failedSaves.isEmpty()) { throw new WrappedException(createMessage(failedSaves), new RuntimeException()); } } catch (final CoreException e) { final Throwable cause = e.getStatus().getException(); if (cause instanceof RuntimeException) { throw (RuntimeException) cause; } throw new RuntimeException(e); } } private static String createMessage(Map<URI, Throwable> failedSaves) { final StringBuilder buf = new StringBuilder("The following resources could not be saved:"); for (final Entry<URI, Throwable> entry : failedSaves.entrySet()) { buf.append("\nURI: ").append(entry.getKey().toString()).append(", cause: \n") .append(getExceptionAsString(entry.getValue())); } return buf.toString(); } private static String getExceptionAsString(Throwable t) { final StringWriter stringWriter = new StringWriter(); final PrintWriter printWriter = new PrintWriter(stringWriter); t.printStackTrace(printWriter); final String result = stringWriter.toString(); try { stringWriter.close(); } catch (final IOException e) { // $JL-EXC$ ignore } printWriter.close(); return result; } }