You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by th...@apache.org on 2009/01/27 17:00:56 UTC
svn commit: r738119 - in /jackrabbit/trunk/jackrabbit-core/src:
main/java/org/apache/jackrabbit/core/data/
main/java/org/apache/jackrabbit/core/data/db/
main/java/org/apache/jackrabbit/core/value/
test/java/org/apache/jackrabbit/core/data/
Author: thomasm
Date: Tue Jan 27 16:00:55 2009
New Revision: 738119
URL: http://svn.apache.org/viewvc?rev=738119&view=rev
Log:
JCR-1892 Unique ID for org.apache.jackrabbit.value.BinaryValue
Added:
jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/value/BinaryValueImpl.java
Modified:
jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/DataStore.java
jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/FileDataStore.java
jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/db/DbDataStore.java
jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/value/BLOBFileValue.java
jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/value/BLOBInDataStore.java
jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/value/InternalValue.java
jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/data/TestTwoGetStreams.java
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/DataStore.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/DataStore.java?rev=738119&r1=738118&r2=738119&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/DataStore.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/DataStore.java Tue Jan 27 16:00:55 2009
@@ -35,6 +35,15 @@
public interface DataStore {
/**
+ * Check if a record for the given identifier exists, and return it if yes.
+ * If no record exists, this method returns null.
+ *
+ * @param identifier data identifier
+ * @return the record if found, and null if not
+ */
+ DataRecord getRecordIfStored(DataIdentifier identifier) throws DataStoreException;
+
+ /**
* Returns the identified data record. The given identifier should be
* the identifier of a previously saved data record. Since records are
* never removed, there should never be cases where the identified record
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/FileDataStore.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/FileDataStore.java?rev=738119&r1=738118&r2=738119&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/FileDataStore.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/FileDataStore.java Tue Jan 27 16:00:55 2009
@@ -122,27 +122,41 @@
directory = new File(path);
directory.mkdirs();
}
-
+
/**
- * Returns the record with the given identifier. Note that this method
- * performs no sanity checks on the given identifier. It is up to the
- * caller to ensure that only identifiers of previously created data
- * records are used.
- *
- * @param identifier data identifier
- * @return identified data record
+ * {@inheritDoc}
*/
- public DataRecord getRecord(DataIdentifier identifier) {
+ public DataRecord getRecordIfStored(DataIdentifier identifier) {
File file = getFile(identifier);
synchronized (this) {
- if (minModifiedDate != 0 && file.exists() && file.canWrite()) {
+ if (!file.exists()) {
+ return null;
+ }
+ if (minModifiedDate != 0 && file.canWrite()) {
if (file.lastModified() < minModifiedDate) {
file.setLastModified(System.currentTimeMillis());
}
}
usesIdentifier(identifier);
+ return new FileDataRecord(identifier, file);
+ }
+ }
+
+ /**
+ * Returns the record with the given identifier. Note that this method
+ * performs no sanity checks on the given identifier. It is up to the
+ * caller to ensure that only identifiers of previously created data
+ * records are used.
+ *
+ * @param identifier data identifier
+ * @return identified data record
+ */
+ public DataRecord getRecord(DataIdentifier identifier) throws DataStoreException {
+ DataRecord record = getRecordIfStored(identifier);
+ if (record == null) {
+ throw new DataStoreException("Record not found: " + identifier);
}
- return new FileDataRecord(identifier, file);
+ return record;
}
private void usesIdentifier(DataIdentifier identifier) {
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/db/DbDataStore.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/db/DbDataStore.java?rev=738119&r1=738118&r2=738119&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/db/DbDataStore.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/db/DbDataStore.java Tue Jan 27 16:00:55 2009
@@ -488,7 +488,7 @@
/**
* {@inheritDoc}
*/
- public DataRecord getRecord(DataIdentifier identifier) throws DataStoreException {
+ public DataRecord getRecordIfStored(DataIdentifier identifier) throws DataStoreException {
ConnectionRecoveryManager conn = getConnection();
usesIdentifier(identifier);
ResultSet rs = null;
@@ -513,6 +513,17 @@
}
/**
+ * {@inheritDoc}
+ */
+ public DataRecord getRecord(DataIdentifier identifier) throws DataStoreException {
+ DataRecord record = getRecordIfStored(identifier);
+ if (record == null) {
+ throw new DataStoreException("Record not found: " + identifier);
+ }
+ return record;
+ }
+
+ /**
* Open the input stream. This method sets those fields of the caller
* that need to be closed once the input stream is read.
*
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/value/BLOBFileValue.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/value/BLOBFileValue.java?rev=738119&r1=738118&r2=738119&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/value/BLOBFileValue.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/value/BLOBFileValue.java Tue Jan 27 16:00:55 2009
@@ -23,6 +23,7 @@
import javax.jcr.RepositoryException;
import org.apache.commons.io.IOUtils;
+import org.apache.jackrabbit.core.data.DataIdentifier;
/**
* Represents binary data which is backed by a resource or byte[].
@@ -118,5 +119,14 @@
* @return true if the value is small
*/
public abstract boolean isSmall();
+
+ /**
+ * Get the data identifier if one is available.
+ *
+ * @return the data identifier or null
+ */
+ public DataIdentifier getDataIdentifier() {
+ return null;
+ }
}
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/value/BLOBInDataStore.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/value/BLOBInDataStore.java?rev=738119&r1=738118&r2=738119&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/value/BLOBInDataStore.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/value/BLOBInDataStore.java Tue Jan 27 16:00:55 2009
@@ -60,6 +60,10 @@
public void discard() {
// do nothing
}
+
+ public DataIdentifier getDataIdentifier() {
+ return identifier;
+ }
/**
* {@inheritDoc}
@@ -115,6 +119,10 @@
DataIdentifier identifier = new DataIdentifier(id);
return new BLOBInDataStore(store, identifier);
}
+
+ static BLOBInDataStore getInstance(DataStore store, DataIdentifier identifier) {
+ return new BLOBInDataStore(store, identifier);
+ }
static BLOBInDataStore getInstance(DataStore store, InputStream in) throws DataStoreException {
DataRecord rec = store.addRecord(in);
Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/value/BinaryValueImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/value/BinaryValueImpl.java?rev=738119&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/value/BinaryValueImpl.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/value/BinaryValueImpl.java Tue Jan 27 16:00:55 2009
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.jackrabbit.core.value;
+
+import javax.jcr.RepositoryException;
+import org.apache.jackrabbit.api.JackrabbitValue;
+import org.apache.jackrabbit.core.data.DataIdentifier;
+import org.apache.jackrabbit.value.BinaryValue;
+
+/**
+ * Represents a binary value that is backed by a blob file value.
+ */
+public class BinaryValueImpl extends BinaryValue implements JackrabbitValue {
+
+ private final BLOBFileValue blob;
+
+ /**
+ * Construct a new object from the given blob.
+ *
+ * @param blob the blob
+ */
+ BinaryValueImpl(BLOBFileValue blob) throws RepositoryException {
+ super(blob.getStream());
+ this.blob = blob;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String getContentIdentity() {
+ DataIdentifier id = blob.getDataIdentifier();
+ return id == null ? null : id.toString();
+ }
+
+ /**
+ * Get the wrapped blob file value
+ *
+ * @return the blob file value
+ */
+ BLOBFileValue getBlob() {
+ return blob;
+ }
+
+ /**
+ * Get the data identifier if one is available.
+ *
+ * @return the data identifier or null
+ */
+ DataIdentifier getDataIdentifier() {
+ return blob.getDataIdentifier();
+ }
+
+}
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/value/InternalValue.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/value/InternalValue.java?rev=738119&r1=738118&r2=738119&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/value/InternalValue.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/value/InternalValue.java Tue Jan 27 16:00:55 2009
@@ -17,6 +17,7 @@
package org.apache.jackrabbit.core.value;
import org.apache.commons.io.IOUtils;
+import org.apache.jackrabbit.core.data.DataIdentifier;
import org.apache.jackrabbit.core.data.DataStore;
import org.apache.jackrabbit.core.fs.FileSystemResource;
import org.apache.jackrabbit.spi.commons.conversion.MalformedPathException;
@@ -26,7 +27,6 @@
import org.apache.jackrabbit.spi.Name;
import org.apache.jackrabbit.util.ISO8601;
import org.apache.jackrabbit.uuid.UUID;
-import org.apache.jackrabbit.value.BinaryValue;
import org.apache.jackrabbit.value.BooleanValue;
import org.apache.jackrabbit.value.DateValue;
import org.apache.jackrabbit.value.DoubleValue;
@@ -121,19 +121,37 @@
}
switch (value.getType()) {
case PropertyType.BINARY:
+ InternalValue result;
if (USE_DATA_STORE) {
- return new InternalValue(getBLOBFileValue(store, value.getStream(), true));
- }
- if (value instanceof BLOBFileValue) {
- return new InternalValue((BLOBFileValue) value);
+ BLOBFileValue blob = null;
+ if (value instanceof BinaryValueImpl) {
+ BinaryValueImpl bin = (BinaryValueImpl) value;
+ DataIdentifier identifier = bin.getDataIdentifier();
+ if (identifier != null) {
+ // access the record to ensure it is not garbage collected
+ if (store.getRecordIfStored(identifier) != null) {
+ // it exists - so we don't need to stream it again
+ // but we need to create a new object because the original
+ // one might be in a different data store (repository)
+ blob = BLOBInDataStore.getInstance(store, identifier);
+ }
+ }
+ }
+ if (blob == null) {
+ blob = getBLOBFileValue(store, value.getStream(), true);
+ }
+ result = new InternalValue(blob);
+ } else if (value instanceof BLOBFileValue) {
+ result = new InternalValue((BLOBFileValue) value);
} else {
InputStream stream = value.getStream();
try {
- return createTemporary(stream);
+ result = createTemporary(stream);
} finally {
IOUtils.closeQuietly(stream);
}
}
+ return result;
case PropertyType.BOOLEAN:
return create(value.getBoolean());
case PropertyType.DATE:
@@ -361,7 +379,7 @@
throws RepositoryException {
switch (type) {
case PropertyType.BINARY:
- return new BinaryValue(((BLOBFileValue) val).getStream());
+ return new BinaryValueImpl((BLOBFileValue) val);
case PropertyType.BOOLEAN:
return new BooleanValue(((Boolean) val));
case PropertyType.DATE:
Modified: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/data/TestTwoGetStreams.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/data/TestTwoGetStreams.java?rev=738119&r1=738118&r2=738119&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/data/TestTwoGetStreams.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/data/TestTwoGetStreams.java Tue Jan 27 16:00:55 2009
@@ -20,8 +20,12 @@
import java.io.InputStream;
import javax.jcr.Node;
+import javax.jcr.RepositoryException;
import javax.jcr.Session;
+import javax.jcr.Value;
+import org.apache.jackrabbit.api.JackrabbitValue;
+import org.apache.jackrabbit.core.RepositoryImpl;
import org.apache.jackrabbit.test.AbstractJCRTest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -34,11 +38,63 @@
private static Logger log = LoggerFactory.getLogger(TestTwoGetStreams.class);
private static final int STREAM_LENGTH = 1 * 1024 * 1024;
+
+ private boolean isDataStoreEnabled() throws RepositoryException {
+ Session session = helper.getSuperuserSession();
+ RepositoryImpl rep = (RepositoryImpl) session.getRepository();
+ return rep.getDataStore() != null;
+ }
+
+ /**
+ * Test the JackrabbitValue.getContentIdentity feature.
+ */
+ public void testContentIdentity() throws Exception {
+ if (!isDataStoreEnabled()) {
+ log.info("testContentIdentity skipped. Data store is not used.");
+ return;
+ }
+
+ Session session = helper.getSuperuserSession();
+
+ Node root = session.getRootNode();
+ root.setProperty("p1", new RandomInputStream(1, STREAM_LENGTH));
+ root.setProperty("p2", new RandomInputStream(1, STREAM_LENGTH));
+ session.save();
+
+ Value v1 = root.getProperty("p1").getValue();
+ Value v2 = root.getProperty("p2").getValue();
+ if (v1 instanceof JackrabbitValue && v2 instanceof JackrabbitValue) {
+ JackrabbitValue j1 = (JackrabbitValue) v1;
+ JackrabbitValue j2 = (JackrabbitValue) v2;
+ String id1 = j1.getContentIdentity();
+ String id2 = j2.getContentIdentity();
+ assertNotNull(id1);
+ assertEquals(id1, id2);
+ }
+
+ // copying a value should not stream the content
+ long time = System.currentTimeMillis();
+ for (int i = 0; i < 100; i++) {
+ Value v = root.getProperty("p1").getValue();
+ root.setProperty("p3", v);
+ }
+ session.save();
+ time = System.currentTimeMillis() - time;
+ // streaming the value again and again takes about 4.3 seconds
+ // on my computer; copying the data identifier takes about 16 ms
+ assertTrue(time < 500);
+ }
+
/**
* Test reading from two concurrently opened streams.
*/
public void testTwoGetStreams() throws Exception {
+ if (!isDataStoreEnabled()) {
+ log.info("testContentIdentity skipped. Data store is not used.");
+ return;
+ }
+
Session session = helper.getSuperuserSession();
Node root = session.getRootNode();
root.setProperty("p1", new RandomInputStream(1, STREAM_LENGTH));
@@ -65,6 +121,11 @@
* Tests reading concurrently from two different streams.
*/
public void testTwoStreamsConcurrently() throws Exception {
+ if (!isDataStoreEnabled()) {
+ log.info("testContentIdentity skipped. Data store is not used.");
+ return;
+ }
+
Session session = helper.getSuperuserSession();
Node root = session.getRootNode();
root.setProperty("p1", new RandomInputStream(1, STREAM_LENGTH));
@@ -91,6 +152,11 @@
* same property.
*/
public void testTwoStreamsFromSamePropertyConcurrently() throws Exception {
+ if (!isDataStoreEnabled()) {
+ log.info("testContentIdentity skipped. Data store is not used.");
+ return;
+ }
+
Session session = helper.getSuperuserSession();
Node root = session.getRootNode();
root.setProperty("p1", new RandomInputStream(1, STREAM_LENGTH));