diff options
author | Eike Stepper | 2019-02-03 08:37:04 +0000 |
---|---|---|
committer | Eike Stepper | 2019-02-03 08:37:04 +0000 |
commit | 9b86d2e358a5d6785be4cf1c4502fcde0f5406c0 (patch) | |
tree | 757c7a05c79ea03dbcba7cd7de92ee32ff023d8d /plugins | |
parent | 5a214bcbdf877c8f9bcca90ad5d1d09ede54fc05 (diff) | |
download | cdo-9b86d2e358a5d6785be4cf1c4502fcde0f5406c0.tar.gz cdo-9b86d2e358a5d6785be4cf1c4502fcde0f5406c0.tar.xz cdo-9b86d2e358a5d6785be4cf1c4502fcde0f5406c0.zip |
[544075] Add setBasename() and setExtension() methods to CDOResourceNode
https://bugs.eclipse.org/bugs/show_bug.cgi?id=544075
Diffstat (limited to 'plugins')
7 files changed, 371 insertions, 40 deletions
diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/ResourceTest.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/ResourceTest.java index 6e3e3630b5..ffe071c98a 100644 --- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/ResourceTest.java +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/ResourceTest.java @@ -2218,6 +2218,88 @@ public class ResourceTest extends AbstractCDOTest } } + public void testNameChecks() + { + CDOSession session = openSession(); + CDOTransaction transaction = session.openTransaction(); + CDOResource resource1 = transaction.createResource(getResourcePath("/my/resource1")); + + assertEquals("resource1", resource1.getName()); + assertEquals("resource1", resource1.getBasename()); + assertEquals("", resource1.getExtension()); + + try + { + resource1.setName("/resource1"); + fail("IllegalArgumentException expected"); + } + catch (IllegalArgumentException expected) + { + // SUCCESS + } + + resource1.setExtension("tar.gz"); + assertEquals("resource1.tar.gz", resource1.getName()); + assertEquals("resource1", resource1.getBasename()); + assertEquals("tar.gz", resource1.getExtension()); + + resource1.setBasename("model"); + assertEquals("model.tar.gz", resource1.getName()); + assertEquals("model", resource1.getBasename()); + assertEquals("tar.gz", resource1.getExtension()); + + try + { + resource1.setBasename("model.xyz"); + fail("IllegalArgumentException expected"); + } + catch (IllegalArgumentException expected) + { + // SUCCESS + } + + resource1.setExtension(""); + assertEquals("model", resource1.getName()); + assertEquals("model", resource1.getBasename()); + assertEquals("", resource1.getExtension()); + + resource1.setExtension("ecore"); + resource1.setBasename(""); + assertEquals(".ecore", resource1.getName()); + assertEquals("", resource1.getBasename()); + assertEquals("ecore", resource1.getExtension()); + + try + { + resource1.setName(null); + fail("IllegalArgumentException expected"); + } + catch (IllegalArgumentException expected) + { + // SUCCESS + } + + try + { + resource1.setName(""); + fail("IllegalArgumentException expected"); + } + catch (IllegalArgumentException expected) + { + // SUCCESS + } + + try + { + resource1.setName("."); + fail("IllegalArgumentException expected"); + } + catch (IllegalArgumentException expected) + { + // SUCCESS + } + } + /** * @author Eike Stepper */ diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_334995_Test.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_334995_Test.java index 79ea70ff09..873eddf9d4 100644 --- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_334995_Test.java +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_334995_Test.java @@ -18,6 +18,8 @@ import org.eclipse.emf.cdo.tests.AbstractCDOTest; import org.eclipse.emf.cdo.transaction.CDOTransaction; import org.eclipse.emf.cdo.util.CommitException; +import org.eclipse.emf.ecore.resource.Resource; + import java.util.Map.Entry; /** @@ -30,37 +32,55 @@ public class Bugzilla_334995_Test extends AbstractCDOTest /** * The following test seems obsolete because (as of bug xxxxxx) no local changes can create resource duplicates. */ - public void _test() throws CommitException + public void testURIClash() throws CommitException { - CDOID resourceID = persistResources("/res1")[0]; + CDOSession session = openSession(); + CDOTransaction transaction = session.openTransaction(); + CDOResource resourceA = transaction.createResource(getResourcePath("/resA")); + resourceA.getContents().add(getModel1Factory().createCustomer()); + transaction.commit(); + System.out.println("Persisted resource: " + resourceA); - { - CDOSession session = openSession(); - CDOTransaction transaction = session.openTransaction(); + CDOSession session2 = openSession(); + CDOTransaction transaction2 = session2.openTransaction(); + CDOResource resourceB2 = transaction2.createResource(getResourcePath("/resB")); + resourceB2.getContents().add(getModel1Factory().createSupplier()); - CDOResource resource = transaction.createResource(getResourcePath("/res1")); - msg("New resource: " + resource); - msg("newObjects:"); + resourceA.setName("resB"); + commitAndSync(transaction, transaction2); - for (Entry<CDOID, CDOObject> entry : transaction.getNewObjects().entrySet()) - { - msg(" " + entry + ", state: " + entry.getValue().cdoState()); - assertNew(entry.getValue(), transaction); - } + System.out.println("newObjects:"); + for (Entry<CDOID, CDOObject> entry : transaction2.getNewObjects().entrySet()) + { + System.out.println(" " + entry + ", state: " + entry.getValue().cdoState()); + assertNew(entry.getValue(), transaction2); + } - // Fetch the persisted resource that has the same URI - CDOResource resource1 = (CDOResource)transaction.getObject(resourceID); - msg("Persisted resource: " + resource1); + System.out.println("resources:"); + for (Resource resource : transaction2.getResourceSet().getResources()) + { + System.out.println(" " + resource); + } - msg("newObjects:"); - for (Entry<CDOID, CDOObject> entry : transaction.getNewObjects().entrySet()) - { - msg(" " + entry + ", state: " + entry.getValue().cdoState()); - assertNew(entry.getValue(), transaction); - } + // Fetch the persisted resource that has the same URI + CDOResource resourceA2 = (CDOResource)transaction2.getObject(resourceA.cdoID()); + System.out.println("Remote resource: " + resourceA2); + System.out.println("Local resource: " + resourceB2); - transaction.commit(); + System.out.println("newObjects:"); + for (Entry<CDOID, CDOObject> entry : transaction2.getNewObjects().entrySet()) + { + System.out.println(" " + entry + ", state: " + entry.getValue().cdoState()); + assertNew(entry.getValue(), transaction2); } + + System.out.println("resources:"); + for (Resource resource : transaction2.getResourceSet().getResources()) + { + System.out.println(" " + resource); + } + + transaction2.commit(); } public void testRename() throws CommitException diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/eresource/CDOResourceNode.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/eresource/CDOResourceNode.java index bcb9068078..b1ce8ba26f 100644 --- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/eresource/CDOResourceNode.java +++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/eresource/CDOResourceNode.java @@ -144,12 +144,32 @@ public interface CDOResourceNode extends CDOObject /** * @ADDED + * @since 4.7 + */ + public void setExtension(String extension); + + /** + * Same as {@link #getBasename()}. + * + * @ADDED * @since 4.4 */ public String trimExtension(); /** * @ADDED + * @since 4.7 + */ + public String getBasename(); + + /** + * @ADDED + * @since 4.7 + */ + public void setBasename(String basename); + + /** + * @ADDED */ public URI getURI(); diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/eresource/impl/CDOResourceNodeImpl.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/eresource/impl/CDOResourceNodeImpl.java index 40eb6ebf6b..acfaf96dc8 100644 --- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/eresource/impl/CDOResourceNodeImpl.java +++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/eresource/impl/CDOResourceNodeImpl.java @@ -24,7 +24,10 @@ import org.eclipse.emf.cdo.util.CDOURIUtil; import org.eclipse.emf.internal.cdo.CDOObjectImpl; import org.eclipse.emf.internal.cdo.messages.Messages; +import org.eclipse.net4j.util.CheckUtil; import org.eclipse.net4j.util.ObjectUtil; +import org.eclipse.net4j.util.StringUtil; +import org.eclipse.net4j.util.om.OMPlatform; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.EClass; @@ -52,6 +55,12 @@ import java.util.List; */ public abstract class CDOResourceNodeImpl extends CDOObjectImpl implements CDOResourceNode { + private static final boolean disableNameChecks = OMPlatform.INSTANCE.isProperty("org.eclipse.emf.cdo.CDOResourceNode.disableNameChecks"); + + private static final boolean singleExtensions = OMPlatform.INSTANCE.isProperty("org.eclipse.emf.cdo.CDOResourceNode.singleExtensions"); + + private static final ExtensionFinder EXTENSION_FINDER = singleExtensions ? new ExtensionFinder.Single() : new ExtensionFinder.Multi(); + /** * <!-- begin-user-doc --> <!-- end-user-doc --> * @generated @@ -171,6 +180,14 @@ public abstract class CDOResourceNodeImpl extends CDOObjectImpl implements CDORe */ public void basicSetName(String newName, boolean checkDuplicates) { + if (!disableNameChecks) + { + CheckUtil.checkArg(newName, "Name is null"); + CheckUtil.checkArg(newName.length() != 0, "Name is empty"); + CheckUtil.checkArg(!".".equals(newName), "Name is a dot"); + CheckUtil.checkArg(newName.indexOf(CDOURIUtil.SEGMENT_SEPARATOR_CHAR) == -1, "Name contains a path separator"); + } + String oldName = getName(); if (!ObjectUtil.equals(oldName, newName)) { @@ -251,33 +268,141 @@ public abstract class CDOResourceNodeImpl extends CDOObjectImpl implements CDORe public String getExtension() { String name = getName(); - - int lastDot = name.lastIndexOf('.'); - if (lastDot != -1) + if (name != null) { - return name.substring(lastDot + 1); + int dot = EXTENSION_FINDER.findExtension(name); + if (dot != -1) + { + return name.substring(dot + 1); + } } return ""; } /** + * @since 4.7 + */ + public void setExtension(String extension) + { + InternalCDOView view = cdoView(); + if (view != null) + { + synchronized (view.getViewMonitor()) + { + view.lockView(); + + try + { + setExtensionSynced(extension); + } + finally + { + view.unlockView(); + } + } + } + else + { + setExtensionSynced(extension); + } + } + + private void setExtensionSynced(String extension) + { + if (StringUtil.isEmpty(extension)) + { + setName(getBasename()); + } + else + { + if (singleExtensions) + { + CheckUtil.checkArg(extension.indexOf(ExtensionFinder.DOT) == -1, "Extension contains a dot"); + } + + setName(getBasename() + ExtensionFinder.DOT + extension); + } + } + + /** * @since 4.4 */ public String trimExtension() { - String name = getName(); + return getBasename(); + } - int lastDot = name.lastIndexOf('.'); - if (lastDot != -1) + /** + * @since 4.7 + */ + public String getBasename() + { + String name = getName(); + if (name != null) { - return name.substring(0, lastDot); + int dot = EXTENSION_FINDER.findExtension(name); + if (dot != -1) + { + return name.substring(0, dot); + } } return name; } /** + * @since 4.7 + */ + public void setBasename(String basename) + { + InternalCDOView view = cdoView(); + if (view != null) + { + synchronized (view.getViewMonitor()) + { + view.lockView(); + + try + { + setBasenameSynced(basename); + } + finally + { + view.unlockView(); + } + } + } + else + { + setBasenameSynced(basename); + } + } + + private void setBasenameSynced(String basename) + { + if (basename == null) + { + basename = StringUtil.EMPTY; + } + + if (!singleExtensions) + { + CheckUtil.checkArg(basename.indexOf(ExtensionFinder.DOT) == -1, "Basename contains a dot"); + } + + String extension = getExtension(); + if (StringUtil.isEmpty(extension)) + { + setName(basename); + } + else + { + setName(basename + ExtensionFinder.DOT + extension); + } + } + + /** * @ADDED */ public URI getURI() @@ -377,4 +502,35 @@ public abstract class CDOResourceNodeImpl extends CDOObjectImpl implements CDORe return string; } + /** + * @author Eike Stepper + */ + private interface ExtensionFinder + { + public static final char DOT = '.'; + + public int findExtension(String name); + + /** + * @author Eike Stepper + */ + public static final class Single implements ExtensionFinder + { + public int findExtension(String name) + { + return name.lastIndexOf(DOT); + } + } + + /** + * @author Eike Stepper + */ + public static final class Multi implements ExtensionFinder + { + public int findExtension(String name) + { + return name.indexOf(DOT); + } + } + } } // CDOResourceNodeImpl diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/transaction/CDOTransactionImpl.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/transaction/CDOTransactionImpl.java index 9532476c2a..df136ab159 100644 --- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/transaction/CDOTransactionImpl.java +++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/transaction/CDOTransactionImpl.java @@ -3725,6 +3725,24 @@ public class CDOTransactionImpl extends CDOViewImpl implements InternalCDOTransa } } + @Override + protected Map<String, CDOResourceNode> collectNewResourceNodes() + { + Map<String, CDOResourceNode> result = new HashMap<String, CDOResourceNode>(); + + for (CDOObject object : getNewObjects().values()) + { + if (object instanceof CDOResourceNode) + { + CDOResourceNode node = (CDOResourceNode)object; + String path = node.getPath(); + result.put(path, node); + } + } + + return result; + } + private Set<CDOObject> getObjects(Collection<? extends CDOIdentifiable> identifiables) { Set<CDOObject> result = new HashSet<CDOObject>(); diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/view/AbstractCDOView.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/view/AbstractCDOView.java index 5869873147..7aeb0e396b 100644 --- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/view/AbstractCDOView.java +++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/view/AbstractCDOView.java @@ -152,6 +152,8 @@ public abstract class AbstractCDOView extends CDOCommitHistoryProviderImpl<CDOOb private static final String REPOSITORY_NAME_KEY = "cdo.repository.name"; + private static final String SAFE_RENAME = "~renamed"; + private static final ThreadLocal<Lock> NEXT_VIEW_LOCK = new ThreadLocal<Lock>(); private final ViewAndState[] viewAndStates = ViewAndState.create(this); @@ -2055,16 +2057,11 @@ public abstract class AbstractCDOView extends CDOCommitHistoryProviderImpl<CDOOb URI uri = CDOURIUtil.createResourceURI(this, path); ResourceSet resourceSet = getResourceSet(); - // Bug 334995: Check if locally there is already a resource with the same URI + // Bug 334995: Check if locally there is already a resource with the same URI. CDOResource existingResource = (CDOResource)resourceSet.getResource(uri, false); if (existingResource != null && !isReadOnly()) { - // We have no other option than to change the name of the local resource - String oldName = existingResource.getName(); - existingResource.setName(oldName + ".renamed"); - - OM.LOG.warn("URI clash: resource being instantiated had same URI as a resource already present " + "locally; local resource was renamed from " + oldName - + " to " + existingResource.getName()); + preventURIClash(existingResource); } return getResource(path, true); @@ -2660,7 +2657,7 @@ public abstract class AbstractCDOView extends CDOCommitHistoryProviderImpl<CDOOb } /* - * Synchronized through InvalidationRunner.run() + * Synchronized through CDOViewImpl.ViewInvalidation.run(). */ protected Map<CDOObject, Pair<CDORevision, CDORevisionDelta>> invalidate( // List<CDORevisionKey> allChangedObjects, // @@ -2699,6 +2696,7 @@ public abstract class AbstractCDOView extends CDOCommitHistoryProviderImpl<CDOOb } } + Map<String, CDOResourceNode> newResourceNodes = null; for (CDORevisionKey key : allChangedObjects) { CDORevisionDelta delta = null; @@ -2729,6 +2727,25 @@ public abstract class AbstractCDOView extends CDOCommitHistoryProviderImpl<CDOOb { if (delta == null || isResourceNodeContainerOrNameChanged(delta)) { + if (!isReadOnly()) + { + if (newResourceNodes == null) + { + newResourceNodes = collectNewResourceNodes(); + } + + CDOResourceNode changedNode = (CDOResourceNode)changedObject; + String path = changedNode.getPath(); + + CDOResourceNode newResourceNode = newResourceNodes.get(path); + if (newResourceNode != null) + { + preventURIClash(newResourceNode); + String oldName = newResourceNode.getBasename(); + newResourceNode.setBasename(oldName + SAFE_RENAME); + } + } + ((CDOResourceNodeImpl)changedObject).recacheURIs(); } } @@ -2764,6 +2781,11 @@ public abstract class AbstractCDOView extends CDOCommitHistoryProviderImpl<CDOOb return false; } + protected Map<String, CDOResourceNode> collectNewResourceNodes() + { + return Collections.emptyMap(); + } + /** * Overridden by {@link CDOTransactionImpl#handleConflicts(long, Map, List)}. */ @@ -3102,6 +3124,18 @@ public abstract class AbstractCDOView extends CDOCommitHistoryProviderImpl<CDOOb return false; } + private static void preventURIClash(CDOResourceNode node) + { + String oldName = node.getName(); + + // We have no other option than to change the name of the local resource. + String oldBasename = node.getBasename(); + node.setBasename(oldBasename + SAFE_RENAME); + + OM.LOG.warn("URI clash: resource being instantiated had same URI as a resource already present locally; local resource was renamed from " // + + oldName + " to " + node.getName()); + } + /** * @author Eike Stepper */ diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/view/CDOViewImpl.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/view/CDOViewImpl.java index 40cf5f71ae..1037eb216e 100644 --- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/view/CDOViewImpl.java +++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/view/CDOViewImpl.java @@ -1120,6 +1120,7 @@ public class CDOViewImpl extends AbstractCDOView implements IExecutorServiceProv public void prefetchRevisions(CDOID id, int depth) { checkArg(depth != CDORevision.DEPTH_NONE, "Prefetch depth must not be zero"); //$NON-NLS-1$ + synchronized (getViewMonitor()) { lockView(); @@ -1159,7 +1160,7 @@ public class CDOViewImpl extends AbstractCDOView implements IExecutorServiceProv /* * Must not by synchronized on the view! */ - public /* synchronized */ void invalidate(ViewInvalidationData invalidationData) + public void invalidate(ViewInvalidationData invalidationData) { if (invalidationData.isAsync()) { |