diff options
author | Eike Stepper | 2020-12-09 07:38:38 +0000 |
---|---|---|
committer | Eike Stepper | 2020-12-09 07:38:38 +0000 |
commit | 7968f34ab4457e97fb5b38f6f0f02d44f7542645 (patch) | |
tree | a603c3fe83c4a695c2445e08ccb5cf3f14b9d6cd | |
parent | d2ca99148ea11b360d2dbef78a6173373484dcc8 (diff) | |
download | cdo-7968f34ab4457e97fb5b38f6f0f02d44f7542645.tar.gz cdo-7968f34ab4457e97fb5b38f6f0f02d44f7542645.tar.xz cdo-7968f34ab4457e97fb5b38f6f0f02d44f7542645.zip |
[569572] [UI] Allows to open a model editor on a CDOFileResource in a CDOCheckout
https://bugs.eclipse.org/bugs/show_bug.cgi?id=569572
10 files changed, 693 insertions, 139 deletions
diff --git a/plugins/org.eclipse.emf.cdo.explorer.ui/src/org/eclipse/emf/cdo/explorer/ui/checkouts/actions/OpenWithActionProvider.java b/plugins/org.eclipse.emf.cdo.explorer.ui/src/org/eclipse/emf/cdo/explorer/ui/checkouts/actions/OpenWithActionProvider.java index e65fad2812..0b81a63a53 100644 --- a/plugins/org.eclipse.emf.cdo.explorer.ui/src/org/eclipse/emf/cdo/explorer/ui/checkouts/actions/OpenWithActionProvider.java +++ b/plugins/org.eclipse.emf.cdo.explorer.ui/src/org/eclipse/emf/cdo/explorer/ui/checkouts/actions/OpenWithActionProvider.java @@ -13,15 +13,17 @@ package org.eclipse.emf.cdo.explorer.ui.checkouts.actions; import org.eclipse.emf.cdo.CDOObject; import org.eclipse.emf.cdo.common.id.CDOID; import org.eclipse.emf.cdo.common.id.CDOIDUtil; +import org.eclipse.emf.cdo.eresource.CDOFileResource; import org.eclipse.emf.cdo.eresource.CDOResource; import org.eclipse.emf.cdo.eresource.CDOResourceFolder; import org.eclipse.emf.cdo.eresource.CDOResourceLeaf; import org.eclipse.emf.cdo.eresource.CDOResourceNode; -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.ui.bundle.OM; +import org.eclipse.emf.cdo.internal.explorer.CDOExplorerURIHandler; import org.eclipse.emf.cdo.internal.ui.dialogs.EditObjectDialog; +import org.eclipse.emf.cdo.internal.ui.editor.CDOLobEditorInput; import org.eclipse.emf.cdo.transaction.CDOTransaction; import org.eclipse.emf.cdo.ui.CDOEditorOpener; import org.eclipse.emf.cdo.ui.CDOEditorUtil; @@ -29,6 +31,7 @@ import org.eclipse.emf.cdo.util.CDOUtil; import org.eclipse.emf.cdo.view.CDOView; import org.eclipse.net4j.util.ObjectUtil; +import org.eclipse.net4j.util.om.OMPlatform; import org.eclipse.net4j.util.ui.UIUtil; import org.eclipse.emf.common.command.BasicCommandStack; @@ -46,7 +49,6 @@ import org.eclipse.jface.action.MenuManager; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.swt.widgets.Shell; import org.eclipse.ui.IActionBars; -import org.eclipse.ui.IEditorInput; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.IPartListener; import org.eclipse.ui.IWorkbenchPage; @@ -63,37 +65,7 @@ import org.eclipse.ui.navigator.ICommonViewerWorkbenchSite; */ public class OpenWithActionProvider extends CommonActionProvider { - // private static final String WORKBENCH_PART_KEY = IWorkbenchPart.class.getName(); - // - // private static final Map<IEditorPart, Pair<CDOView, Pair<CDOResourceLeaf, String>>> VIEWS = new - // HashMap<IEditorPart, Pair<CDOView, Pair<CDOResourceLeaf, String>>>(); - // - // private static final Map<Pair<CDOResourceLeaf, String>, Object> EDITORS = new HashMap<Pair<CDOResourceLeaf, - // String>, Object>(); - // - // private static final Object EDITOR_OPENING = new Object(); - // - // private static final IPartListener2 PART_LISTENER = new PartListener(); - // - // private static final IPageListener PAGE_LISTENER = new PageListener(); - // - // private static final IWindowListener WINDOW_LISTENER = new WindowListener(); - // - // static - // { - // IWorkbench workbench = UIUtil.getWorkbench(); - // for (IWorkbenchWindow window : workbench.getWorkbenchWindows()) - // { - // window.addPageListener(PAGE_LISTENER); - // - // for (IWorkbenchPage page : window.getPages()) - // { - // page.addPartListener(PART_LISTENER); - // } - // } - // - // workbench.addWindowListener(WINDOW_LISTENER); - // } + private static final boolean OMIT_LOB_HANDLER_URI = OMPlatform.INSTANCE.isProperty("org.eclipse.emf.cdo.explorer.ui.omitLobHandlerURI"); private ICommonViewerWorkbenchSite viewSite; @@ -224,61 +196,6 @@ public class OpenWithActionProvider extends CommonActionProvider return cdoObject.cdoResource(); } - // private static IEditorInput createEditorInput(String editorID, CDOCheckout checkout, CDOResourceLeaf resourceLeaf) - // { - // if (CDOEditorUtil.EDITOR_ID.equals(editorID)) - // { - // return CDOEditorUtil.createEditorInput(editorID, resourceLeaf, false, true); - // } - // - // String path = resourceLeaf.getPath(); - // URI uri = checkout.createResourceURI(path); - // return new URIEditorInput(uri); - // } - // - // private static void openEditor(final IWorkbenchPage page, final CDOObject object, final CDOResourceLeaf - // resourceLeaf, - // final String editorID, final Pair<CDOResourceLeaf, String> key) - // { - // new Job("Open") - // { - // @Override - // protected IStatus run(IProgressMonitor monitor) - // { - // final CDOCheckout checkout = CDOExplorerUtil.getCheckout(object); - // final CDOView view = checkout.openView(); - // - // final CDOResourceLeaf contextualLeaf = view.getObject(resourceLeaf); - // final IEditorInput editorInput = createEditorInput(editorID, checkout, contextualLeaf); - // - // Shell shell = page.getWorkbenchWindow().getShell(); - // if (!shell.isDisposed()) - // { - // shell.getDisplay().asyncExec(new Runnable() - // { - // public void run() - // { - // try - // { - // IEditorPart editor = page.openEditor(editorInput, editorID); - // if (editor != null) - // { - // registerEditor(editor, view, key); - // } - // } - // catch (Exception ex) - // { - // OM.LOG.error(ex); - // } - // } - // }); - // } - // - // return Status.OK_STATUS; - // } - // }.schedule(); - // } - public static void openEditor(IWorkbenchPage page, ComposedAdapterFactory adapterFactory, EObject object, String editorOpenerID) { if (page == null) @@ -383,7 +300,7 @@ public class OpenWithActionProvider extends CommonActionProvider } } } - else if (resourceLeaf instanceof CDOTextResource) + else if (resourceLeaf instanceof CDOFileResource) { String editorID = CDOEditorUtil.getEffectiveEditorID(resourceLeaf); if (editorID != null) @@ -395,7 +312,13 @@ public class OpenWithActionProvider extends CommonActionProvider try { - IEditorInput editorInput = CDOEditorUtil.createLobEditorInput(txLeaf, true); + CDOLobEditorInput editorInput = (CDOLobEditorInput)CDOEditorUtil.createLobEditorInput(txLeaf, true); + + if (!OMIT_LOB_HANDLER_URI) + { + editorInput.setURI(CDOExplorerURIHandler.createURI(checkout, txLeaf)); + } + IEditorPart editor = page.openEditor(editorInput, editorID); page.addPartListener(new IPartListener() diff --git a/plugins/org.eclipse.emf.cdo.explorer/src/org/eclipse/emf/cdo/explorer/CDOExplorerUtil.java b/plugins/org.eclipse.emf.cdo.explorer/src/org/eclipse/emf/cdo/explorer/CDOExplorerUtil.java index a0385b54d0..1255253850 100644 --- a/plugins/org.eclipse.emf.cdo.explorer/src/org/eclipse/emf/cdo/explorer/CDOExplorerUtil.java +++ b/plugins/org.eclipse.emf.cdo.explorer/src/org/eclipse/emf/cdo/explorer/CDOExplorerUtil.java @@ -39,6 +39,11 @@ import java.util.LinkedList; */ public final class CDOExplorerUtil { + /** + * @since 4.8 + */ + public static final String URI_SCHEME = "cdo.checkout"; + public static CDORepositoryManager getRepositoryManager() { return OM.getRepositoryManager(); diff --git a/plugins/org.eclipse.emf.cdo.explorer/src/org/eclipse/emf/cdo/internal/explorer/CDOExplorerURIHandler.java b/plugins/org.eclipse.emf.cdo.explorer/src/org/eclipse/emf/cdo/internal/explorer/CDOExplorerURIHandler.java new file mode 100644 index 0000000000..21da85f350 --- /dev/null +++ b/plugins/org.eclipse.emf.cdo.explorer/src/org/eclipse/emf/cdo/internal/explorer/CDOExplorerURIHandler.java @@ -0,0 +1,325 @@ +/* + * Copyright (c) 2020 Eike Stepper (Loehne, Germany) 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: + * Eike Stepper - initial API and implementation + */ +package org.eclipse.emf.cdo.internal.explorer; + +import org.eclipse.emf.cdo.common.commit.CDOCommitInfo; +import org.eclipse.emf.cdo.common.lob.CDOBlob; +import org.eclipse.emf.cdo.common.lob.CDOClob; +import org.eclipse.emf.cdo.common.lob.CDOLobStore; +import org.eclipse.emf.cdo.common.util.CDOException; +import org.eclipse.emf.cdo.common.util.CDOResourceNodeNotFoundException; +import org.eclipse.emf.cdo.eresource.CDOBinaryResource; +import org.eclipse.emf.cdo.eresource.CDOResourceNode; +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.transaction.CDOTransaction; +import org.eclipse.emf.cdo.view.CDOView; + +import org.eclipse.emf.internal.cdo.view.CDOURIHandler; + +import org.eclipse.net4j.util.io.IOUtil; +import org.eclipse.net4j.util.io.ReaderInputStream; + +import org.eclipse.emf.common.util.URI; +import org.eclipse.emf.ecore.resource.URIConverter; +import org.eclipse.emf.ecore.resource.impl.URIHandlerImpl; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.StringReader; +import java.nio.charset.StandardCharsets; +import java.util.Map; + +/** + * @author Eike Stepper + */ +public abstract class CDOExplorerURIHandler<NODE extends CDOResourceNode> extends URIHandlerImpl +{ + public static final CDOExplorerURIHandler<CDOTextResource> TEXT = new TextURIHandler(); + + public static final CDOExplorerURIHandler<CDOBinaryResource> BINARY = new BinaryURIRHandler(); + + private final String scheme; + + protected CDOExplorerURIHandler(String schemeType) + { + this.scheme = CDOExplorerUtil.URI_SCHEME + "." + schemeType; + } + + public final String getScheme() + { + return scheme; + } + + @Override + public boolean canHandle(URI uri) + { + return scheme.equals(uri.scheme()); + } + + @Override + public boolean exists(URI uri, Map<?, ?> options) + { + CDOView view = getView(uri); + NODE node = null; + + try + { + node = getNode(view, uri.path()); + } + catch (CDOResourceNodeNotFoundException ex) + { + //$FALL-THROUGH$ + } + + return node != null; + } + + @Override + public Map<String, ?> getAttributes(URI uri, Map<?, ?> options) + { + CDOView view = getView(uri); + Map<String, ?> attributes = CDOURIHandler.getAttributes(view, uri.path(), options); + + // The view of a checkout is always read-only, so remove this attribute. + attributes.remove(URIConverter.ATTRIBUTE_READ_ONLY); + + return attributes; + } + + @Override + public InputStream createInputStream(URI uri, Map<?, ?> options) throws IOException + { + CDOView view = getView(uri); + NODE node = getNode(view, uri.path()); + return createInputStream(node); + } + + @Override + public OutputStream createOutputStream(URI uri, Map<?, ?> options) throws IOException + { + return new ByteArrayOutputStream() + { + @Override + public void close() throws IOException + { + super.close(); + byte[] bytes = toByteArray(); + + CDOCheckout checkout = getCheckout(uri); + CDOLobStore lobStore = checkout.getView().getSession().options().getLobCache(); + + modify(checkout, uri.path(), true, node -> setContents(node, bytes, lobStore)); + } + }; + } + + @Override + public void delete(URI uri, Map<?, ?> options) throws IOException + { + CDOCheckout checkout = getCheckout(uri); + modify(checkout, uri.path(), false, node -> node.delete(options)); + } + + protected abstract NODE getNode(CDOView view, String path) throws CDOResourceNodeNotFoundException; + + protected abstract NODE getOrCreateNode(CDOTransaction transaction, String path); + + protected abstract InputStream createInputStream(NODE node) throws IOException; + + protected abstract void setContents(NODE node, byte[] bytes, CDOLobStore lobStore) throws IOException; + + private CDOCheckout getCheckout(URI uri) + { + String id = uri.authority(); + + CDOCheckout checkout = CDOExplorerUtil.getCheckout(id); + if (checkout == null) + { + throw new CDOException("No checkout exists for " + uri); + } + + if (!checkout.isOpen()) + { + throw new CDOException("Checkout '" + checkout.getLabel() + "' is not open"); + } + + return checkout; + } + + private CDOView getView(URI uri) + { + CDOCheckout checkout = getCheckout(uri); + return checkout.getView(); + } + + private void modify(CDOCheckout checkout, String path, boolean createOnDemand, ResourceNodeModifier<NODE> modifier) throws IOException + { + CDOTransaction transaction = null; + + try + { + transaction = checkout.openTransaction(); + + NODE node = createOnDemand ? getOrCreateNode(transaction, path) : getNode(transaction, path); + modifier.modify(node); + + CDOCommitInfo commitInfo = transaction.commit(); + if (commitInfo != null) + { + CDOView view = checkout.getView(); + view.waitForUpdate(commitInfo.getTimeStamp()); + } + } + catch (Exception ex) + { + throw IOUtil.ioException(ex); + } + finally + { + IOUtil.closeSilent(transaction); + } + } + + private static CDOExplorerURIHandler<?> getURIHandler(CDOResourceNode node) + { + if (node instanceof CDOTextResource) + { + return TEXT; + } + + if (node instanceof CDOBinaryResource) + { + return TEXT; + } + + return null; + } + + public static URI createURI(CDOCheckout checkout, CDOResourceNode node) + { + CDOExplorerURIHandler<?> uriHandler = getURIHandler(node); + if (uriHandler == null) + { + return null; + } + + String scheme = uriHandler.getScheme(); + String authority = checkout.getID(); + String[] segments = node.getURI().segments(); + + return URI.createHierarchicalURI(scheme, authority, null, segments, null, null); + } + + /** + * @author Eike Stepper + */ + @FunctionalInterface + private interface ResourceNodeModifier<NODE extends CDOResourceNode> + { + public void modify(NODE node) throws IOException; + } + + /** + * @author Eike Stepper + */ + private static final class TextURIHandler extends CDOExplorerURIHandler<CDOTextResource> + { + public TextURIHandler() + { + super("text"); + } + + @Override + protected CDOTextResource getNode(CDOView view, String path) throws CDOResourceNodeNotFoundException + { + return view.getTextResource(path); + } + + @Override + protected CDOTextResource getOrCreateNode(CDOTransaction transaction, String path) + { + return transaction.getOrCreateTextResource(path); + } + + @Override + protected InputStream createInputStream(CDOTextResource node) throws IOException + { + CDOClob clob = node.getContents(); + if (clob == null) + { + return new InputStream() + { + @Override + public int read() throws IOException + { + return IOUtil.EOF; + } + }; + } + + return new ReaderInputStream(clob.getContents(), node.getEncoding()); + } + + @Override + protected void setContents(CDOTextResource node, byte[] bytes, CDOLobStore lobStore) throws IOException + { + String encoding = node.getEncoding(); + if (encoding == null) + { + encoding = StandardCharsets.UTF_8.toString(); + } + + CDOClob clob = new CDOClob(new StringReader(new String(bytes, encoding)), lobStore); + node.setContents(clob); + } + } + + /** + * @author Eike Stepper + */ + private static final class BinaryURIRHandler extends CDOExplorerURIHandler<CDOBinaryResource> + { + public BinaryURIRHandler() + { + super("binary"); + } + + @Override + protected CDOBinaryResource getNode(CDOView view, String path) throws CDOResourceNodeNotFoundException + { + return view.getBinaryResource(path); + } + + @Override + protected CDOBinaryResource getOrCreateNode(CDOTransaction transaction, String path) + { + return transaction.getOrCreateBinaryResource(path); + } + + @Override + protected InputStream createInputStream(CDOBinaryResource node) throws IOException + { + return node.getContents().getContents(); + } + + @Override + protected void setContents(CDOBinaryResource node, byte[] bytes, CDOLobStore lobStore) throws IOException + { + CDOBlob blob = new CDOBlob(new ByteArrayInputStream(bytes), lobStore); + node.setContents(blob); + } + } +} diff --git a/plugins/org.eclipse.emf.cdo.explorer/src/org/eclipse/emf/cdo/internal/explorer/bundle/OM.java b/plugins/org.eclipse.emf.cdo.explorer/src/org/eclipse/emf/cdo/internal/explorer/bundle/OM.java index 1d803b960d..f6470f5b55 100644 --- a/plugins/org.eclipse.emf.cdo.explorer/src/org/eclipse/emf/cdo/internal/explorer/bundle/OM.java +++ b/plugins/org.eclipse.emf.cdo.explorer/src/org/eclipse/emf/cdo/internal/explorer/bundle/OM.java @@ -11,6 +11,7 @@ */ package org.eclipse.emf.cdo.internal.explorer.bundle; +import org.eclipse.emf.cdo.internal.explorer.CDOExplorerURIHandler; import org.eclipse.emf.cdo.internal.explorer.checkouts.CDOCheckoutManagerImpl; import org.eclipse.emf.cdo.internal.explorer.repositories.CDORepositoryManagerImpl; @@ -21,7 +22,16 @@ import org.eclipse.net4j.util.om.OSGiActivator; import org.eclipse.net4j.util.om.log.OMLogger; import org.eclipse.net4j.util.om.trace.OMTracer; +import org.eclipse.emf.common.util.URI; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.emf.ecore.resource.URIConverter; +import org.eclipse.emf.ecore.resource.impl.BinaryResourceImpl; +import org.eclipse.emf.ecore.resource.impl.ResourceFactoryImpl; +import org.eclipse.emf.ecore.xmi.impl.XMIResourceFactoryImpl; +import org.eclipse.emf.ecore.xmi.impl.XMIResourceImpl; + import java.io.File; +import java.util.Map; /** * The <em>Operations & Maintenance</em> class of this bundle. @@ -40,6 +50,8 @@ public abstract class OM private static final String STATE_LOCATION = OMPlatform.INSTANCE.getProperty("org.eclipse.emf.cdo.explorer.stateLocation"); + private static final boolean OMIT_CHECKOUT_FILE_URI_HANDLERS = OMPlatform.INSTANCE.isProperty("org.eclipse.emf.cdo.explorer.omitCheckoutFileURIHandlers"); + private static String stateLocation; private static CDORepositoryManagerImpl repositoryManager; @@ -116,6 +128,54 @@ public abstract class OM */ public static final class Activator extends OSGiActivator { + private static final Resource.Factory TEXT_RESOURCE_FACTORY = new XMIResourceFactoryImpl() + { + @Override + public Resource createResource(URI uri) + { + return new XMIResourceImpl(uri) + { + private URIConverter uriConverter; + + @Override + protected URIConverter getURIConverter() + { + if (uriConverter == null) + { + uriConverter = super.getURIConverter(); + uriConverter.getURIHandlers().add(0, CDOExplorerURIHandler.TEXT); + } + + return uriConverter; + } + }; + } + }; + + private static final Resource.Factory BINARY_RESOURCE_FACTORY = new ResourceFactoryImpl() + { + @Override + public Resource createResource(URI uri) + { + return new BinaryResourceImpl(uri) + { + private URIConverter uriConverter; + + @Override + protected URIConverter getURIConverter() + { + if (uriConverter == null) + { + uriConverter = super.getURIConverter(); + uriConverter.getURIHandlers().add(0, CDOExplorerURIHandler.TEXT); + } + + return uriConverter; + } + }; + } + }; + public Activator() { super(BUNDLE); @@ -126,6 +186,13 @@ public abstract class OM { super.doStart(); + if (!OMIT_CHECKOUT_FILE_URI_HANDLERS) + { + Map<String, Object> factoryMap = Resource.Factory.Registry.INSTANCE.getProtocolToFactoryMap(); + factoryMap.put(CDOExplorerURIHandler.TEXT.getScheme(), TEXT_RESOURCE_FACTORY); + factoryMap.put(CDOExplorerURIHandler.BINARY.getScheme(), BINARY_RESOURCE_FACTORY); + } + stateLocation = STATE_LOCATION != null ? STATE_LOCATION : BUNDLE.getStateLocation(); initializeManagers(new File(stateLocation)); } diff --git a/plugins/org.eclipse.emf.cdo.explorer/src/org/eclipse/emf/cdo/internal/explorer/checkouts/CDOCheckoutViewProvider.java b/plugins/org.eclipse.emf.cdo.explorer/src/org/eclipse/emf/cdo/internal/explorer/checkouts/CDOCheckoutViewProvider.java index 1e0a054cea..caae1dc27c 100644 --- a/plugins/org.eclipse.emf.cdo.explorer/src/org/eclipse/emf/cdo/internal/explorer/checkouts/CDOCheckoutViewProvider.java +++ b/plugins/org.eclipse.emf.cdo.explorer/src/org/eclipse/emf/cdo/internal/explorer/checkouts/CDOCheckoutViewProvider.java @@ -39,7 +39,7 @@ import java.util.Map; */ public class CDOCheckoutViewProvider extends AbstractCDOViewProvider { - public static final String SCHEME = "cdo.checkout"; + public static final String SCHEME = CDOExplorerUtil.URI_SCHEME; // TODO Move to activator and deactivate via stop(). private static final ReferenceMonitor<ResourceSet> MONITOR = new ReferenceMonitor<ResourceSet>() diff --git a/plugins/org.eclipse.emf.cdo.ui/src/org/eclipse/emf/cdo/internal/ui/editor/CDOLobEditorInput.java b/plugins/org.eclipse.emf.cdo.ui/src/org/eclipse/emf/cdo/internal/ui/editor/CDOLobEditorInput.java index 2bf858fff1..922fe5f0e3 100644 --- a/plugins/org.eclipse.emf.cdo.ui/src/org/eclipse/emf/cdo/internal/ui/editor/CDOLobEditorInput.java +++ b/plugins/org.eclipse.emf.cdo.ui/src/org/eclipse/emf/cdo/internal/ui/editor/CDOLobEditorInput.java @@ -12,6 +12,8 @@ package org.eclipse.emf.cdo.internal.ui.editor; import org.eclipse.emf.cdo.eresource.CDOResourceLeaf; +import org.eclipse.emf.common.util.URI; + import org.eclipse.core.runtime.PlatformObject; import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.ui.IEditorInput; @@ -28,6 +30,8 @@ public class CDOLobEditorInput extends PlatformObject implements IEditorInput private final boolean commitOnSave; + private URI uri; + public CDOLobEditorInput(CDOResourceLeaf resource) { this(resource, false); @@ -49,6 +53,16 @@ public class CDOLobEditorInput extends PlatformObject implements IEditorInput return commitOnSave; } + public final URI getURI() + { + return uri == null ? resource.getURI() : uri; + } + + public final void setURI(URI uri) + { + this.uri = uri; + } + @Override public boolean exists() { @@ -78,4 +92,18 @@ public class CDOLobEditorInput extends PlatformObject implements IEditorInput { return resource.getURI().toString(); } + + @Override + @SuppressWarnings("unchecked") + public <T> T getAdapter(Class<T> type) + { + T adapter = super.getAdapter(type); + + if (adapter == null && type == URI.class) + { + adapter = (T)getURI(); + } + + return adapter; + } } diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/view/CDOURIHandler.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/view/CDOURIHandler.java index d749af89f4..5be36fc821 100644 --- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/view/CDOURIHandler.java +++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/view/CDOURIHandler.java @@ -11,11 +11,15 @@ */ package org.eclipse.emf.internal.cdo.view; +import org.eclipse.emf.cdo.common.branch.CDOBranch; +import org.eclipse.emf.cdo.common.commit.CDOCommitInfo; import org.eclipse.emf.cdo.eresource.CDOResource; import org.eclipse.emf.cdo.eresource.CDOResourceFolder; import org.eclipse.emf.cdo.eresource.CDOResourceNode; +import org.eclipse.emf.cdo.session.CDOSession; import org.eclipse.emf.cdo.transaction.CDOTransaction; import org.eclipse.emf.cdo.util.CDOURIUtil; +import org.eclipse.emf.cdo.view.CDOView; import org.eclipse.emf.cdo.view.CDOViewProvider; import org.eclipse.emf.cdo.view.CDOViewProvider.CDOViewProvider2; import org.eclipse.emf.cdo.view.CDOViewProviderRegistry; @@ -101,26 +105,7 @@ public class CDOURIHandler implements URIHandler @Override public void delete(URI uri, Map<?, ?> options) throws IOException { - String path = CDOURIUtil.extractResourcePath(uri); - CDOTransaction transaction = null; - - try - { - transaction = view.getSession().openTransaction(); - CDOResourceNode node = transaction.getResourceNode(path); - node.delete(options); - transaction.commit(); - } - catch (Exception ex) - { - IOException ioException = new IOException(ex.getMessage()); - ioException.initCause(ex); - throw ioException; - } - finally - { - IOUtil.closeSilent(transaction); - } + modify(uri, node -> node.delete(options)); } @Override @@ -144,33 +129,10 @@ public class CDOURIHandler implements URIHandler } @Override - @SuppressWarnings("unchecked") public Map<String, ?> getAttributes(URI uri, Map<?, ?> options) { - Map<String, Object> result = new HashMap<>(); - String path = CDOURIUtil.extractResourcePath(uri); - CDOResourceNode node = view.getResourceNode(path); - if (node != null) - { - Set<String> requestedAttributes = (Set<String>)options.get(URIConverter.OPTION_REQUESTED_ATTRIBUTES); - if (requestedAttributes == null || requestedAttributes.contains(URIConverter.ATTRIBUTE_TIME_STAMP)) - { - long stamp = node instanceof CDOResource ? ((CDOResource)node).getTimeStamp() : URIConverter.NULL_TIME_STAMP; - result.put(URIConverter.ATTRIBUTE_TIME_STAMP, stamp); - } - - if (requestedAttributes == null || requestedAttributes.contains(URIConverter.ATTRIBUTE_DIRECTORY)) - { - result.put(URIConverter.ATTRIBUTE_DIRECTORY, node instanceof CDOResourceFolder); - } - - if (requestedAttributes == null || requestedAttributes.contains(URIConverter.ATTRIBUTE_READ_ONLY)) - { - result.put(URIConverter.ATTRIBUTE_READ_ONLY, view.isReadOnly()); - } - } - - return result; + String path = getPath(uri); + return getAttributes(view, path, options); } @Override @@ -180,6 +142,12 @@ public class CDOURIHandler implements URIHandler // storing that attribute in the server. Due to CDOResouce distributed nature, changing it wouldn't make much sense. } + void setViewProvider2(CDOViewProvider2 viewProvider2) + { + this.viewProvider2 = viewProvider2; + viewURI = viewProvider2.getViewURI(view); + } + private String getPath(URI uri) { if (CDO_URI_SCHEME.equals(uri.scheme())) @@ -198,9 +166,76 @@ public class CDOURIHandler implements URIHandler return null; } - void setViewProvider2(CDOViewProvider2 viewProvider2) + private void modify(URI uri, ResourceNodeModifier modifier) throws IOException { - this.viewProvider2 = viewProvider2; - viewURI = viewProvider2.getViewURI(view); + if (view.isHistorical()) + { + throw new IOException("View is historical: " + view); + } + + String path = getPath(uri); + CDOTransaction transaction = null; + + try + { + CDOSession session = view.getSession(); + CDOBranch branch = view.getBranch(); + transaction = session.openTransaction(branch); + + CDOResourceNode node = transaction.getResourceNode(path); + modifier.modify(node); + + CDOCommitInfo commitInfo = transaction.commit(); + if (commitInfo != null) + { + view.waitForUpdate(commitInfo.getTimeStamp()); + } + } + catch (Exception ex) + { + throw IOUtil.ioException(ex); + } + finally + { + IOUtil.closeSilent(transaction); + } + } + + @SuppressWarnings("unchecked") + public static Map<String, ?> getAttributes(CDOView view, String path, Map<?, ?> options) + { + Map<String, Object> result = new HashMap<>(); + + CDOResourceNode node = view.getResourceNode(path); + if (node != null) + { + Set<String> requestedAttributes = (Set<String>)options.get(URIConverter.OPTION_REQUESTED_ATTRIBUTES); + if (requestedAttributes == null || requestedAttributes.contains(URIConverter.ATTRIBUTE_TIME_STAMP)) + { + long stamp = node instanceof CDOResource ? ((CDOResource)node).getTimeStamp() : URIConverter.NULL_TIME_STAMP; + result.put(URIConverter.ATTRIBUTE_TIME_STAMP, stamp); + } + + if (requestedAttributes == null || requestedAttributes.contains(URIConverter.ATTRIBUTE_DIRECTORY)) + { + result.put(URIConverter.ATTRIBUTE_DIRECTORY, node instanceof CDOResourceFolder); + } + + if (requestedAttributes == null || requestedAttributes.contains(URIConverter.ATTRIBUTE_READ_ONLY)) + { + result.put(URIConverter.ATTRIBUTE_READ_ONLY, view.isReadOnly()); + } + } + + return result; + } + + /** + * @author Eike Stepper + */ + @FunctionalInterface + private interface ResourceNodeModifier + { + public void modify(CDOResourceNode node) throws IOException; } } diff --git a/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/io/IORunnable.java b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/io/IORunnable.java index 7c40dabea0..8876a0bb30 100644 --- a/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/io/IORunnable.java +++ b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/io/IORunnable.java @@ -16,6 +16,7 @@ import java.io.IOException; /** * @author Eike Stepper */ +@FunctionalInterface public interface IORunnable<IO extends Closeable> { public void run(IO io) throws IOException; diff --git a/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/io/IOUtil.java b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/io/IOUtil.java index 9bb821777f..a55380e4d9 100644 --- a/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/io/IOUtil.java +++ b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/io/IOUtil.java @@ -108,6 +108,21 @@ public final class IOUtil } /** + * @since 3.13 + */ + public static IOException ioException(Exception ex) + { + if (ex instanceof IOException) + { + return (IOException)ex; + } + + IOException ioException = new IOException(ex.getMessage()); + ioException.initCause(ex); + return ioException; + } + + /** * @since 3.1 */ public static void print(StackTraceElement[] elements) diff --git a/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/io/ReaderInputStream.java b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/io/ReaderInputStream.java new file mode 100644 index 0000000000..b9291ef374 --- /dev/null +++ b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/io/ReaderInputStream.java @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2020 Eike Stepper (Loehne, Germany) 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: + * Eike Stepper - initial API and implementation + */ +package org.eclipse.net4j.util.io; + +import java.io.IOException; +import java.io.InputStream; +import java.io.Reader; +import java.nio.Buffer; +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; + +/** + * An input stream for reading a {@link Reader}. + * + * @author Eike Stepper + * @since 3.13 + */ +public class ReaderInputStream extends InputStream +{ + private static final int MASK = 0xFF; + + private final Charset charset; + + private Reader reader; + + private CharBuffer chars = CharBuffer.allocate(IOUtil.DEFAULT_BUFFER_SIZE); + + private ByteBuffer bytes; + + public ReaderInputStream(Reader reader, String encoding) throws IOException + { + this.reader = reader; + charset = encoding == null ? StandardCharsets.UTF_8 : Charset.forName(encoding); + } + + public ReaderInputStream(Reader reader) throws IOException + { + this(reader, null); + } + + @Override + public int available() throws IOException + { + checkClosed(); + ensureBytes(); + + if (bytes == null) + { + return 0; + } + + return bytes.remaining(); + } + + @Override + public int read(byte[] b, int off, int len) throws IOException + { + checkClosed(); + + if (len == 0) + { + return 0; + } + + ensureBytes(); + if (bytes == null) + { + return IOUtil.EOF; + } + + int count = 0; + do + { + ensureBytes(); + + if (bytes == null) + { + // No more to read. + break; + } + + int toRead = Math.min(bytes.remaining(), len - count); + bytes.get(b, off + count, toRead); + count = count + toRead; + } while (count < len); + + return count; + } + + @Override + public int read() throws IOException + { + checkClosed(); + + ensureBytes(); + if (bytes == null) + { + return IOUtil.EOF; + } + + return bytes.get() & MASK; + } + + @Override + public void close() throws IOException + { + if (reader != null) + { + reader.close(); + reader = null; + bytes = null; + chars = null; + } + } + + private void ensureBytes() throws IOException + { + if (bytes == null || !bytes.hasRemaining()) + { + checkClosed(); + + Buffer buffer = chars; + buffer.rewind(); + + int count = reader.read(chars); + if (count > 0) + { + buffer.flip(); + bytes = charset.encode(chars); + } + else + { + bytes = null; + } + } + } + + private void checkClosed() throws IOException + { + if (reader == null) + { + throw new IOException("Reader is closed"); //$NON-NLS-1$ + } + } +} |