diff --git a/boms/modeshape-bom-embedded/pom.xml b/boms/modeshape-bom-embedded/pom.xml
index 1889cd32d0..261b727a44 100644
--- a/boms/modeshape-bom-embedded/pom.xml
+++ b/boms/modeshape-bom-embedded/pom.xml
@@ -4,7 +4,7 @@
org.modeshape.bom
modeshape-bom-embedded
- 4.5-SNAPSHOT
+ 4.5.0.1-deg-SNAPSHOT
ModeShape BOM for embedded usage
@@ -84,8 +84,8 @@
- https://repository.jboss.org/nexus/service/local/staging/deploy/maven2/
- https://repository.jboss.org/nexus/content/repositories/snapshots/
+ http://nexus.data-experts.de:8081/nexus/content/repositories/portal/
+ http://nexus.data-experts.de:8081/nexus/content/repositories/portal-snapshot/
- https://repository.jboss.org/nexus/service/local/staging/deploy/maven2/
- https://repository.jboss.org/nexus/content/repositories/snapshots/
+ http://nexus.data-experts.de:8081/nexus/content/repositories/portal/
+ http://nexus.data-experts.de:8081/nexus/content/repositories/portal-snapshot/
2.0
9.0.0.Final
diff --git a/boms/modeshape-bom-remote-client/pom.xml b/boms/modeshape-bom-remote-client/pom.xml
index 181607226a..b848ba046f 100644
--- a/boms/modeshape-bom-remote-client/pom.xml
+++ b/boms/modeshape-bom-remote-client/pom.xml
@@ -4,7 +4,7 @@
org.modeshape.bom
modeshape-bom-remote-client
- 4.5-SNAPSHOT
+ 4.5.0.1-deg-SNAPSHOT
ModeShape BOM for remote REST and JDBC clients
@@ -52,8 +52,8 @@
- https://repository.jboss.org/nexus/service/local/staging/deploy/maven2/
- https://repository.jboss.org/nexus/content/repositories/snapshots/
+ http://nexus.data-experts.de:8081/nexus/content/repositories/portal/
+ http://nexus.data-experts.de:8081/nexus/content/repositories/portal-snapshot/
2.0
diff --git a/checkstyle/pom.xml b/checkstyle/pom.xml
index dec477fc7c..009d38fdf6 100644
--- a/checkstyle/pom.xml
+++ b/checkstyle/pom.xml
@@ -4,7 +4,7 @@
org.modeshape
modeshape-checkstyle
- 4.5-SNAPSHOT
+ 4.5.0.1-deg-SNAPSHOT
ModeShape Checkstyle Rules
Contains the definitions for the ModeShape commons code style and conventions
diff --git a/connectors/modeshape-connector-cmis/pom.xml b/connectors/modeshape-connector-cmis/pom.xml
index f5b4f58981..398be57ac3 100644
--- a/connectors/modeshape-connector-cmis/pom.xml
+++ b/connectors/modeshape-connector-cmis/pom.xml
@@ -4,7 +4,7 @@
org.modeshape
modeshape-connectors
- 4.5-SNAPSHOT
+ 4.5.0.1-deg-SNAPSHOT
../pom.xml
diff --git a/connectors/modeshape-connector-git/pom.xml b/connectors/modeshape-connector-git/pom.xml
index cd18829b8c..b80620a732 100644
--- a/connectors/modeshape-connector-git/pom.xml
+++ b/connectors/modeshape-connector-git/pom.xml
@@ -4,7 +4,7 @@
org.modeshape
modeshape-connectors
- 4.5-SNAPSHOT
+ 4.5.0.1-deg-SNAPSHOT
../pom.xml
diff --git a/connectors/modeshape-connector-jdbc-metadata/pom.xml b/connectors/modeshape-connector-jdbc-metadata/pom.xml
index eef2e8b682..12ee86b875 100644
--- a/connectors/modeshape-connector-jdbc-metadata/pom.xml
+++ b/connectors/modeshape-connector-jdbc-metadata/pom.xml
@@ -4,7 +4,7 @@
org.modeshape
modeshape-connectors
- 4.5-SNAPSHOT
+ 4.5.0.1-deg-SNAPSHOT
../pom.xml
diff --git a/connectors/pom.xml b/connectors/pom.xml
index 4c2224eb7b..ed905e220f 100644
--- a/connectors/pom.xml
+++ b/connectors/pom.xml
@@ -4,7 +4,7 @@
org.modeshape
modeshape-parent
- 4.5-SNAPSHOT
+ 4.5.0.1-deg-SNAPSHOT
../modeshape-parent/pom.xml
diff --git a/demos/embedded-repo/pom.xml b/demos/embedded-repo/pom.xml
index c7380efa6d..67f2ed0655 100644
--- a/demos/embedded-repo/pom.xml
+++ b/demos/embedded-repo/pom.xml
@@ -4,7 +4,7 @@
org.modeshape
modeshape-parent
- 4.5-SNAPSHOT
+ 4.5.0.1-deg-SNAPSHOT
../../modeshape-parent
diff --git a/demos/pom.xml b/demos/pom.xml
index bdf54bf1e6..6d2fc6012e 100644
--- a/demos/pom.xml
+++ b/demos/pom.xml
@@ -3,7 +3,7 @@
org.modeshape
modeshape-parent
- 4.5-SNAPSHOT
+ 4.5.0.1-deg-SNAPSHOT
../modeshape-parent
diff --git a/demos/sequencers/pom.xml b/demos/sequencers/pom.xml
index 5ccb70ea92..d631dfd29e 100644
--- a/demos/sequencers/pom.xml
+++ b/demos/sequencers/pom.xml
@@ -4,7 +4,7 @@
org.modeshape
modeshape-parent
- 4.5-SNAPSHOT
+ 4.5.0.1-deg-SNAPSHOT
../../modeshape-parent/pom.xml
diff --git a/deploy/jbossas/modeshape-jbossas-cmis-war/pom.xml b/deploy/jbossas/modeshape-jbossas-cmis-war/pom.xml
index 44029c5db0..eecb688b05 100644
--- a/deploy/jbossas/modeshape-jbossas-cmis-war/pom.xml
+++ b/deploy/jbossas/modeshape-jbossas-cmis-war/pom.xml
@@ -4,7 +4,7 @@
org.modeshape
modeshape-parent
- 4.5-SNAPSHOT
+ 4.5.0.1-deg-SNAPSHOT
../../../modeshape-parent/pom.xml
modeshape-jbossas-cmis-war
diff --git a/deploy/jbossas/modeshape-jbossas-explorer-war/pom.xml b/deploy/jbossas/modeshape-jbossas-explorer-war/pom.xml
index e0928312cf..b549bc0625 100644
--- a/deploy/jbossas/modeshape-jbossas-explorer-war/pom.xml
+++ b/deploy/jbossas/modeshape-jbossas-explorer-war/pom.xml
@@ -4,7 +4,7 @@
org.modeshape
modeshape-parent
- 4.5-SNAPSHOT
+ 4.5.0.1-deg-SNAPSHOT
../../../modeshape-parent/pom.xml
modeshape-jbossas-explorer-war
diff --git a/deploy/jbossas/modeshape-jbossas-subsystem/pom.xml b/deploy/jbossas/modeshape-jbossas-subsystem/pom.xml
index 0293909bb5..740632ad4a 100644
--- a/deploy/jbossas/modeshape-jbossas-subsystem/pom.xml
+++ b/deploy/jbossas/modeshape-jbossas-subsystem/pom.xml
@@ -4,7 +4,7 @@
org.modeshape
modeshape-parent
- 4.5-SNAPSHOT
+ 4.5.0.1-deg-SNAPSHOT
../../../modeshape-parent/pom.xml
diff --git a/deploy/jbossas/modeshape-jbossas-web-rest-war/pom.xml b/deploy/jbossas/modeshape-jbossas-web-rest-war/pom.xml
index 258046d0e6..29ac3b3502 100644
--- a/deploy/jbossas/modeshape-jbossas-web-rest-war/pom.xml
+++ b/deploy/jbossas/modeshape-jbossas-web-rest-war/pom.xml
@@ -4,7 +4,7 @@
org.modeshape
modeshape-parent
- 4.5-SNAPSHOT
+ 4.5.0.1-deg-SNAPSHOT
../../../modeshape-parent/pom.xml
modeshape-jbossas-web-rest-war
diff --git a/deploy/jbossas/modeshape-jbossas-web-webdav-war/pom.xml b/deploy/jbossas/modeshape-jbossas-web-webdav-war/pom.xml
index 0b87906878..6a76b3419d 100644
--- a/deploy/jbossas/modeshape-jbossas-web-webdav-war/pom.xml
+++ b/deploy/jbossas/modeshape-jbossas-web-webdav-war/pom.xml
@@ -4,7 +4,7 @@
org.modeshape
modeshape-parent
- 4.5-SNAPSHOT
+ 4.5.0.1-deg-SNAPSHOT
../../../modeshape-parent/pom.xml
modeshape-jbossas-web-webdav-war
diff --git a/deploy/jbossas/pom.xml b/deploy/jbossas/pom.xml
index ad9b297c63..9a0d25383a 100644
--- a/deploy/jbossas/pom.xml
+++ b/deploy/jbossas/pom.xml
@@ -4,7 +4,7 @@
org.modeshape
modeshape-parent
- 4.5-SNAPSHOT
+ 4.5.0.1-deg-SNAPSHOT
../../modeshape-parent/pom.xml
pom
diff --git a/deploy/pom.xml b/deploy/pom.xml
index fdd65def28..093486f86a 100644
--- a/deploy/pom.xml
+++ b/deploy/pom.xml
@@ -3,7 +3,7 @@
org.modeshape
modeshape-parent
- 4.5-SNAPSHOT
+ 4.5.0.1-deg-SNAPSHOT
../modeshape-parent
diff --git a/extractors/modeshape-extractor-tika/pom.xml b/extractors/modeshape-extractor-tika/pom.xml
index e70308da1c..409d40c878 100644
--- a/extractors/modeshape-extractor-tika/pom.xml
+++ b/extractors/modeshape-extractor-tika/pom.xml
@@ -4,7 +4,7 @@
org.modeshape
modeshape-extractors
- 4.5-SNAPSHOT
+ 4.5.0.1-deg-SNAPSHOT
../pom.xml
diff --git a/extractors/pom.xml b/extractors/pom.xml
index be186048bd..ab3530f5fe 100644
--- a/extractors/pom.xml
+++ b/extractors/pom.xml
@@ -4,7 +4,7 @@
org.modeshape
modeshape-parent
- 4.5-SNAPSHOT
+ 4.5.0.1-deg-SNAPSHOT
../modeshape-parent/pom.xml
diff --git a/index-providers/modeshape-lucene-index-provider/pom.xml b/index-providers/modeshape-lucene-index-provider/pom.xml
index 8e362b97ed..014a72652c 100644
--- a/index-providers/modeshape-lucene-index-provider/pom.xml
+++ b/index-providers/modeshape-lucene-index-provider/pom.xml
@@ -4,7 +4,7 @@
org.modeshape
modeshape-index-providers
- 4.5-SNAPSHOT
+ 4.5.0.1-deg-SNAPSHOT
../pom.xml
diff --git a/index-providers/modeshape-lucene-index-provider/src/main/java/org/modeshape/jcr/index/lucene/MultiColumnIndex.java b/index-providers/modeshape-lucene-index-provider/src/main/java/org/modeshape/jcr/index/lucene/MultiColumnIndex.java
index 0431ae2109..d2229d163f 100644
--- a/index-providers/modeshape-lucene-index-provider/src/main/java/org/modeshape/jcr/index/lucene/MultiColumnIndex.java
+++ b/index-providers/modeshape-lucene-index-provider/src/main/java/org/modeshape/jcr/index/lucene/MultiColumnIndex.java
@@ -16,12 +16,20 @@
package org.modeshape.jcr.index.lucene;
import java.io.IOException;
+import java.util.Arrays;
import java.util.HashSet;
-import java.util.Iterator;
+import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.lucene.document.Document;
+import org.apache.lucene.document.DoubleField;
+import org.apache.lucene.document.Field;
+import org.apache.lucene.document.IntField;
+import org.apache.lucene.document.LongField;
+import org.apache.lucene.document.StringField;
import org.apache.lucene.index.IndexableField;
+import org.apache.lucene.index.Term;
+import org.apache.lucene.util.BytesRef;
import org.modeshape.common.annotation.Immutable;
import org.modeshape.common.annotation.ThreadSafe;
import org.modeshape.common.util.CheckArg;
@@ -69,13 +77,18 @@ public void add( final String nodeKey, final String propertyName, final Object[]
// we're updating an existing document
logger.debug("Updating the property '{0}' of document '{1}' in the Lucene index '{2}' with the values '{3}'", values,
propertyName, nodeKey, name, values);
-
- Document document = searcher.loadDocumentById(nodeKey);
- // remove the old values for the property from the document
- removeProperty(propertyName, document);
- // add the new values
- addProperty(nodeKey, document, propertyName, values);
- writer.updateDocument(FieldUtil.idTerm(nodeKey), document);
+ // load the existing document
+ Document oldDocument = searcher.loadDocumentById(nodeKey);
+
+ //clone the old document without the property we're updating...
+ Document newDocument = clone(oldDocument, propertyName);
+
+ //add the fields for the new property
+ List fields = valuesToFields(propertyName, values);
+ for (Field field : fields) {
+ newDocument.add(field);
+ }
+ writer.updateDocument(FieldUtil.idTerm(nodeKey), newDocument);
} else {
// we're creating the document for the first time...
logger.debug("Adding the document '{0}' in the Lucene Index '{1}' with the property '{2}' and values '{3}",
@@ -90,6 +103,49 @@ public void add( final String nodeKey, final String propertyName, final Object[]
throw new LuceneIndexException(e);
}
}
+
+ private Document clone(Document oldDocument, String... excludeProps) {
+ List excluded = Arrays.asList(excludeProps);
+
+ Document newDocument = new Document();
+ for (IndexableField indexableField : oldDocument) {
+ Field oldField = (Field) indexableField;
+ String name = oldField.name();
+ if (excluded.contains(name)) {
+ continue;
+ }
+ Field newField = clone(oldField);
+ newDocument.add(newField);
+ }
+ return newDocument;
+ }
+
+ private Field clone(Field existing) {
+ String name = existing.name();
+
+ if (name.startsWith(FieldUtil.LENGTH_PREFIX)) {
+ // these are always stored as longs
+ return new LongField(name, Long.valueOf(existing.stringValue()), Field.Store.YES);
+ }
+ Number numberValue = existing.numericValue();
+ if (numberValue instanceof Integer) {
+ return new IntField(name, numberValue.intValue(), Field.Store.YES);
+ } else if (numberValue instanceof Long) {
+ return new LongField(name, numberValue.longValue(), Field.Store.YES);
+ } else if (numberValue instanceof Double) {
+ return new DoubleField(name, numberValue.doubleValue(), Field.Store.YES);
+ }
+ String stringValue = existing.stringValue();
+ if (stringValue != null) {
+ return new StringField(name, stringValue, Field.Store.YES);
+ }
+ BytesRef bytesRef = existing.binaryValue();
+ if (bytesRef != null) {
+ // we don't really store any binary fields
+ return new StringField(name, bytesRef, Field.Store.YES);
+ }
+ throw new LuceneIndexException("Cannot clone existing field: " + existing);
+ }
@Override
protected void preCommit( Map commitData ) {
@@ -108,16 +164,20 @@ protected void remove(final String nodeKey, final String propertyName) {
}
try {
Document document = searcher.loadDocumentById(nodeKey);
- removeProperty(propertyName, document);
- if (document.getFields().isEmpty()) {
+ boolean hasProperty = document.getField(propertyName) != null;
+ if (!hasProperty) {
+ return;
+ }
+ Term idTerm = FieldUtil.idTerm(nodeKey);
+ if (document.getFields().size() == 1) {
// there are no more fields, so remove the entire document....
- writer.deleteDocuments(FieldUtil.idTerm(nodeKey));
+ writer.deleteDocuments(idTerm);
// mark the node key as removed
cache.remove(nodeKey);
} else {
- // update the document after adding back the ID (which was removed during removeProperty)
- document.add(FieldUtil.idField(nodeKey));
- writer.updateDocument(FieldUtil.idTerm(nodeKey), document);
+ // create a clone without the property
+ Document newDocument = clone(document, propertyName);
+ writer.updateDocument(idTerm, newDocument);
}
} catch (IOException e) {
throw new LuceneIndexException(e);
@@ -141,21 +201,6 @@ private boolean documentExists( String nodeKey ) {
return cache.hasNode(nodeKey) || writer.getCommitData().containsKey(nodeKey);
}
- private void removeProperty( String propertyName, Document document ) {
- Iterator fieldIterator = document.iterator();
- while (fieldIterator.hasNext()) {
- IndexableField field = fieldIterator.next();
- String name = field.name();
- if (name.equals(propertyName)) {
- // there can be multiple properties with the same name (multivalued) so we need to call remove for each one
- fieldIterator.remove();
- } else if (FieldUtil.ID.equals(name)) {
- // for some inexplicable reason (Lucene bug ??) this has to be removed and readded with each update
- fieldIterator.remove();
- }
- }
- }
-
/**
* A simple holder which tracks for each index writer session the document keys which exist in the index
* and then writes this information in the commit data. This avoids the document searching required when updating the column
diff --git a/index-providers/modeshape-lucene-index-provider/src/test/java/org/modeshape/jcr/index/lucene/LuceneIndexProviderTest.java b/index-providers/modeshape-lucene-index-provider/src/test/java/org/modeshape/jcr/index/lucene/LuceneIndexProviderTest.java
index 95771e078e..8b3123e58a 100644
--- a/index-providers/modeshape-lucene-index-provider/src/test/java/org/modeshape/jcr/index/lucene/LuceneIndexProviderTest.java
+++ b/index-providers/modeshape-lucene-index-provider/src/test/java/org/modeshape/jcr/index/lucene/LuceneIndexProviderTest.java
@@ -21,6 +21,7 @@
import javax.jcr.Node;
import javax.jcr.PropertyType;
import org.junit.Test;
+import org.modeshape.common.FixFor;
import org.modeshape.jcr.LocalIndexProviderTest;
import org.modeshape.jcr.api.JcrTools;
import org.modeshape.jcr.api.index.IndexDefinition;
@@ -52,6 +53,7 @@ protected String providerName() {
}
@Test
+ @FixFor( "MODE-2520" )
public void shouldUseMultiColumnIndex() throws Exception {
registerNodeType("nt:testType");
Map properties = new HashMap<>();
diff --git a/index-providers/pom.xml b/index-providers/pom.xml
index 9e85469d7b..6cf591ee2c 100644
--- a/index-providers/pom.xml
+++ b/index-providers/pom.xml
@@ -4,7 +4,7 @@
org.modeshape
modeshape-parent
- 4.5-SNAPSHOT
+ 4.5.0.1-deg-SNAPSHOT
../modeshape-parent/pom.xml
diff --git a/integration/modeshape-jbossas-integration-tests/pom.xml b/integration/modeshape-jbossas-integration-tests/pom.xml
index 986d4b8934..1ce442b279 100644
--- a/integration/modeshape-jbossas-integration-tests/pom.xml
+++ b/integration/modeshape-jbossas-integration-tests/pom.xml
@@ -5,7 +5,7 @@
org.modeshape
modeshape-parent
- 4.5-SNAPSHOT
+ 4.5.0.1-deg-SNAPSHOT
../../modeshape-parent/pom.xml
diff --git a/integration/modeshape-jbossas-kit-tests/pom.xml b/integration/modeshape-jbossas-kit-tests/pom.xml
index 62df3bbc9d..3798aa3c14 100644
--- a/integration/modeshape-jbossas-kit-tests/pom.xml
+++ b/integration/modeshape-jbossas-kit-tests/pom.xml
@@ -5,7 +5,7 @@
org.modeshape
modeshape-parent
- 4.5-SNAPSHOT
+ 4.5.0.1-deg-SNAPSHOT
../../modeshape-parent/pom.xml
diff --git a/integration/pom.xml b/integration/pom.xml
index 6bef1b06a0..546d82e7cf 100644
--- a/integration/pom.xml
+++ b/integration/pom.xml
@@ -4,7 +4,7 @@
org.modeshape
modeshape-parent
- 4.5-SNAPSHOT
+ 4.5.0.1-deg-SNAPSHOT
../modeshape-parent
diff --git a/modeshape-assembly-descriptors/pom.xml b/modeshape-assembly-descriptors/pom.xml
index 930be25450..a09a12c96f 100644
--- a/modeshape-assembly-descriptors/pom.xml
+++ b/modeshape-assembly-descriptors/pom.xml
@@ -6,7 +6,7 @@
org.modeshape
modeshape-parent
- 4.5-SNAPSHOT
+ 4.5.0.1-deg-SNAPSHOT
../modeshape-parent/pom.xml
diff --git a/modeshape-client/pom.xml b/modeshape-client/pom.xml
index 43557a8fc2..2ee7edc10c 100644
--- a/modeshape-client/pom.xml
+++ b/modeshape-client/pom.xml
@@ -6,7 +6,7 @@
org.modeshape
modeshape-parent
- 4.5-SNAPSHOT
+ 4.5.0.1-deg-SNAPSHOT
../modeshape-parent/pom.xml
diff --git a/modeshape-common/pom.xml b/modeshape-common/pom.xml
index 90f57cd404..187e2e02f3 100644
--- a/modeshape-common/pom.xml
+++ b/modeshape-common/pom.xml
@@ -5,7 +5,7 @@
org.modeshape
modeshape-parent
- 4.5-SNAPSHOT
+ 4.5.0.1-deg-SNAPSHOT
../modeshape-parent/pom.xml
diff --git a/modeshape-distribution/pom.xml b/modeshape-distribution/pom.xml
index 00775904e6..7adc910ed3 100644
--- a/modeshape-distribution/pom.xml
+++ b/modeshape-distribution/pom.xml
@@ -6,7 +6,7 @@
org.modeshape
modeshape-parent
- 4.5-SNAPSHOT
+ 4.5.0.1-deg-SNAPSHOT
../modeshape-parent/pom.xml
diff --git a/modeshape-jca-rar/pom.xml b/modeshape-jca-rar/pom.xml
index 391c69a4f0..9fdab0861d 100644
--- a/modeshape-jca-rar/pom.xml
+++ b/modeshape-jca-rar/pom.xml
@@ -7,7 +7,7 @@
org.modeshape
modeshape-parent
- 4.5-SNAPSHOT
+ 4.5.0.1-deg-SNAPSHOT
../modeshape-parent/pom.xml
diff --git a/modeshape-jca/pom.xml b/modeshape-jca/pom.xml
index 7cf69a80d6..04020585a0 100644
--- a/modeshape-jca/pom.xml
+++ b/modeshape-jca/pom.xml
@@ -7,7 +7,7 @@
org.modeshape
modeshape-parent
- 4.5-SNAPSHOT
+ 4.5.0.1-deg-SNAPSHOT
../modeshape-parent/pom.xml
diff --git a/modeshape-jcr-api/pom.xml b/modeshape-jcr-api/pom.xml
index cabbbaad9c..286232432c 100644
--- a/modeshape-jcr-api/pom.xml
+++ b/modeshape-jcr-api/pom.xml
@@ -6,7 +6,7 @@
org.modeshape
modeshape-parent
- 4.5-SNAPSHOT
+ 4.5.0.1-deg-SNAPSHOT
../modeshape-parent/pom.xml
diff --git a/modeshape-jcr-tck/pom.xml b/modeshape-jcr-tck/pom.xml
index 63c8c7ca76..bf2a74606d 100644
--- a/modeshape-jcr-tck/pom.xml
+++ b/modeshape-jcr-tck/pom.xml
@@ -6,7 +6,7 @@
org.modeshape
modeshape-parent
- 4.5-SNAPSHOT
+ 4.5.0.1-deg-SNAPSHOT
../modeshape-parent
diff --git a/modeshape-jcr/pom.xml b/modeshape-jcr/pom.xml
index 501d04158e..ce7184f408 100644
--- a/modeshape-jcr/pom.xml
+++ b/modeshape-jcr/pom.xml
@@ -6,7 +6,7 @@
org.modeshape
modeshape-parent
- 4.5-SNAPSHOT
+ 4.5.0.1-deg-SNAPSHOT
../modeshape-parent/pom.xml
diff --git a/modeshape-jcr/src/main/java/org/modeshape/jcr/JcrSession.java b/modeshape-jcr/src/main/java/org/modeshape/jcr/JcrSession.java
index 8025c9f2c3..b4522d0965 100644
--- a/modeshape-jcr/src/main/java/org/modeshape/jcr/JcrSession.java
+++ b/modeshape-jcr/src/main/java/org/modeshape/jcr/JcrSession.java
@@ -2088,8 +2088,8 @@ private void aclMetadataRefresh( long aclChangesCount ) {
}
@Override
- public void process( MutableCachedNode node,
- SaveContext context ) throws Exception {
+ public void processBeforeLocking(MutableCachedNode node,
+ SaveContext context) throws Exception {
// Most nodes do not need any extra processing, so the first thing to do is figure out whether this
// node has a primary type or mixin types that need extra processing. Unfortunately, this means we always have
// to get the primary type and mixin types.
@@ -2114,20 +2114,13 @@ public void process( MutableCachedNode node,
// -----------
// mix:created
// -----------
- boolean initializeVersionHistory = false;
if (node.isNew()) {
if (nodeTypeCapabilities.isCreated(primaryType, mixinTypes)) {
// Set the created by and time information if not changed explicitly
node.setPropertyIfUnchanged(cache, propertyFactory.create(JcrLexicon.CREATED, context.getTime()));
node.setPropertyIfUnchanged(cache, propertyFactory.create(JcrLexicon.CREATED_BY, context.getUserId()));
}
- initializeVersionHistory = nodeTypeCapabilities.isVersionable(primaryType, mixinTypes);
- } else {
- // Changed nodes can only be made versionable if the primary type or mixins changed ...
- if (node.hasChangedPrimaryType() || !node.getAddedMixins(cache).isEmpty()) {
- initializeVersionHistory = nodeTypeCapabilities.isVersionable(primaryType, mixinTypes);
- }
- }
+ }
// ----------------
// mix:lastModified
@@ -2141,44 +2134,14 @@ public void process( MutableCachedNode node,
// ---------------
// mix:versionable
// ---------------
- if (initializeVersionHistory) {
+ if (nodeTypeCapabilities.isVersionable(primaryType, mixinTypes)) {
// See if there is a version history for the node ...
NodeKey versionableKey = node.getKey();
if (!systemContent.hasVersionHistory(versionableKey)) {
- // Initialize the version history ...
- NodeKey historyKey = systemContent.versionHistoryNodeKeyFor(versionableKey);
- NodeKey baseVersionKey = baseVersionKeys == null ? null : baseVersionKeys.get(versionableKey);
- // it may happen during an import, that a node with version history & base version is assigned a new key and
- // therefore
- // the base version points to an existing version while no version history is found initially
- boolean shouldCreateNewVersionHistory = true;
- if (baseVersionKey != null) {
- CachedNode baseVersionNode = systemCache.getNode(baseVersionKey);
- if (baseVersionNode != null) {
- historyKey = baseVersionNode.getParentKey(systemCache);
- shouldCreateNewVersionHistory = (historyKey == null);
- }
- }
- if (shouldCreateNewVersionHistory) {
- // a new version history should be initialized
- assert historyKey != null;
- if (baseVersionKey == null) baseVersionKey = historyKey.withRandomId();
- NodeKey originalVersionKey = originalVersionKeys != null ? originalVersionKeys.get(versionableKey) : null;
- Path versionHistoryPath = versionManager.versionHistoryPathFor(versionableKey);
- systemContent.initializeVersionStorage(versionableKey, historyKey, baseVersionKey, primaryType,
- mixinTypes, versionHistoryPath, originalVersionKey,
- context.getTime());
- }
-
- // Now update the node as if it's checked in (with the exception of the predecessors...)
- Reference historyRef = referenceFactory.create(historyKey, true);
- Reference baseVersionRef = referenceFactory.create(baseVersionKey, true);
- node.setProperty(cache, propertyFactory.create(JcrLexicon.IS_CHECKED_OUT, Boolean.TRUE));
- node.setReference(cache, propertyFactory.create(JcrLexicon.VERSION_HISTORY, historyRef), systemCache);
- node.setReference(cache, propertyFactory.create(JcrLexicon.BASE_VERSION, baseVersionRef), systemCache);
- // JSR 283 - 15.1
- node.setReference(cache, propertyFactory.create(JcrLexicon.PREDECESSORS, new Object[] {baseVersionRef}),
- systemCache);
+ // we have to initialize the version history, but we should only do so after we've locked the 'versionStorage'
+ // root node because initializing the storage implies adding children under it.
+ // So we'll load this node here so that it will be locked later and processed in #processAfterLocking
+ systemContent.mutableVersionStorageNode();
} else {
// we're dealing with node which has a version history, check if there any versionable properties present
boolean hasVersioningProperties = node.hasProperty(JcrLexicon.IS_CHECKED_OUT, cache)
@@ -2356,7 +2319,50 @@ public void processAfterLocking( MutableCachedNode modifiedNode,
// We actually can avoid this altogether if certain conditions are met ...
final Name primaryType = modifiedNode.getPrimaryType(cache);
final Set mixinTypes = modifiedNode.getMixinTypes(cache);
- if (nodeTypeCapabilities.allowsNameSiblings(primaryType, mixinTypes)) return;
+ final NodeKey nodeKey = modifiedNode.getKey();
+
+ if (nodeTypeCapabilities.isVersionable(primaryType, mixinTypes) && !systemContent.hasVersionHistory(nodeKey)) {
+ // Initialize the version history (at this point we should've locked the versionStorage node exclusively)
+ NodeKey historyKey = systemContent.versionHistoryNodeKeyFor(nodeKey);
+ NodeKey baseVersionKey = baseVersionKeys == null ? null : baseVersionKeys.get(nodeKey);
+ // it may happen during an import, that a node with version history & base version is assigned a new key and
+ // therefore
+ // the base version points to an existing version while no version history is found initially
+ boolean shouldCreateNewVersionHistory = true;
+ if (baseVersionKey != null) {
+ CachedNode baseVersionNode = systemCache.getNode(baseVersionKey);
+ if (baseVersionNode != null) {
+ historyKey = baseVersionNode.getParentKey(systemCache);
+ shouldCreateNewVersionHistory = (historyKey == null);
+ }
+ }
+ if (shouldCreateNewVersionHistory) {
+ // a new version history should be initialized
+ assert historyKey != null;
+ if (baseVersionKey == null) {
+ baseVersionKey = historyKey.withRandomId();
+ }
+ NodeKey originalVersionKey = originalVersionKeys != null ? originalVersionKeys.get(nodeKey) : null;
+ Path versionHistoryPath = versionManager.versionHistoryPathFor(nodeKey);
+ systemContent.initializeVersionStorage(nodeKey, historyKey, baseVersionKey, primaryType,
+ mixinTypes, versionHistoryPath, originalVersionKey,
+ context.getTime());
+ }
+
+ // Now update the node as if it's checked in (with the exception of the predecessors...)
+ Reference historyRef = referenceFactory.create(historyKey, true);
+ Reference baseVersionRef = referenceFactory.create(baseVersionKey, true);
+ modifiedNode.setProperty(cache, propertyFactory.create(JcrLexicon.IS_CHECKED_OUT, Boolean.TRUE));
+ modifiedNode.setReference(cache, propertyFactory.create(JcrLexicon.VERSION_HISTORY, historyRef), systemCache);
+ modifiedNode.setReference(cache, propertyFactory.create(JcrLexicon.BASE_VERSION, baseVersionRef), systemCache);
+ // JSR 283 - 15.1
+ modifiedNode.setReference(cache,
+ propertyFactory.create(JcrLexicon.PREDECESSORS, new Object[] { baseVersionRef }),
+ systemCache);
+
+ }
+
+ if (modifiedNode.isNew() || nodeTypeCapabilities.allowsNameSiblings(primaryType, mixinTypes)) return;
MutableCachedNode.NodeChanges changes = modifiedNode.getNodeChanges();
Map appendedOrRenamedChildrenByKey = new HashMap<>();
diff --git a/modeshape-jcr/src/main/java/org/modeshape/jcr/NodeTypes.java b/modeshape-jcr/src/main/java/org/modeshape/jcr/NodeTypes.java
index b18f37d401..5507e67db0 100644
--- a/modeshape-jcr/src/main/java/org/modeshape/jcr/NodeTypes.java
+++ b/modeshape-jcr/src/main/java/org/modeshape/jcr/NodeTypes.java
@@ -284,8 +284,7 @@ protected NodeTypes( ExecutionContext context,
}
Collection allChildNodeDefinitions = nodeType.allChildNodeDefinitions();
if (allChildNodeDefinitions.isEmpty()) nodeTypeNamesWithNoChildNodeDefns.add(name);
- boolean allowsResidualWithSameNameSiblings = false;
- boolean allowsOnlySameNameSiblings = true;
+ boolean allowsSNS = false;
boolean mixinWithNoChildNodeDefinitions = nodeType.isMixin() && allChildNodeDefinitions.isEmpty();
for (JcrNodeDefinition childDefn : allChildNodeDefinitions) {
if (childDefn.isMandatory() && !childDefn.isProtected()) {
@@ -298,17 +297,12 @@ protected NodeTypes( ExecutionContext context,
// fullDefined = false;
}
if (childDefn.allowsSameNameSiblings()) {
- if (childDefn.isResidual()) {
- allowsResidualWithSameNameSiblings = true;
- }
- } else {
- // same name siblings are not allowed ...
- allowsOnlySameNameSiblings = false;
+ allowsSNS = true;
}
}
if (!nodeType.isAbstract()
&& !isUnorderedCollection
- && (allowsResidualWithSameNameSiblings || allowsOnlySameNameSiblings || mixinWithNoChildNodeDefinitions)) {
+ && (allowsSNS || mixinWithNoChildNodeDefinitions)) {
nodeTypeNamesThatAllowSameNameSiblings.add(name);
}
diff --git a/modeshape-jcr/src/main/java/org/modeshape/jcr/SystemContentInitializer.java b/modeshape-jcr/src/main/java/org/modeshape/jcr/SystemContentInitializer.java
index 62948458cb..660a53a239 100644
--- a/modeshape-jcr/src/main/java/org/modeshape/jcr/SystemContentInitializer.java
+++ b/modeshape-jcr/src/main/java/org/modeshape/jcr/SystemContentInitializer.java
@@ -51,7 +51,7 @@ public void initialize( SessionCache session,
// Create the "/jcr:system/jcr:versionStorage" node which we don't want to index
MutableCachedNode versionStorage = createNode(session, system, "jcr:versionStorage", JcrLexicon.VERSION_STORAGE, ModeShapeLexicon.VERSION_STORAGE);
- versionStorage.excludeFromSearch();
+ //versionStorage.excludeFromSearch();
// Create the "/jcr:system/mode:namespaces" node ...
namespaces = createNode(session, system, "mode:namespaces", ModeShapeLexicon.NAMESPACES, ModeShapeLexicon.NAMESPACES);
diff --git a/modeshape-jcr/src/main/java/org/modeshape/jcr/cache/SessionCache.java b/modeshape-jcr/src/main/java/org/modeshape/jcr/cache/SessionCache.java
index ffbccc1db4..556017b91a 100644
--- a/modeshape-jcr/src/main/java/org/modeshape/jcr/cache/SessionCache.java
+++ b/modeshape-jcr/src/main/java/org/modeshape/jcr/cache/SessionCache.java
@@ -27,7 +27,9 @@ public interface SessionCache extends NodeCache {
/**
* The context of a save operation, created during each call to {@link #save} and passed to the
- * {@link PreSave#process(MutableCachedNode, SaveContext)} invocations.
+ * {@link PreSave#processBeforeLocking(MutableCachedNode, SaveContext)} or
+ * {@link PreSave#processAfterLocking(MutableCachedNode, SaveContext, NodeCache)}
+ * invocations.
*/
public static interface SaveContext {
/**
@@ -61,8 +63,8 @@ public static interface PreSave {
* @param context the context of the save operation; never null
* @throws Exception if there is a problem during the processing
*/
- void process( MutableCachedNode modifiedOrNewNode,
- SaveContext context ) throws Exception;
+ void processBeforeLocking(MutableCachedNode modifiedOrNewNode,
+ SaveContext context) throws Exception;
/**
* Process the supplied existing node prior to saving the changes but only after the entry corresponding to the key of the
diff --git a/modeshape-jcr/src/main/java/org/modeshape/jcr/cache/document/WritableSessionCache.java b/modeshape-jcr/src/main/java/org/modeshape/jcr/cache/document/WritableSessionCache.java
index 3d3410dc4a..d94dd2b8f8 100644
--- a/modeshape-jcr/src/main/java/org/modeshape/jcr/cache/document/WritableSessionCache.java
+++ b/modeshape-jcr/src/main/java/org/modeshape/jcr/cache/document/WritableSessionCache.java
@@ -444,7 +444,7 @@ protected void save( PreSave preSaveOperation ) {
lock.lock();
// Before we start the transaction, apply the pre-save operations to the new and changed nodes ...
- runPreSaveBeforeTransaction(preSaveOperation);
+ runBeforeLocking(preSaveOperation);
final int numNodes = this.changedNodes.size();
@@ -470,7 +470,7 @@ protected void save( PreSave preSaveOperation ) {
checkForTransaction();
// process after locking
- runPreSaveAfterLocking(preSaveOperation, persistedCache);
+ runAfterLocking(preSaveOperation, persistedCache);
// Now persist the changes ...
logChangesBeingSaved(this.changedNodesInOrder, this.changedNodes, null, null);
@@ -540,27 +540,39 @@ protected void save( PreSave preSaveOperation ) {
txns.updateCache(workspaceCache(), events, txn);
}
- private void runPreSaveBeforeTransaction( PreSave preSaveOperation ) throws Exception {
+ private void runBeforeLocking(PreSave preSaveOperation) throws Exception {
+ runBeforeLocking(preSaveOperation, changedNodesInOrder);
+ }
+
+ private List runBeforeLocking(PreSave preSaveOperation, Collection filter) throws Exception {
+ List nodeKeys = new ArrayList<>();
if (preSaveOperation != null) {
SaveContext saveContext = new BasicSaveContext(context());
for (MutableCachedNode node : this.changedNodes.values()) {
- if (node == REMOVED) {
+ if (node == REMOVED || !filter.contains(node.getKey())) {
continue;
}
checkNodeNotRemovedByAnotherTransaction(node);
- preSaveOperation.process(node, saveContext);
-
+ preSaveOperation.processBeforeLocking(node, saveContext);
+ nodeKeys.add(node.getKey());
}
}
+ return nodeKeys;
+ }
+
+ private void runAfterLocking(PreSave preSaveOperation,
+ NodeCache persistedCache) throws Exception {
+ runAfterLocking(preSaveOperation, persistedCache, changedNodesInOrder);
}
- private void runPreSaveAfterLocking( PreSave preSaveOperation,
- NodeCache persistedCache ) throws Exception {
+ private void runAfterLocking(PreSave preSaveOperation,
+ NodeCache persistedCache,
+ Collection filter) throws Exception {
if (preSaveOperation != null) {
SaveContext saveContext = new BasicSaveContext(context());
for (MutableCachedNode node : this.changedNodes.values()) {
// only process existing nodes that have not been removed
- if (node == REMOVED || node.isNew()) {
+ if (node == REMOVED || !filter.contains(node.getKey())) {
continue;
}
preSaveOperation.processAfterLocking(node, saveContext, persistedCache);
@@ -609,7 +621,7 @@ public void save( SessionCache other,
thatLock.lock();
// Before we start the transaction, apply the pre-save operations to the new and changed nodes ...
- runPreSaveBeforeTransaction(preSaveOperation);
+ runBeforeLocking(preSaveOperation);
final int numNodes = this.changedNodes.size() + that.changedNodes.size();
@@ -639,7 +651,7 @@ public void save( SessionCache other,
that.checkForTransaction();
// process after locking
- runPreSaveAfterLocking(preSaveOperation, thisPersistedCache);
+ runAfterLocking(preSaveOperation, thisPersistedCache);
// Now persist the changes ...
logChangesBeingSaved(this.changedNodesInOrder, this.changedNodes, that.changedNodesInOrder,
@@ -767,21 +779,7 @@ public void save( Set toBeSaved,
thatLock.lock();
// Before we start the transaction, apply the pre-save operations to the new and changed nodes below the path ...
- final List savedNodesInOrder = new LinkedList();
-
- // Before we start the transaction, apply the pre-save operations to the new and changed nodes ...
- if (preSaveOperation != null) {
- SaveContext saveContext = new BasicSaveContext(context());
- for (MutableCachedNode node : this.changedNodes.values()) {
- if (node == REMOVED || !toBeSaved.contains(node.getKey())) {
- continue;
- }
- checkNodeNotRemovedByAnotherTransaction(node);
- preSaveOperation.process(node, saveContext);
- savedNodesInOrder.add(node.getKey());
- }
- }
-
+ final List savedNodesInOrder = runBeforeLocking(preSaveOperation, toBeSaved);
final int numNodes = savedNodesInOrder.size() + that.changedNodesInOrder.size();
int repeat = txns.isCurrentlyInTransaction() ? 1 : MAX_REPEAT_FOR_LOCK_ACQUISITION_TIMEOUT;
@@ -809,15 +807,7 @@ public void save( Set toBeSaved,
// process after locking
// Before we start the transaction, apply the pre-save operations to the new and changed nodes ...
- if (preSaveOperation != null) {
- SaveContext saveContext = new BasicSaveContext(context());
- for (MutableCachedNode node : this.changedNodes.values()) {
- if (node == REMOVED || !toBeSaved.contains(node.getKey())) {
- continue;
- }
- preSaveOperation.processAfterLocking(node, saveContext, thisPersistedCache);
- }
- }
+ runAfterLocking(preSaveOperation, thisPersistedCache, toBeSaved);
// Now persist the changes ...
logChangesBeingSaved(savedNodesInOrder, this.changedNodes, that.changedNodesInOrder, that.changedNodes);
@@ -1018,8 +1008,9 @@ protected ChangeSet persistChanges( Iterable changedNodesInOrder,
translator.addInternalProperties(doc, node.getAddedInternalProperties());
SessionNode mutableParent = mutable(newParent);
+ Name parentPrimaryType = mutableParent.getPrimaryType(this);
Set parentMixinTypes = mutableParent.getMixinTypes(this);
- boolean parentAllowsSNS = nodeTypes != null && nodeTypes.allowsNameSiblings(primaryType, parentMixinTypes);
+ boolean parentAllowsSNS = nodeTypes != null && nodeTypes.allowsNameSiblings(parentPrimaryType, parentMixinTypes);
if (!parentAllowsSNS) {
// if the parent of the *new* node doesn't allow SNS, we can optimize the path lookup by
// looking directly at the parent's appended nodes because:
diff --git a/modeshape-jcr/src/test/java/org/modeshape/jcr/JcrNodeTest.java b/modeshape-jcr/src/test/java/org/modeshape/jcr/JcrNodeTest.java
index 702b7f9964..35ebbfd3ef 100644
--- a/modeshape-jcr/src/test/java/org/modeshape/jcr/JcrNodeTest.java
+++ b/modeshape-jcr/src/test/java/org/modeshape/jcr/JcrNodeTest.java
@@ -871,4 +871,18 @@ public void transientRemovalAndAdditionOfTheSameNodeShouldNotCorruptPaths() thro
//expected
}
}
+
+ @Test
+ @FixFor("MODE-2533")
+ public void shouldCreateSNSBasedOnParentPrimaryType() throws Exception {
+ registerNodeTypes("cnd/nodetypes-with-sns.cnd");
+ Node snsFolder = session.getRootNode().addNode("snsFolder", "cds:SiblingFolder");
+ snsFolder.addNode("cds:sibling", "cds:Sibling");
+ snsFolder.addNode("cds:sibling", "cds:Sibling");
+ assertNode("/snsFolder/cds:sibling[1]");
+ assertNode("/snsFolder/cds:sibling[2]");
+ session.save();
+ assertNode("/snsFolder/cds:sibling[1]");
+ assertNode("/snsFolder/cds:sibling[2]");
+ }
}
diff --git a/modeshape-jcr/src/test/java/org/modeshape/jcr/LocalIndexProviderTest.java b/modeshape-jcr/src/test/java/org/modeshape/jcr/LocalIndexProviderTest.java
index fc0da995b8..952c5c9ebb 100644
--- a/modeshape-jcr/src/test/java/org/modeshape/jcr/LocalIndexProviderTest.java
+++ b/modeshape-jcr/src/test/java/org/modeshape/jcr/LocalIndexProviderTest.java
@@ -1127,10 +1127,6 @@ public void shouldExposeManagedIndexStatuses() throws Exception {
session.save();
assertEquals(IndexManager.IndexStatus.ENABLED, indexManager().getIndexStatus(providerName(), indexName, "default"));
Future reindexingResult = session.getWorkspace().reindexAsync();
- Thread.sleep(10);
- if (!reindexingResult.isDone()) {
- assertEquals(IndexManager.IndexStatus.REINDEXING, indexManager().getIndexStatus(providerName(), indexName, "default"));
- }
assertEquals(true, reindexingResult.get());
assertEquals(IndexManager.IndexStatus.ENABLED, indexManager().getIndexStatus(providerName(), indexName, "default"));
diff --git a/modeshape-jcr/src/test/resources/cnd/nodetypes-with-sns.cnd b/modeshape-jcr/src/test/resources/cnd/nodetypes-with-sns.cnd
index 5c28c0c256..f20a11b6d1 100644
--- a/modeshape-jcr/src/test/resources/cnd/nodetypes-with-sns.cnd
+++ b/modeshape-jcr/src/test/resources/cnd/nodetypes-with-sns.cnd
@@ -1,6 +1,7 @@
+
[inf:patient] > mix:versionable, nt:hierarchyNode
+ * (inf:patientId) COPY
@@ -18,3 +19,12 @@
[inf:patientId]
- inf:name (STRING) mandatory COPY
+
+[cds:Sibling] > nt:folder, mix:referenceable
+ - cds:name (STRING)
+
+[cds:SiblingUnstructured] > nt:unstructured, mix:referenceable
+ + cds:sibling (cds:Sibling) = cds:Sibling sns
+
+[cds:SiblingFolder] > nt:folder, mix:referenceable
+ + cds:sibling (cds:Sibling) = cds:Sibling sns
diff --git a/modeshape-jdbc-local/pom.xml b/modeshape-jdbc-local/pom.xml
index fbdaa79894..4a0062e73a 100644
--- a/modeshape-jdbc-local/pom.xml
+++ b/modeshape-jdbc-local/pom.xml
@@ -6,7 +6,7 @@
org.modeshape
modeshape-parent
- 4.5-SNAPSHOT
+ 4.5.0.1-deg-SNAPSHOT
../modeshape-parent/pom.xml
diff --git a/modeshape-jdbc-local/src/main/java/org/modeshape/jdbc/JcrResultSet.java b/modeshape-jdbc-local/src/main/java/org/modeshape/jdbc/JcrResultSet.java
index 18e6d6c549..a4e14e1e0d 100644
--- a/modeshape-jdbc-local/src/main/java/org/modeshape/jdbc/JcrResultSet.java
+++ b/modeshape-jdbc-local/src/main/java/org/modeshape/jdbc/JcrResultSet.java
@@ -115,14 +115,13 @@ protected JcrResultSet() {
@Override
public boolean isClosed() {
- return closed || statement.isClosed();
+ return closed;
}
@Override
public void close() {
if (!closed) {
closed = true;
- this.statement.close();
}
}
diff --git a/modeshape-jdbc/pom.xml b/modeshape-jdbc/pom.xml
index e534161d31..cedfd5dd67 100644
--- a/modeshape-jdbc/pom.xml
+++ b/modeshape-jdbc/pom.xml
@@ -6,7 +6,7 @@
org.modeshape
modeshape-parent
- 4.5-SNAPSHOT
+ 4.5.0.1-deg-SNAPSHOT
../modeshape-parent/pom.xml
diff --git a/modeshape-jdbc/src/main/java/org/modeshape/jdbc/delegate/HttpQueryResult.java b/modeshape-jdbc/src/main/java/org/modeshape/jdbc/delegate/HttpQueryResult.java
index e7d154ce4c..ad31d8a8f3 100644
--- a/modeshape-jdbc/src/main/java/org/modeshape/jdbc/delegate/HttpQueryResult.java
+++ b/modeshape-jdbc/src/main/java/org/modeshape/jdbc/delegate/HttpQueryResult.java
@@ -13,10 +13,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
package org.modeshape.jdbc.delegate;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.math.BigDecimal;
import java.util.ArrayList;
+import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
@@ -25,30 +29,38 @@
import java.util.NoSuchElementException;
import javax.jcr.Node;
import javax.jcr.NodeIterator;
+import javax.jcr.PropertyType;
+import javax.jcr.RepositoryException;
import javax.jcr.Value;
+import javax.jcr.ValueFormatException;
import javax.jcr.query.Row;
import javax.jcr.query.RowIterator;
import org.modeshape.jcr.api.query.QueryResult;
+import org.modeshape.jdbc.JcrType;
import org.modeshape.jdbc.JdbcJcrValueFactory;
+import org.modeshape.jdbc.rest.JSONRestClient;
+import org.modeshape.jdbc.rest.ModeShapeRestClient;
/**
* A simple implementation of the {@link QueryResult} interface.
- *
+ *
* @author Horia Chiorean
*/
public final class HttpQueryResult implements QueryResult {
protected final List rows = new ArrayList<>();
protected final Map columnTypesByName = new LinkedHashMap<>();
+ private final ModeShapeRestClient restClient;
- protected HttpQueryResult( org.modeshape.jdbc.rest.QueryResult queryResult ) {
+ protected HttpQueryResult(org.modeshape.jdbc.rest.QueryResult queryResult, ModeShapeRestClient restClient) {
assert queryResult != null;
+ this.restClient = restClient;
if (!queryResult.isEmpty()) {
this.columnTypesByName.putAll(queryResult.getColumns());
for (org.modeshape.jdbc.rest.QueryResult.Row queryRow : queryResult) {
- rows.add(new HttpRow(queryRow));
+ rows.add(new HttpRow(queryRow, this.restClient));
}
}
}
@@ -115,7 +127,7 @@ public Row nextRow() {
}
@Override
- public void skip( long skipNum ) {
+ public void skip(long skipNum) {
if (skipNum < 0) {
throw new IllegalArgumentException("skipNum must be a positive value");
}
@@ -153,13 +165,101 @@ public void remove() {
}
private class HttpRow implements Row {
+
private final Map valuesMap = new LinkedHashMap<>();
+ private final ModeShapeRestClient restClient;
- protected HttpRow( org.modeshape.jdbc.rest.QueryResult.Row row ) {
+ protected HttpRow(org.modeshape.jdbc.rest.QueryResult.Row row, ModeShapeRestClient restClient) {
assert row != null;
- for (String columnName : columnTypesByName.keySet()) {
- Object queryRowValue = row.getValue(columnName);
- valuesMap.put(columnName, JdbcJcrValueFactory.createValue(queryRowValue));
+ this.restClient = restClient;
+ for (Map.Entry column : columnTypesByName.entrySet()) {
+ Object queryRowValue = row.getValue(column.getKey());
+ if (column.getValue().equalsIgnoreCase(JcrType.DefaultDataTypes.BINARY) || (queryRowValue != null && queryRowValue.toString().startsWith(restClient.serverUrl()))) {
+ class Binary implements javax.jcr.Value, javax.jcr.Binary {
+
+ private final ModeShapeRestClient restClient;
+ private byte[] data;
+ private final String uri;
+
+ public Binary(ModeShapeRestClient restClient, String uri) {
+ this.restClient = restClient;
+ this.uri = uri;
+ }
+
+ private byte[] getData() {
+ if (data == null) {
+ JSONRestClient.Response doGet = restClient.getJsonRestClient().doGet(uri);
+ if (doGet.isOK()) {
+ data = doGet.getContent();
+ }
+ }
+ return data;
+ }
+
+ @Override
+ public String getString() throws ValueFormatException, IllegalStateException, RepositoryException {
+ return new String(getData());
+ }
+
+ @Override
+ public InputStream getStream() throws RepositoryException {
+ return new ByteArrayInputStream(getData());
+ }
+
+ @Override
+ public javax.jcr.Binary getBinary() throws RepositoryException {
+ return this;
+ }
+
+ @Override
+ public long getLong() throws ValueFormatException, RepositoryException {
+ return getData().length;
+ }
+
+ @Override
+ public double getDouble() throws ValueFormatException, RepositoryException {
+ return getLong();
+ }
+
+ @Override
+ public BigDecimal getDecimal() throws ValueFormatException, RepositoryException {
+ throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ }
+
+ @Override
+ public Calendar getDate() throws ValueFormatException, RepositoryException {
+ throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ }
+
+ @Override
+ public boolean getBoolean() throws ValueFormatException, RepositoryException {
+ throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ }
+
+ @Override
+ public int getType() {
+ return PropertyType.BINARY;
+ }
+
+ @Override
+ public int read(byte[] b, long position) throws IOException, RepositoryException {
+ return getStream().read(b, (int) position, b.length);
+ }
+
+ @Override
+ public long getSize() throws RepositoryException {
+ return getLong();
+ }
+
+ @Override
+ public void dispose() {
+ data = null;
+ }
+ }
+ valuesMap.put(column.getKey(), new Binary(this.restClient, queryRowValue.toString()));
+ } else {
+ valuesMap.put(column.getKey(), JdbcJcrValueFactory.createValue(queryRowValue));
+ }
}
}
@@ -174,12 +274,12 @@ public Value[] getValues() {
}
@Override
- public Value getValue( String columnName ) {
+ public Value getValue(String columnName) {
return valuesMap.get(columnName);
}
@Override
- public Node getNode( String selectorName ) {
+ public Node getNode(String selectorName) {
throw new UnsupportedOperationException("Method getNode(selectorName) not supported");
}
@@ -189,7 +289,7 @@ public String getPath() {
}
@Override
- public String getPath( String selectorName ) {
+ public String getPath(String selectorName) {
throw new UnsupportedOperationException("Method getPath(selectorName) not supported");
}
@@ -199,7 +299,7 @@ public double getScore() {
}
@Override
- public double getScore( String selectorName ) {
+ public double getScore(String selectorName) {
throw new UnsupportedOperationException("Method getScore( String selectorName ) not supported");
}
}
diff --git a/modeshape-jdbc/src/main/java/org/modeshape/jdbc/delegate/HttpRepositoryDelegate.java b/modeshape-jdbc/src/main/java/org/modeshape/jdbc/delegate/HttpRepositoryDelegate.java
index 1050fe7ea1..8096c88177 100644
--- a/modeshape-jdbc/src/main/java/org/modeshape/jdbc/delegate/HttpRepositoryDelegate.java
+++ b/modeshape-jdbc/src/main/java/org/modeshape/jdbc/delegate/HttpRepositoryDelegate.java
@@ -89,7 +89,7 @@ public QueryResult execute( String query,
logger.trace("Executing query: {0}", query);
try {
org.modeshape.jdbc.rest.QueryResult result = this.restClient.query(query, language);
- return new HttpQueryResult(result);
+ return new HttpQueryResult(result, this.restClient);
} catch (Exception e) {
throw new RepositoryException(e.getMessage(), e);
}
diff --git a/modeshape-jdbc/src/main/java/org/modeshape/jdbc/rest/JSONRestClient.java b/modeshape-jdbc/src/main/java/org/modeshape/jdbc/rest/JSONRestClient.java
index 36f8000ead..ee21050947 100644
--- a/modeshape-jdbc/src/main/java/org/modeshape/jdbc/rest/JSONRestClient.java
+++ b/modeshape-jdbc/src/main/java/org/modeshape/jdbc/rest/JSONRestClient.java
@@ -96,7 +96,7 @@ protected Response doGet() {
return new Response(newJSONRequest(HttpGet.class, null, null, null));
}
- protected Response doGet( String url ) {
+ public Response doGet( String url ) {
return new Response(newJSONRequest(HttpGet.class, null, null, url));
}
@@ -191,7 +191,7 @@ protected interface MediaType {
String TEXT_PLAIN = "text/plain;";
}
- protected class Response {
+ public class Response {
private final HttpResponse response;
private byte[] content;
@@ -217,6 +217,10 @@ protected Response( HttpRequestBase request ) {
}
}
+ public byte[] getContent() {
+ return content;
+ }
+
public boolean isOK() {
return hasCode(HttpURLConnection.HTTP_OK);
}
diff --git a/modeshape-jdbc/src/main/java/org/modeshape/jdbc/rest/ModeShapeRestClient.java b/modeshape-jdbc/src/main/java/org/modeshape/jdbc/rest/ModeShapeRestClient.java
index ea56f0719d..e95b80ae20 100644
--- a/modeshape-jdbc/src/main/java/org/modeshape/jdbc/rest/ModeShapeRestClient.java
+++ b/modeshape-jdbc/src/main/java/org/modeshape/jdbc/rest/ModeShapeRestClient.java
@@ -35,6 +35,10 @@ public final class ModeShapeRestClient {
private final JSONRestClient jsonRestClient;
+ public JSONRestClient getJsonRestClient() {
+ return jsonRestClient;
+ }
+
/**
* Creates a new REST client instance which will always use the given URL as the server connection
*
diff --git a/modeshape-parent/pom.xml b/modeshape-parent/pom.xml
index 908f13454e..53e5127df3 100644
--- a/modeshape-parent/pom.xml
+++ b/modeshape-parent/pom.xml
@@ -10,7 +10,7 @@
4.0.0
org.modeshape
modeshape-parent
- 4.5-SNAPSHOT
+ 4.5.0.1-deg-SNAPSHOT
ModeShape Parent
http://www.modeshape.org
@@ -2331,4 +2331,15 @@
+
+
+
+ portal-releases
+ http://nexus.data-experts.de:8081/nexus/content/repositories/portal/
+
+
+ portal-snapshot
+ http://nexus.data-experts.de:8081/nexus/content/repositories/portal-snapshot/
+
+
diff --git a/modeshape-performance-tests/pom.xml b/modeshape-performance-tests/pom.xml
index 329d50165b..868f6b1787 100644
--- a/modeshape-performance-tests/pom.xml
+++ b/modeshape-performance-tests/pom.xml
@@ -6,7 +6,7 @@
org.modeshape
modeshape-parent
- 4.5-SNAPSHOT
+ 4.5.0.1-deg-SNAPSHOT
../modeshape-parent
diff --git a/modeshape-schematic/pom.xml b/modeshape-schematic/pom.xml
index 3d3d3bda45..cd32a42dd6 100644
--- a/modeshape-schematic/pom.xml
+++ b/modeshape-schematic/pom.xml
@@ -6,7 +6,7 @@
org.modeshape
modeshape-parent
- 4.5-SNAPSHOT
+ 4.5.0.1-deg-SNAPSHOT
../modeshape-parent/pom.xml
diff --git a/modeshape-unit-test/pom.xml b/modeshape-unit-test/pom.xml
index 23352cfdba..ab03be052a 100644
--- a/modeshape-unit-test/pom.xml
+++ b/modeshape-unit-test/pom.xml
@@ -6,7 +6,7 @@
org.modeshape
modeshape-parent
- 4.5-SNAPSHOT
+ 4.5.0.1-deg-SNAPSHOT
../modeshape-parent/pom.xml
diff --git a/pom.xml b/pom.xml
index 500a3e5d49..971d241c84 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
org.modeshape
modeshape-parent
- 4.5-SNAPSHOT
+ 4.5.0.1-deg-SNAPSHOT
modeshape-parent/pom.xml
diff --git a/release_notes.md b/release_notes.md
index 30e49fdebc..f6b147d3c6 100644
--- a/release_notes.md
+++ b/release_notes.md
@@ -5,17 +5,24 @@ We hope you enjoy it!
## What's new
-This release addresses 18 bugs and 12 enhancements, most notably:
-- Wildfly 9 support. Starting with this version, the ModeShape AS kit can be run both on Wildfly 8 and Wildly 9.
-
-- Support for large collections of flat nodes. This is a long outstanding enhancement which allows large number of children (>500k)
- to be stored under the same parent node. See [MODE-2109](https://issues.jboss.org/browse/MODE-2109) and [our documentation](https://docs.jboss.org/author/display/MODE40/Large+numbers+of+child+nodes#Largenumbersofchildnodes-Unorderedlargecollections)
- for more information.
-
-- Enhanced look & feel for the Repository Explorer web application, together with a number of bug fixes.
+This release addresses 10 bugs and 7 enhancements, most notably:
+- **Rebuilding indexes incrementally** - prior to this release, ModeShape did not have the ability to rebuild indexes (reindex)
+ from a given point in time, it only supported full reindexing. With this new feature
+ (that requires the [event journal](https://docs.jboss.org/author/display/MODE40/Journaling) to be enabled) the repository is
+ able to reindex nodes from a certain timestamp onwards.
+ This new feature also allows, when running in a cluster, for a cluster
+ node which was previously down to update its indexes automatically by getting the *delta* from the other nodes. In other words,
+ a full reindexing operation is no longer required to bring a cluster node up-to-date index-wise.
+ See [the ModeShape documentation](https://docs.jboss.org/author/display/MODE40/Query+and+search#Queryandsearch-Reindexing) for more information.
+
+- **Storing indexes in Lucene** - this has been a long outstanding feature which was missing in ModeShape 4 ever since the new
+ indexing design was introduced. Starting with this release, in addition to the Local (MapDB based) index provider, it is
+ possible to store indexes and run queries using Lucene 5.
+ See [the ModeShape documentation](https://docs.jboss.org/author/display/MODE40/Lucene) for more information.
+
+- **Allowing CAST as a dynamic operand in queries** - see [this issue](https://issues.jboss.org/browse/MODE-2166) for more information
-- New example of how to use and embed a custom authorization and authentication provider in your own application.
- The example can be found [here](https://github.com/ModeShape/modeshape-examples/tree/4.4.0.Final/modeshape-custom-security-example)
+- **Support custom Locales in queries** - see [this issue](https://issues.jboss.org/browse/MODE-1727) for more information
## Features
diff --git a/sandbox/modeshape-test-reference-impl/pom.xml b/sandbox/modeshape-test-reference-impl/pom.xml
index 3bf0a12285..e64285c36b 100644
--- a/sandbox/modeshape-test-reference-impl/pom.xml
+++ b/sandbox/modeshape-test-reference-impl/pom.xml
@@ -5,7 +5,7 @@
org.modeshape
modeshape-parent
- 4.5-SNAPSHOT
+ 4.5.0.1-deg-SNAPSHOT
../../modeshape-parent
diff --git a/sequencers/modeshape-sequencer-ddl/pom.xml b/sequencers/modeshape-sequencer-ddl/pom.xml
index 7ef818caa6..2c66753678 100644
--- a/sequencers/modeshape-sequencer-ddl/pom.xml
+++ b/sequencers/modeshape-sequencer-ddl/pom.xml
@@ -4,7 +4,7 @@
org.modeshape
modeshape-sequencers
- 4.5-SNAPSHOT
+ 4.5.0.1-deg-SNAPSHOT
../pom.xml
diff --git a/sequencers/modeshape-sequencer-images/pom.xml b/sequencers/modeshape-sequencer-images/pom.xml
index b8ff8b6f4a..186f960d62 100644
--- a/sequencers/modeshape-sequencer-images/pom.xml
+++ b/sequencers/modeshape-sequencer-images/pom.xml
@@ -4,7 +4,7 @@
org.modeshape
modeshape-sequencers
- 4.5-SNAPSHOT
+ 4.5.0.1-deg-SNAPSHOT
../pom.xml
diff --git a/sequencers/modeshape-sequencer-java/pom.xml b/sequencers/modeshape-sequencer-java/pom.xml
index c3aa87b3e6..f79e9cd902 100644
--- a/sequencers/modeshape-sequencer-java/pom.xml
+++ b/sequencers/modeshape-sequencer-java/pom.xml
@@ -4,7 +4,7 @@
org.modeshape
modeshape-sequencers
- 4.5-SNAPSHOT
+ 4.5.0.1-deg-SNAPSHOT
../pom.xml
diff --git a/sequencers/modeshape-sequencer-mp3/pom.xml b/sequencers/modeshape-sequencer-mp3/pom.xml
index 7fbc2966c3..779ad615ed 100644
--- a/sequencers/modeshape-sequencer-mp3/pom.xml
+++ b/sequencers/modeshape-sequencer-mp3/pom.xml
@@ -4,7 +4,7 @@
org.modeshape
modeshape-sequencers
- 4.5-SNAPSHOT
+ 4.5.0.1-deg-SNAPSHOT
../pom.xml
diff --git a/sequencers/modeshape-sequencer-msoffice/pom.xml b/sequencers/modeshape-sequencer-msoffice/pom.xml
index f90c013834..b105b6665f 100644
--- a/sequencers/modeshape-sequencer-msoffice/pom.xml
+++ b/sequencers/modeshape-sequencer-msoffice/pom.xml
@@ -4,7 +4,7 @@
org.modeshape
modeshape-sequencers
- 4.5-SNAPSHOT
+ 4.5.0.1-deg-SNAPSHOT
../pom.xml
diff --git a/sequencers/modeshape-sequencer-sramp/pom.xml b/sequencers/modeshape-sequencer-sramp/pom.xml
index 8f99a5cb8b..bcb6d6d625 100644
--- a/sequencers/modeshape-sequencer-sramp/pom.xml
+++ b/sequencers/modeshape-sequencer-sramp/pom.xml
@@ -4,7 +4,7 @@
org.modeshape
modeshape-sequencers
- 4.5-SNAPSHOT
+ 4.5.0.1-deg-SNAPSHOT
../pom.xml
diff --git a/sequencers/modeshape-sequencer-teiid/pom.xml b/sequencers/modeshape-sequencer-teiid/pom.xml
index 2f5db95608..7a57a68eb4 100644
--- a/sequencers/modeshape-sequencer-teiid/pom.xml
+++ b/sequencers/modeshape-sequencer-teiid/pom.xml
@@ -4,7 +4,7 @@
org.modeshape
modeshape-sequencers
- 4.5-SNAPSHOT
+ 4.5.0.1-deg-SNAPSHOT
../pom.xml
diff --git a/sequencers/modeshape-sequencer-text/pom.xml b/sequencers/modeshape-sequencer-text/pom.xml
index f109609f75..4818439059 100644
--- a/sequencers/modeshape-sequencer-text/pom.xml
+++ b/sequencers/modeshape-sequencer-text/pom.xml
@@ -4,7 +4,7 @@
org.modeshape
modeshape-sequencers
- 4.5-SNAPSHOT
+ 4.5.0.1-deg-SNAPSHOT
../pom.xml
diff --git a/sequencers/modeshape-sequencer-wsdl/pom.xml b/sequencers/modeshape-sequencer-wsdl/pom.xml
index 118afcfc08..d7dbc8e385 100644
--- a/sequencers/modeshape-sequencer-wsdl/pom.xml
+++ b/sequencers/modeshape-sequencer-wsdl/pom.xml
@@ -4,7 +4,7 @@
org.modeshape
modeshape-sequencers
- 4.5-SNAPSHOT
+ 4.5.0.1-deg-SNAPSHOT
../pom.xml
diff --git a/sequencers/modeshape-sequencer-xml/pom.xml b/sequencers/modeshape-sequencer-xml/pom.xml
index 46d06c0bd8..d1252a43e9 100644
--- a/sequencers/modeshape-sequencer-xml/pom.xml
+++ b/sequencers/modeshape-sequencer-xml/pom.xml
@@ -4,7 +4,7 @@
org.modeshape
modeshape-sequencers
- 4.5-SNAPSHOT
+ 4.5.0.1-deg-SNAPSHOT
../pom.xml
diff --git a/sequencers/modeshape-sequencer-xsd/pom.xml b/sequencers/modeshape-sequencer-xsd/pom.xml
index 83b7ba7bee..06abc88073 100644
--- a/sequencers/modeshape-sequencer-xsd/pom.xml
+++ b/sequencers/modeshape-sequencer-xsd/pom.xml
@@ -4,7 +4,7 @@
org.modeshape
modeshape-sequencers
- 4.5-SNAPSHOT
+ 4.5.0.1-deg-SNAPSHOT
../pom.xml
diff --git a/sequencers/modeshape-sequencer-zip/pom.xml b/sequencers/modeshape-sequencer-zip/pom.xml
index 19a0fe0b50..7fb49b0acd 100644
--- a/sequencers/modeshape-sequencer-zip/pom.xml
+++ b/sequencers/modeshape-sequencer-zip/pom.xml
@@ -4,7 +4,7 @@
org.modeshape
modeshape-sequencers
- 4.5-SNAPSHOT
+ 4.5.0.1-deg-SNAPSHOT
../pom.xml
diff --git a/sequencers/pom.xml b/sequencers/pom.xml
index a22de25b27..58767254ee 100644
--- a/sequencers/pom.xml
+++ b/sequencers/pom.xml
@@ -4,7 +4,7 @@
org.modeshape
modeshape-parent
- 4.5-SNAPSHOT
+ 4.5.0.1-deg-SNAPSHOT
../modeshape-parent/pom.xml
diff --git a/web/modeshape-web-cmis-war/pom.xml b/web/modeshape-web-cmis-war/pom.xml
index 8082107758..5242e00ad7 100644
--- a/web/modeshape-web-cmis-war/pom.xml
+++ b/web/modeshape-web-cmis-war/pom.xml
@@ -4,7 +4,7 @@
org.modeshape
modeshape-parent
- 4.5-SNAPSHOT
+ 4.5.0.1-deg-SNAPSHOT
../../modeshape-parent
modeshape-web-cmis-war
diff --git a/web/modeshape-web-cmis/pom.xml b/web/modeshape-web-cmis/pom.xml
index 344f14c072..300e3e97b7 100644
--- a/web/modeshape-web-cmis/pom.xml
+++ b/web/modeshape-web-cmis/pom.xml
@@ -5,7 +5,7 @@
org.modeshape
modeshape-parent
- 4.5-SNAPSHOT
+ 4.5.0.1-deg-SNAPSHOT
../../modeshape-parent
diff --git a/web/modeshape-web-explorer-war/pom.xml b/web/modeshape-web-explorer-war/pom.xml
index 982789d9e8..36891a6a2a 100644
--- a/web/modeshape-web-explorer-war/pom.xml
+++ b/web/modeshape-web-explorer-war/pom.xml
@@ -4,7 +4,7 @@
org.modeshape
modeshape-parent
- 4.5-SNAPSHOT
+ 4.5.0.1-deg-SNAPSHOT
../../modeshape-parent
modeshape-web-explorer-war
diff --git a/web/modeshape-web-explorer/pom.xml b/web/modeshape-web-explorer/pom.xml
index 533fb07fe8..7dfa233c7e 100644
--- a/web/modeshape-web-explorer/pom.xml
+++ b/web/modeshape-web-explorer/pom.xml
@@ -4,7 +4,7 @@
org.modeshape
modeshape-parent
- 4.5-SNAPSHOT
+ 4.5.0.1-deg-SNAPSHOT
../../modeshape-parent
modeshape-web-explorer
diff --git a/web/modeshape-web-jcr-rest-war/pom.xml b/web/modeshape-web-jcr-rest-war/pom.xml
index bffba7c503..318f2c4482 100644
--- a/web/modeshape-web-jcr-rest-war/pom.xml
+++ b/web/modeshape-web-jcr-rest-war/pom.xml
@@ -5,7 +5,7 @@
org.modeshape
modeshape-parent
- 4.5-SNAPSHOT
+ 4.5.0.1-deg-SNAPSHOT
../../modeshape-parent
diff --git a/web/modeshape-web-jcr-rest/pom.xml b/web/modeshape-web-jcr-rest/pom.xml
index 6295144be9..1d9d71e696 100644
--- a/web/modeshape-web-jcr-rest/pom.xml
+++ b/web/modeshape-web-jcr-rest/pom.xml
@@ -5,7 +5,7 @@
org.modeshape
modeshape-parent
- 4.5-SNAPSHOT
+ 4.5.0.1-deg-SNAPSHOT
../../modeshape-parent
@@ -80,6 +80,12 @@
modeshape-jcr
test
+
+ org.modeshape
+ modeshape-unit-test
+ ${project.version}
+ test
+
diff --git a/web/modeshape-web-jcr-rest/src/main/java/org/modeshape/web/jcr/rest/ModeShapeRestService.java b/web/modeshape-web-jcr-rest/src/main/java/org/modeshape/web/jcr/rest/ModeShapeRestService.java
index db80046925..dc2d91d593 100644
--- a/web/modeshape-web-jcr-rest/src/main/java/org/modeshape/web/jcr/rest/ModeShapeRestService.java
+++ b/web/modeshape-web-jcr-rest/src/main/java/org/modeshape/web/jcr/rest/ModeShapeRestService.java
@@ -525,6 +525,7 @@ public Response deleteItems( @Context HttpServletRequest request,
* @param rawRepositoryName the URL-encoded repository name
* @param rawWorkspaceName the URL-encoded workspace name
* @param path the path to the item
+ * @param autoCheckoutCheckin automatic checkout/checkin of Node
* @param requestContent the JSON-encoded representation of the values and, possibly, properties to be set
* @return a {@link RestItem} instance representing the modified item.
* @throws JSONException if there is an error reading the request body as a valid JSON object.
@@ -538,8 +539,9 @@ public RestItem putItem( @Context HttpServletRequest request,
@PathParam( "repositoryName" ) String rawRepositoryName,
@PathParam( "workspaceName" ) String rawWorkspaceName,
@PathParam( "path" ) String path,
+ @QueryParam( "autoCheckoutCheckin" ) @DefaultValue( "true" ) boolean autoCheckoutCheckin,
String requestContent ) throws JSONException, RepositoryException {
- return itemHandler.updateItem(request, rawRepositoryName, rawWorkspaceName, path, requestContent);
+ return itemHandler.updateItem(request, rawRepositoryName, rawWorkspaceName, path,autoCheckoutCheckin, requestContent);
}
/**
@@ -556,11 +558,12 @@ public RestItem putItem( @Context HttpServletRequest request,
* @param request the servlet request; may not be null or unauthenticated
* @param rawRepositoryName the URL-encoded repository name
* @param rawWorkspaceName the URL-encoded workspace name
+ * @param autoCheckoutCheckin automatic checkout/checkin of Node
* @param requestContent the JSON-encoded representation of the values and, possibly, properties to be set
* @return a {@code non-null} {@link Response}
* @throws JSONException if there is an error reading the request body as a valid JSON object.
* @throws RepositoryException if any other error occurs
- * @see ModeShapeRestService#putItem(javax.servlet.http.HttpServletRequest, String, String, String, String)
+ * @see ModeShapeRestService#putItem(javax.servlet.http.HttpServletRequest, String, String, String, boolean, String)
*/
@PUT
@Path( "{repositoryName}/{workspaceName}/" + RestHelper.ITEMS_METHOD_NAME )
@@ -569,8 +572,9 @@ public RestItem putItem( @Context HttpServletRequest request,
public Response putItems( @Context HttpServletRequest request,
@PathParam( "repositoryName" ) String rawRepositoryName,
@PathParam( "workspaceName" ) String rawWorkspaceName,
+ @QueryParam( "autoCheckoutCheckin" ) @DefaultValue( "true" ) boolean autoCheckoutCheckin,
String requestContent ) throws JSONException, RepositoryException {
- return itemHandler.updateItems(request, rawRepositoryName, rawWorkspaceName, requestContent);
+ return itemHandler.updateItems(request, rawRepositoryName, rawWorkspaceName,autoCheckoutCheckin, requestContent);
}
/**
@@ -1040,6 +1044,7 @@ public RestItem getNodeWithId( @Context HttpServletRequest request,
* @param rawRepositoryName the URL-encoded repository name
* @param rawWorkspaceName the URL-encoded workspace name
* @param id the node identifier of the existing item
+ * @param autoCheckoutCheckin automatic checkout/checkin of Node
* @param requestContent the JSON-encoded representation of the values and, possibly, properties to be set
* @return a {@link RestItem} instance representing the modified item.
* @throws JSONException if there is an error reading the request body as a valid JSON object.
@@ -1053,8 +1058,9 @@ public RestItem putNodeWithId( @Context HttpServletRequest request,
@PathParam( "repositoryName" ) String rawRepositoryName,
@PathParam( "workspaceName" ) String rawWorkspaceName,
@PathParam( "id" ) String id,
+ @QueryParam( "autoCheckoutCheckin" ) @DefaultValue( "true" ) boolean autoCheckoutCheckin,
String requestContent ) throws JSONException, RepositoryException {
- return nodeHandler.updateNodeWithId(request, rawRepositoryName, rawWorkspaceName, id, requestContent);
+ return nodeHandler.updateNodeWithId(request, rawRepositoryName, rawWorkspaceName, id,autoCheckoutCheckin, requestContent);
}
/**
diff --git a/web/modeshape-web-jcr-rest/src/main/java/org/modeshape/web/jcr/rest/RestHelper.java b/web/modeshape-web-jcr-rest/src/main/java/org/modeshape/web/jcr/rest/RestHelper.java
index 3bf33b2d82..8a2792ecc1 100644
--- a/web/modeshape-web-jcr-rest/src/main/java/org/modeshape/web/jcr/rest/RestHelper.java
+++ b/web/modeshape-web-jcr-rest/src/main/java/org/modeshape/web/jcr/rest/RestHelper.java
@@ -58,7 +58,7 @@ public final class RestHelper {
public static final String UPLOAD_METHOD_NAME = "upload";
public static final String BACKUP_METHOD_NAME = "backup";
public static final String RESTORE_METHOD_NAME = "restore";
-
+
private static final List ALL_METHODS = Arrays.asList(BINARY_METHOD_NAME,
ITEMS_METHOD_NAME,
NODES_METHOD_NAME,
@@ -72,6 +72,12 @@ public final class RestHelper {
private static final Logger LOGGER = WebLogger.getLogger(RestHelper.class);
+ static {
+ for(SimpleDateFormat format:ISO8601_DATE_PARSERS) {
+ format.setLenient(false);
+ }
+ }
+
private RestHelper() {
}
diff --git a/web/modeshape-web-jcr-rest/src/main/java/org/modeshape/web/jcr/rest/handler/ItemHandler.java b/web/modeshape-web-jcr-rest/src/main/java/org/modeshape/web/jcr/rest/handler/ItemHandler.java
index e2e8523aa7..91bceb3640 100644
--- a/web/modeshape-web-jcr-rest/src/main/java/org/modeshape/web/jcr/rest/handler/ItemHandler.java
+++ b/web/modeshape-web-jcr-rest/src/main/java/org/modeshape/web/jcr/rest/handler/ItemHandler.java
@@ -27,6 +27,7 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
+
import javax.jcr.Binary;
import javax.jcr.Item;
import javax.jcr.ItemNotFoundException;
@@ -38,11 +39,14 @@
import javax.jcr.Session;
import javax.jcr.Value;
import javax.jcr.ValueFactory;
+import javax.jcr.lock.Lock;
+import javax.jcr.lock.LockManager;
import javax.jcr.nodetype.NodeType;
import javax.jcr.version.VersionManager;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.NotAuthorizedException;
import javax.ws.rs.NotFoundException;
+
import org.codehaus.jettison.json.JSONArray;
import org.codehaus.jettison.json.JSONException;
import org.codehaus.jettison.json.JSONObject;
@@ -60,12 +64,14 @@ public abstract class ItemHandler extends AbstractHandler {
protected static final String CHILD_NODE_HOLDER = "children";
private static final String PRIMARY_TYPE_PROPERTY = JcrConstants.JCR_PRIMARY_TYPE;
+
private static final String MIXIN_TYPES_PROPERTY = JcrConstants.JCR_MIXIN_TYPES;
+
private static final String PROPERTIES_HOLDER = "properties";
/**
* Adds the node described by {@code jsonNode} with name {@code nodeName} to the existing node {@code parentNode}.
- *
+ *
* @param parentNode the parent of the node to be added
* @param nodeName the name of the node to be added
* @param jsonNode the JSON-encoded representation of the node or nodes to be added.
@@ -74,13 +80,21 @@ public abstract class ItemHandler extends AbstractHandler {
* @throws JSONException if there is an error encoding the node
* @throws RepositoryException if any other error occurs
*/
- protected Node addNode( Node parentNode,
- String nodeName,
- JSONObject jsonNode ) throws RepositoryException, JSONException {
+ protected Node addNode(Node parentNode, String nodeName, JSONObject jsonNode) throws RepositoryException, JSONException {
Node newNode;
JSONObject properties = getProperties(jsonNode);
+ if(parentNode.isLocked()) {
+ LockManager lockManager = parentNode.getSession().getWorkspace().getLockManager();
+ Lock lock = lockManager.getLock(parentNode.getPath());
+ if (lock.getLockOwner().equals(parentNode.getSession().getUserID())) {
+ //Add LockToken to current session
+ lockManager.unlock(parentNode.getPath());
+ lockManager.lock(parentNode.getPath(),lock.isDeep(),lock.isSessionScoped(),lock.getSecondsRemaining(),lock.getLockOwner());
+ }
+ }
+
if (properties.has(PRIMARY_TYPE_PROPERTY)) {
String primaryType = properties.getString(PRIMARY_TYPE_PROPERTY);
newNode = parentNode.addNode(nodeName, primaryType);
@@ -94,8 +108,8 @@ protected Node addNode( Node parentNode,
updateMixins(newNode, properties.get(MIXIN_TYPES_PROPERTY));
}
- for (Iterator> iter = properties.keys(); iter.hasNext();) {
- String key = (String)iter.next();
+ for (Iterator> iter = properties.keys(); iter.hasNext(); ) {
+ String key = (String) iter.next();
if (PRIMARY_TYPE_PROPERTY.equals(key) || MIXIN_TYPES_PROPERTY.equals(key)) {
continue;
@@ -114,12 +128,12 @@ protected Node addNode( Node parentNode,
return newNode;
}
- protected List getChildren( JSONObject jsonNode ) throws JSONException {
+ protected List getChildren(JSONObject jsonNode) throws JSONException {
List children;
try {
JSONObject childrenObject = jsonNode.getJSONObject(CHILD_NODE_HOLDER);
children = new ArrayList<>(childrenObject.length());
- for (Iterator> iterator = childrenObject.keys(); iterator.hasNext();) {
+ for (Iterator> iterator = childrenObject.keys(); iterator.hasNext(); ) {
String childName = iterator.next().toString();
//it is not possible to have SNS in the object form, so the index will always be 1
children.add(new JSONChild(childName, childrenObject.getJSONObject(childName), 1));
@@ -136,8 +150,7 @@ protected List getChildren( JSONObject jsonNode ) throws JSONExceptio
continue;
}
if (child.length() > 1) {
- logger.warn("The child object {0} has more than 1 elements, only the first one will be taken into account",
- child);
+ logger.warn("The child object {0} has more than 1 elements, only the first one will be taken into account", child);
}
String childName = child.keys().next().toString();
int sns = visitedNames.containsKey(childName) ? visitedNames.get(childName) + 1 : 1;
@@ -149,16 +162,15 @@ protected List getChildren( JSONObject jsonNode ) throws JSONExceptio
}
}
- protected boolean hasChildren( JSONObject jsonNode ) {
+ protected boolean hasChildren(JSONObject jsonNode) {
return jsonNode.has(CHILD_NODE_HOLDER);
}
- protected JSONObject getProperties( JSONObject jsonNode ) throws JSONException {
+ protected JSONObject getProperties(JSONObject jsonNode) throws JSONException {
return jsonNode.has(PROPERTIES_HOLDER) ? jsonNode.getJSONObject(PROPERTIES_HOLDER) : new JSONObject();
}
- private Value createBinaryValue( String base64EncodedValue,
- ValueFactory valueFactory ) throws RepositoryException {
+ private Value createBinaryValue(String base64EncodedValue, ValueFactory valueFactory) throws RepositoryException {
InputStream stream = null;
try {
byte[] binaryValue = Base64.decode(base64EncodedValue);
@@ -183,16 +195,14 @@ private Value createBinaryValue( String base64EncodedValue,
* Sets the named property on the given node. This method expects {@code value} to be either a JSON string or a JSON array of
* JSON strings. If {@code value} is a JSON array, {@code Node#setProperty(String, String[]) the multi-valued property setter}
* will be used.
- *
+ *
* @param node the node on which the property is to be set
* @param propName the name of the property to set
* @param value the JSON-encoded values to be set
* @throws RepositoryException if there is an error setting the property
* @throws JSONException if {@code value} cannot be decoded
*/
- protected void setPropertyOnNode( Node node,
- String propName,
- Object value ) throws RepositoryException, JSONException {
+ protected void setPropertyOnNode(Node node, String propName, Object value) throws RepositoryException, JSONException {
// Are the property values encoded ?
boolean encoded = propName.endsWith(BASE64_ENCODING_SUFFIX);
if (encoded) {
@@ -211,16 +221,15 @@ protected void setPropertyOnNode( Node node,
}
}
- private Set updateMixins( Node node,
- Object mixinsJsonValue ) throws JSONException, RepositoryException {
+ private Set updateMixins(Node node, Object mixinsJsonValue) throws JSONException, RepositoryException {
Object valuesObject = convertToJcrValues(node, mixinsJsonValue, false);
Value[] values = null;
if (valuesObject == null) {
values = new Value[0];
} else if (valuesObject instanceof Value[]) {
- values = (Value[])valuesObject;
+ values = (Value[]) valuesObject;
} else {
- values = new Value[]{(Value)valuesObject};
+ values = new Value[] { (Value) valuesObject };
}
Set jsonMixins = new HashSet(values.length);
@@ -245,16 +254,14 @@ private Set updateMixins( Node node,
return mixinsToRemove;
}
- private Object convertToJcrValues( Node node,
- Object value,
- boolean encoded ) throws RepositoryException, JSONException {
- if (value == JSONObject.NULL || (value instanceof JSONArray && ((JSONArray)value).length() == 0)) {
+ private Object convertToJcrValues(Node node, Object value, boolean encoded) throws RepositoryException, JSONException {
+ if (value == JSONObject.NULL || (value instanceof JSONArray && ((JSONArray) value).length() == 0)) {
// for any null value of empty json array, return an empty array which will mean the property will be removed
return null;
}
- org.modeshape.jcr.api.ValueFactory valueFactory = (org.modeshape.jcr.api.ValueFactory)node.getSession().getValueFactory();
+ org.modeshape.jcr.api.ValueFactory valueFactory = (org.modeshape.jcr.api.ValueFactory) node.getSession().getValueFactory();
if (value instanceof JSONArray) {
- JSONArray jsonValues = (JSONArray)value;
+ JSONArray jsonValues = (JSONArray) value;
Value[] values = new Value[jsonValues.length()];
for (int i = 0; i < jsonValues.length(); i++) {
@@ -272,7 +279,7 @@ private Object convertToJcrValues( Node node,
/**
* Deletes the item at {@code path}.
- *
+ *
* @param request the servlet request; may not be null or unauthenticated
* @param rawRepositoryName the URL-encoded repository name
* @param rawWorkspaceName the URL-encoded workspace name
@@ -281,10 +288,7 @@ private Object convertToJcrValues( Node node,
* @throws NotAuthorizedException if the user does not have the access required to delete the item at this path
* @throws RepositoryException if any other error occurs
*/
- public void deleteItem( HttpServletRequest request,
- String rawRepositoryName,
- String rawWorkspaceName,
- String path ) throws NotFoundException, NotAuthorizedException, RepositoryException {
+ public void deleteItem(HttpServletRequest request, String rawRepositoryName, String rawWorkspaceName, String path) throws NotFoundException, NotAuthorizedException, RepositoryException {
assert rawRepositoryName != null;
assert rawWorkspaceName != null;
@@ -296,8 +300,7 @@ public void deleteItem( HttpServletRequest request,
session.save();
}
- protected void doDelete( String path,
- Session session ) throws RepositoryException {
+ protected void doDelete(String path, Session session) throws RepositoryException {
Item item;
try {
item = session.getItem(path);
@@ -309,23 +312,22 @@ protected void doDelete( String path,
/**
* Updates the existing item based upon the supplied JSON content.
- *
+ *
* @param item the node or property to be updated
* @param jsonItem the JSON of the item(s) to be updated
+ * @param autoCheckoutCheckin automatic checkout/checkin of item
* @return the node that was updated; never null
* @throws JSONException if there is an error encoding the node
* @throws RepositoryException if any other error occurs
*/
- protected Item updateItem( Item item,
- JSONObject jsonItem ) throws RepositoryException, JSONException {
+ protected Item updateItem(Item item, JSONObject jsonItem, boolean autoCheckoutCheckin) throws RepositoryException, JSONException {
if (item instanceof Node) {
- return updateNode((Node)item, jsonItem);
+ return updateNode((Node) item, jsonItem,autoCheckoutCheckin);
}
- return updateProperty((Property)item, jsonItem);
+ return updateProperty((Property) item, jsonItem);
}
- private Property updateProperty( Property property,
- JSONObject jsonItem ) throws RepositoryException, JSONException {
+ private Property updateProperty(Property property, JSONObject jsonItem) throws RepositoryException, JSONException {
String propertyName = property.getName();
String jsonPropertyName = jsonItem.has(propertyName) ? propertyName : propertyName + BASE64_ENCODING_SUFFIX;
Node node = property.getParent();
@@ -333,9 +335,8 @@ private Property updateProperty( Property property,
return property;
}
- protected Node updateNode( Node node,
- JSONObject jsonItem ) throws RepositoryException, JSONException {
- VersionableChanges changes = new VersionableChanges(node.getSession());
+ protected Node updateNode(Node node, JSONObject jsonItem,boolean autoCheckoutCheckin) throws RepositoryException, JSONException {
+ VersionableChanges changes = new VersionableChanges(node.getSession(),autoCheckoutCheckin);
try {
node = updateNode(node, jsonItem, changes);
changes.checkin();
@@ -348,7 +349,7 @@ protected Node updateNode( Node node,
/**
* Updates the existing node with the properties (and optionally children) as described by {@code jsonNode}.
- *
+ *
* @param node the node to be updated
* @param jsonNode the JSON-encoded representation of the node or nodes to be updated.
* @param changes the versionable changes; may not be null
@@ -356,9 +357,7 @@ protected Node updateNode( Node node,
* @throws JSONException if there is an error encoding the node
* @throws RepositoryException if any other error occurs
*/
- protected Node updateNode( Node node,
- JSONObject jsonNode,
- VersionableChanges changes ) throws RepositoryException, JSONException {
+ protected Node updateNode(Node node, JSONObject jsonNode, VersionableChanges changes) throws RepositoryException, JSONException {
// If the JSON object has a properties holder, then this is likely a subgraph ...
JSONObject properties = jsonNode;
if (jsonNode.has(PROPERTIES_HOLDER)) {
@@ -367,6 +366,16 @@ protected Node updateNode( Node node,
changes.checkout(node);
+ if(node.isLocked()) {
+ LockManager lockManager = node.getSession().getWorkspace().getLockManager();
+ Lock lock = lockManager.getLock(node.getPath());
+ if (lock.getLockOwner().equals(node.getSession().getUserID())) {
+ //Add LockToken to current session
+ lockManager.unlock(node.getPath());
+ lockManager.lock(node.getPath(),lock.isDeep(),lock.isSessionScoped(),lock.getSecondsRemaining(),lock.getLockOwner());
+ }
+ }
+
// Change the primary type first ...
if (properties.has(PRIMARY_TYPE_PROPERTY)) {
String primaryType = properties.getString(PRIMARY_TYPE_PROPERTY);
@@ -384,8 +393,8 @@ protected Node updateNode( Node node,
}
// Now set all the other properties ...
- for (Iterator> iter = properties.keys(); iter.hasNext();) {
- String key = (String)iter.next();
+ for (Iterator> iter = properties.keys(); iter.hasNext(); ) {
+ String key = (String) iter.next();
if (PRIMARY_TYPE_PROPERTY.equals(key) || MIXIN_TYPES_PROPERTY.equals(key) || CHILD_NODE_HOLDER.equals(key)) {
continue;
}
@@ -405,9 +414,7 @@ protected Node updateNode( Node node,
return node;
}
- private void updateChildren( Node node,
- JSONObject jsonNode,
- VersionableChanges changes ) throws JSONException, RepositoryException {
+ private void updateChildren(Node node, JSONObject jsonNode, VersionableChanges changes) throws JSONException, RepositoryException {
Session session = node.getSession();
// Get the existing children ...
@@ -449,8 +456,7 @@ private void updateChildren( Node node,
//this is a child belonging to another node
if (childNode.isNodeType("mix:shareable")) {
//if it's a shared node, we can't clone it because clone is not a session-scoped operation
- logger.warn("The node {0} with the id {1} is a shared node belonging to another parent. It cannot be changed via the update operation",
- childNode.getPath(), childNode.getIdentifier());
+ logger.warn("The node {0} with the id {1} is a shared node belonging to another parent. It cannot be changed via the update operation", childNode.getPath(), childNode.getIdentifier());
} else {
//move the node into this parent
session.move(childNode.getPath(), node.getPath() + "/" + childNodeName);
@@ -495,7 +501,7 @@ private void updateChildren( Node node,
}
}
- private String nameOf( Node node ) throws RepositoryException {
+ private String nameOf(Node node) throws RepositoryException {
int index = node.getIndex();
String childName = node.getName();
return index == 1 ? childName : childName + "[" + index + "]";
@@ -503,10 +509,12 @@ private String nameOf( Node node ) throws RepositoryException {
protected static class JSONChild {
private final String name;
+
private final JSONObject body;
+
private final int snsIdx;
- protected JSONChild( String name, JSONObject body, int snsIdx ) {
+ protected JSONChild(String name, JSONObject body, int snsIdx) {
this.name = name;
this.body = body;
this.snsIdx = snsIdx;
@@ -536,18 +544,23 @@ public String toString() {
protected static class VersionableChanges {
private final Set changedVersionableNodes = new HashSet();
+
private final Session session;
+
private final VersionManager versionManager;
- protected VersionableChanges( Session session ) throws RepositoryException {
+ private final boolean autoCheckoutCheckin;
+
+ protected VersionableChanges(Session session, boolean autoCheckoutCheckin) throws RepositoryException {
this.session = session;
assert this.session != null;
this.versionManager = session.getWorkspace().getVersionManager();
+ this.autoCheckoutCheckin = autoCheckoutCheckin;
}
- public void checkout( Node node ) throws RepositoryException {
+ public void checkout(Node node) throws RepositoryException {
boolean versionable = node.isNodeType("mix:versionable");
- if (versionable) {
+ if (versionable && autoCheckoutCheckin) {
String path = node.getPath();
versionManager.checkout(path);
this.changedVersionableNodes.add(path);
@@ -562,7 +575,7 @@ public void checkin() throws RepositoryException {
RepositoryException first = null;
for (String path : this.changedVersionableNodes) {
try {
- if (versionManager.isCheckedOut(path)) {
+ if (versionManager.isCheckedOut(path) && autoCheckoutCheckin) {
versionManager.checkin(path);
}
} catch (RepositoryException e) {
@@ -585,7 +598,7 @@ public void abort() throws RepositoryException {
RepositoryException first = null;
for (String path : this.changedVersionableNodes) {
try {
- if (versionManager.isCheckedOut(path)) {
+ if (versionManager.isCheckedOut(path) && autoCheckoutCheckin) {
versionManager.checkin(path);
}
} catch (RepositoryException e) {
diff --git a/web/modeshape-web-jcr-rest/src/main/java/org/modeshape/web/jcr/rest/handler/RestItemHandler.java b/web/modeshape-web-jcr-rest/src/main/java/org/modeshape/web/jcr/rest/handler/RestItemHandler.java
index de5077d72b..eb739271a9 100644
--- a/web/modeshape-web-jcr-rest/src/main/java/org/modeshape/web/jcr/rest/handler/RestItemHandler.java
+++ b/web/modeshape-web-jcr-rest/src/main/java/org/modeshape/web/jcr/rest/handler/RestItemHandler.java
@@ -137,6 +137,7 @@ private String newNodeName( String path ) {
* @param rawRepositoryName the URL-encoded repository name
* @param rawWorkspaceName the URL-encoded workspace name
* @param path the path to the item
+ * @param autoCheckoutCheckin automatic checkout/checkin of item
* @param requestContent the JSON-encoded representation of the values and, possibly, properties to be set
* @return the JSON-encoded representation of the node on which the property or properties were set.
* @throws JSONException if there is an error encoding the node
@@ -146,10 +147,11 @@ public RestItem updateItem( HttpServletRequest request,
String rawRepositoryName,
String rawWorkspaceName,
String path,
+ boolean autoCheckoutCheckin,
String requestContent ) throws JSONException, RepositoryException {
Session session = getSession(request, rawRepositoryName, rawWorkspaceName);
Item item = itemAtPath(path, session);
- item = updateItem(item, stringToJSONObject(requestContent));
+ item = updateItem(item, stringToJSONObject(requestContent),autoCheckoutCheckin);
session.save();
return createRestItem(request, 0, session, item);
@@ -196,15 +198,17 @@ public Response addItems( HttpServletRequest request,
* @param request the servlet request; may not be null or unauthenticated
* @param repositoryName the URL-encoded repository name
* @param workspaceName the URL-encoded workspace name
+ * @param autoCheckoutCheckin automatic checkout/checkin of items
* @param requestContent the JSON-encoded representation of the values and, possibly, properties to be set
* @return a {@code non-null} {@link Response}
* @throws JSONException if the body of the request is not a valid JSON object
* @throws RepositoryException if any of the JCR operations fail
- * @see RestItemHandler#updateItem(javax.servlet.http.HttpServletRequest, String, String, String, String)
+ * @see RestItemHandler#updateItem(javax.servlet.http.HttpServletRequest, String, String, String, boolean, String)
*/
public Response updateItems( HttpServletRequest request,
String repositoryName,
String workspaceName,
+ boolean autoCheckoutCheckin,
String requestContent ) throws JSONException, RepositoryException {
JSONObject requestBody = stringToJSONObject(requestContent);
if (requestBody.length() == 0) {
@@ -212,7 +216,7 @@ public Response updateItems( HttpServletRequest request,
}
Session session = getSession(request, repositoryName, workspaceName);
TreeMap nodesByPath = createNodesByPathMap(requestBody);
- List result = updateMultipleNodes(request, session, nodesByPath);
+ List result = updateMultipleNodes(request, session, nodesByPath,autoCheckoutCheckin);
return createOkResponse(result);
}
@@ -258,12 +262,12 @@ public Response deleteItems( HttpServletRequest request,
private List updateMultipleNodes( HttpServletRequest request,
Session session,
- TreeMap nodesByPath )
+ TreeMap nodesByPath,boolean automaticCheckoutCheckin )
throws RepositoryException, JSONException {
List result = new ArrayList();
for (String nodePath : nodesByPath.keySet()) {
Item item = session.getItem(nodePath);
- item = updateItem(item, nodesByPath.get(nodePath));
+ item = updateItem(item, nodesByPath.get(nodePath),automaticCheckoutCheckin);
result.add(createRestItem(request, 0, session, item));
}
session.save();
diff --git a/web/modeshape-web-jcr-rest/src/main/java/org/modeshape/web/jcr/rest/handler/RestNodeHandler.java b/web/modeshape-web-jcr-rest/src/main/java/org/modeshape/web/jcr/rest/handler/RestNodeHandler.java
index 23d6e0dfb2..e40e298eb1 100644
--- a/web/modeshape-web-jcr-rest/src/main/java/org/modeshape/web/jcr/rest/handler/RestNodeHandler.java
+++ b/web/modeshape-web-jcr-rest/src/main/java/org/modeshape/web/jcr/rest/handler/RestNodeHandler.java
@@ -73,6 +73,7 @@ public RestItem nodeWithId( HttpServletRequest request,
* @param rawRepositoryName the URL-encoded repository name
* @param rawWorkspaceName the URL-encoded workspace name
* @param id the node identifier
+ * @param autoCheckoutCheckin automatic checkout/checkin of item
* @param requestContent the JSON-encoded representation of the values and, possibly, properties to be set
* @return the JSON-encoded representation of the node on which the property or properties were set.
* @throws JSONException if there is an error encoding the node
@@ -82,10 +83,11 @@ public RestItem updateNodeWithId( HttpServletRequest request,
String rawRepositoryName,
String rawWorkspaceName,
String id,
+ boolean autoCheckoutCheckin,
String requestContent ) throws JSONException, RepositoryException {
Session session = getSession(request, rawRepositoryName, rawWorkspaceName);
Node node = nodeWithId(id, session);
- node = updateNode(node, stringToJSONObject(requestContent));
+ node = updateNode(node, stringToJSONObject(requestContent),autoCheckoutCheckin);
session.save();
return createRestItem(request, 0, session, node);
diff --git a/web/modeshape-web-jcr-rest/src/test/java/org/modeshape/web/jcr/rest/RestHelperTest.java b/web/modeshape-web-jcr-rest/src/test/java/org/modeshape/web/jcr/rest/RestHelperTest.java
new file mode 100644
index 0000000000..303f354d57
--- /dev/null
+++ b/web/modeshape-web-jcr-rest/src/test/java/org/modeshape/web/jcr/rest/RestHelperTest.java
@@ -0,0 +1,51 @@
+/*
+ * ModeShape (http://www.modeshape.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.modeshape.web.jcr.rest;
+
+import java.time.LocalDate;
+import java.time.ZoneId;
+
+import javax.jcr.PropertyType;
+import javax.jcr.Value;
+
+import org.junit.Test;
+import org.modeshape.test.ModeShapeSingleUseTest;
+
+import static org.hamcrest.core.Is.is;
+import static org.junit.Assert.assertThat;
+
+/**
+ * Created by abieberbach on 25.01.2016.
+ */
+public class RestHelperTest extends ModeShapeSingleUseTest {
+
+ @Test
+ public void testJsonValueToJCRValue_UUIDWithTimestamp() throws Exception {
+ Value value = RestHelper.jsonValueToJCRValue("32899126-7281-46a6-b298-4558fbc82d5f", session().getValueFactory());
+ assertThat(value.getString(),is("32899126-7281-46a6-b298-4558fbc82d5f"));
+ assertThat(value.getType(),is(PropertyType.STRING));
+ }
+
+ @Test
+ public void testJsonValueToJCRValue_Date() throws Exception {
+ Value value = RestHelper.jsonValueToJCRValue("2016-01-25", session().getValueFactory());
+ assertThat(value.getDate().toInstant(),is(LocalDate.of(2016,1,25).atStartOfDay(ZoneId.systemDefault()).toInstant()));
+ assertThat(value.getType(),is(PropertyType.DATE));
+ }
+
+
+}
\ No newline at end of file
diff --git a/web/modeshape-web-jcr-webdav-war/pom.xml b/web/modeshape-web-jcr-webdav-war/pom.xml
index 12702ec179..e5911c6eaa 100644
--- a/web/modeshape-web-jcr-webdav-war/pom.xml
+++ b/web/modeshape-web-jcr-webdav-war/pom.xml
@@ -5,7 +5,7 @@
org.modeshape
modeshape-parent
- 4.5-SNAPSHOT
+ 4.5.0.1-deg-SNAPSHOT
../../modeshape-parent
modeshape-web-jcr-webdav-war
diff --git a/web/modeshape-web-jcr-webdav/pom.xml b/web/modeshape-web-jcr-webdav/pom.xml
index cbc031fc9b..7f7ee39a1d 100644
--- a/web/modeshape-web-jcr-webdav/pom.xml
+++ b/web/modeshape-web-jcr-webdav/pom.xml
@@ -5,7 +5,7 @@
org.modeshape
modeshape-parent
- 4.5-SNAPSHOT
+ 4.5.0.1-deg-SNAPSHOT
../../modeshape-parent
modeshape-web-jcr-webdav
diff --git a/web/modeshape-web-jcr/pom.xml b/web/modeshape-web-jcr/pom.xml
index 5cd089e80c..895968664b 100644
--- a/web/modeshape-web-jcr/pom.xml
+++ b/web/modeshape-web-jcr/pom.xml
@@ -5,7 +5,7 @@
org.modeshape
modeshape-parent
- 4.5-SNAPSHOT
+ 4.5.0.1-deg-SNAPSHOT
../../modeshape-parent
diff --git a/web/modeshape-webdav-war/pom.xml b/web/modeshape-webdav-war/pom.xml
index 31193a97d2..f5a852714d 100644
--- a/web/modeshape-webdav-war/pom.xml
+++ b/web/modeshape-webdav-war/pom.xml
@@ -4,7 +4,7 @@
org.modeshape
modeshape-parent
- 4.5-SNAPSHOT
+ 4.5.0.1-deg-SNAPSHOT
../../modeshape-parent
modeshape-webdav-war
diff --git a/web/modeshape-webdav/pom.xml b/web/modeshape-webdav/pom.xml
index 850ad83c01..befc721b2a 100644
--- a/web/modeshape-webdav/pom.xml
+++ b/web/modeshape-webdav/pom.xml
@@ -5,7 +5,7 @@
org.modeshape
modeshape-parent
- 4.5-SNAPSHOT
+ 4.5.0.1-deg-SNAPSHOT
../../modeshape-parent
modeshape-webdav
diff --git a/web/pom.xml b/web/pom.xml
index 4bc7a7caed..5c99859672 100644
--- a/web/pom.xml
+++ b/web/pom.xml
@@ -4,7 +4,7 @@
org.modeshape
modeshape-parent
- 4.5-SNAPSHOT
+ 4.5.0.1-deg-SNAPSHOT
../modeshape-parent