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 2007/09/06 12:07:46 UTC

svn commit: r573209 - in /jackrabbit/trunk/jackrabbit-core: ./ src/main/java/org/apache/jackrabbit/core/ src/main/java/org/apache/jackrabbit/core/config/ src/main/java/org/apache/jackrabbit/core/data/ src/main/java/org/apache/jackrabbit/core/persistenc...

Author: thomasm
Date: Thu Sep  6 03:07:41 2007
New Revision: 573209

URL: http://svn.apache.org/viewvc?rev=573209&view=rev
Log:
JCR-926: configuration for data store in repository.xml

Added:
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/DataStoreConfig.java   (with props)
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/value/BLOBInResource.java   (with props)
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/value/BLOBInTempFile.java
Modified:
    jackrabbit/trunk/jackrabbit-core/   (props changed)
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryImpl.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/RepositoryConfig.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/RepositoryConfigurationParser.java
    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/persistence/bundle/util/BundleBinding.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/bundle/util/ItemStateBinding.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/value/InternalValue.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/BufferedStringValue.java

Propchange: jackrabbit/trunk/jackrabbit-core/
------------------------------------------------------------------------------
--- svn:ignore (original)
+++ svn:ignore Thu Sep  6 03:07:41 2007
@@ -1,11 +1,12 @@
-target
-*.log
-*.iws
-*.ipr
-*.iml
-junit*.properties
-.settings
-.classpath
-.project
-*.xml.md5
-*-pom-snapshot-version
+target
+*.log
+*.iws
+*.ipr
+*.iml
+junit*.properties
+.settings
+.classpath
+.project
+*.xml.md5
+*-pom-snapshot-version
+.checkstyle

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryImpl.java?rev=573209&r1=573208&r2=573209&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryImpl.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryImpl.java Thu Sep  6 03:07:41 2007
@@ -29,6 +29,7 @@
 import org.apache.jackrabbit.core.cluster.UpdateEventChannel;
 import org.apache.jackrabbit.core.cluster.UpdateEventListener;
 import org.apache.jackrabbit.core.config.ClusterConfig;
+import org.apache.jackrabbit.core.config.DataStoreConfig;
 import org.apache.jackrabbit.core.config.FileSystemConfig;
 import org.apache.jackrabbit.core.config.LoginModuleConfig;
 import org.apache.jackrabbit.core.config.PersistenceManagerConfig;
@@ -36,7 +37,6 @@
 import org.apache.jackrabbit.core.config.VersioningConfig;
 import org.apache.jackrabbit.core.config.WorkspaceConfig;
 import org.apache.jackrabbit.core.data.DataStore;
-import org.apache.jackrabbit.core.data.FileDataStore;
 import org.apache.jackrabbit.core.fs.BasedFileSystem;
 import org.apache.jackrabbit.core.fs.FileSystem;
 import org.apache.jackrabbit.core.fs.FileSystemException;
@@ -58,6 +58,7 @@
 import org.apache.jackrabbit.core.state.ManagedMLRUItemStateCacheFactory;
 import org.apache.jackrabbit.core.state.SharedItemStateManager;
 import org.apache.jackrabbit.core.util.RepositoryLock;
+import org.apache.jackrabbit.core.value.InternalValue;
 import org.apache.jackrabbit.core.version.VersionManager;
 import org.apache.jackrabbit.core.version.VersionManagerImpl;
 import org.apache.jackrabbit.name.NamespaceResolver;
@@ -248,8 +249,6 @@
             throw new RepositoryException(msg, fse);
         }
         metaDataStore = new BasedFileSystem(repStore, fsRootPath);
-        dataStore =
-            new FileDataStore(new File(repConfig.getHomeDir(), "datastore"));        
 
         // init root node uuid
         rootNodeId = loadRootNodeId(metaDataStore);
@@ -262,6 +261,13 @@
         // create registries
         nsReg = createNamespaceRegistry(new BasedFileSystem(repStore, "/namespaces"));
         ntReg = createNodeTypeRegistry(nsReg, new BasedFileSystem(repStore, "/nodetypes"));
+        
+        if (repConfig.getDataStoreConfig() != null) {
+            assert InternalValue.USE_DATA_STORE;
+            dataStore = createDataStore();
+        } else {
+            dataStore = null;            
+        }
 
         // init workspace configs
         Iterator iter = repConfig.getWorkspaceConfigs().iterator();
@@ -627,6 +633,18 @@
         } catch (Exception e) {
             throw new RepositoryException(e);
         }
+    }
+    
+    /**
+     * Create a data store object using the data store configuration.
+     *
+     * @return the data store object
+     */
+    protected DataStore createDataStore() throws RepositoryException {
+        DataStoreConfig dsc = repConfig.getDataStoreConfig();
+        DataStore dataStore = (DataStore) dsc.newInstance();
+        dataStore.init(repConfig.getHomeDir());
+        return dataStore;
     }
 
     protected NamespaceRegistryImpl getNamespaceRegistry() {

Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/DataStoreConfig.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/DataStoreConfig.java?rev=573209&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/DataStoreConfig.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/DataStoreConfig.java Thu Sep  6 03:07:41 2007
@@ -0,0 +1,17 @@
+package org.apache.jackrabbit.core.config;
+
+/**
+ * Data store configuration. 
+ */
+public class DataStoreConfig extends BeanConfig {
+
+    /**
+     * Creates a data store configuration object from the given bean configuration.
+     *
+     * @param config bean configuration
+     */
+    public DataStoreConfig(BeanConfig config) {
+        super(config);
+    }
+    
+}

Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/DataStoreConfig.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/RepositoryConfig.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/RepositoryConfig.java?rev=573209&r1=573208&r2=573209&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/RepositoryConfig.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/RepositoryConfig.java Thu Sep  6 03:07:41 2007
@@ -216,6 +216,11 @@
      * Optional cluster configuration.
      */
     private final ClusterConfig cc;
+    
+    /**
+     * Optional data store configuration
+     */
+    private final DataStoreConfig dataStoreConfig;
 
     /**
      * Creates a repository configuration object.
@@ -237,7 +242,7 @@
             String workspaceDirectory, String workspaceConfigDirectory,
             String defaultWorkspace, int workspaceMaxIdleTime,
             Element template, VersioningConfig vc, SearchConfig sc,
-            ClusterConfig cc, RepositoryConfigurationParser parser) {
+            ClusterConfig cc, DataStoreConfig dataStoreConfig, RepositoryConfigurationParser parser) {
         workspaces = new HashMap();
         this.home = home;
         this.sec = sec;
@@ -250,6 +255,7 @@
         this.vc = vc;
         this.sc = sc;
         this.cc = cc;
+        this.dataStoreConfig = dataStoreConfig;
         this.parser = parser;
     }
 
@@ -742,4 +748,13 @@
     public ClusterConfig getClusterConfig() {
         return cc;
     }
+    
+    /**
+     * Returns the data store configuration. Returns <code>null</code> if data store
+     * has not been configured.
+     */
+    public DataStoreConfig getDataStoreConfig() {
+        return dataStoreConfig;
+    }
 }
+

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/RepositoryConfigurationParser.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/RepositoryConfigurationParser.java?rev=573209&r1=573208&r2=573209&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/RepositoryConfigurationParser.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/RepositoryConfigurationParser.java Thu Sep  6 03:07:41 2007
@@ -78,6 +78,9 @@
 
     /** Name of the journal configuration element. */
     public static final String JOURNAL_ELEMENT = "Journal";
+    
+    /** Name of the data store configuration element. */
+    public static final String DATA_STORE_ELEMENT = "DataStore";    
 
     /** Name of the persistence manager configuration element. */
     public static final String PERSISTENCE_MANAGER_ELEMENT =
@@ -216,10 +219,13 @@
 
         // Optional journal configuration
         ClusterConfig cc = parseClusterConfig(root);
+        
+        // Optional data store configuration
+        DataStoreConfig dsc = parseDataStoreConfig(root);
 
         return new RepositoryConfig(home, securityConfig, fsc,
                 workspaceDirectory, workspaceConfigDirectory, defaultWorkspace,
-                maxIdleTime, template, vc, sc, cc, this);
+                maxIdleTime, template, vc, sc, cc, dsc, this);
     }
 
     /**
@@ -513,6 +519,37 @@
         return new JournalConfig(
                 parseBeanConfig(cluster, JOURNAL_ELEMENT));
     }
+    
+    /**
+     * Parses data store configuration. Data store configuration uses the following format:
+     * <pre>
+     *   &lt;DataStore class="..."&gt;
+     *     &lt;param name="..." value="..."&gt;
+     *     ...
+     *   &lt;/DataStore&gt;
+     * </pre>
+     * <p/>
+     * <code>DataStore</code> is a {@link #parseBeanConfig(Element,String) bean configuration}
+     * element.
+     *
+     * @param cluster parent cluster element
+     * @return journal configuration, or <code>null</code>
+     * @throws ConfigurationException if the configuration is broken
+     */
+    protected DataStoreConfig parseDataStoreConfig(Element parent)
+            throws ConfigurationException {
+        NodeList children = parent.getChildNodes();
+        for (int i = 0; i < children.getLength(); i++) {
+            Node child = children.item(i);
+            if (child.getNodeType() == Node.ELEMENT_NODE
+                    && DATA_STORE_ELEMENT.equals(child.getNodeName())) {
+                DataStoreConfig cfg = new DataStoreConfig(parseBeanConfig(
+                        parent, DATA_STORE_ELEMENT));
+                return cfg;
+            }
+        }
+        return null;
+    }    
 
     /**
      * Parses the PersistenceManager config.

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=573209&r1=573208&r2=573209&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 Thu Sep  6 03:07:41 2007
@@ -92,5 +92,12 @@
      * Get all identifiers.
      */
     Iterator getAllIdentifiers();
+    
+    /**
+     * Initialized the data store
+     * 
+     * @param homeDir the home directory of the repository
+     */
+    void init(String homeDir);
 
 }

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=573209&r1=573208&r2=573209&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 Thu Sep  6 03:07:41 2007
@@ -30,6 +30,15 @@
 /**
  * Simple file-based data store. Data records are stored as normal files
  * named using a message digest of the contained binary stream.
+ * 
+ * Configuration:<br>
+ * <ul>
+ * <li>&lt;param name="className" value="org.apache.jackrabbit.core.data.FileDataStore"/>
+ * <li>&lt;param name="{@link #setPath(String) path}" value="/data/datastore"/>
+ * </ul>
+ * 
+ * <p>
+ * If the directory is not set, the directory &lt;repository home&gt;/repository/datastore is used.
  * <p>
  * A three level directory structure is used to avoid placing too many
  * files in a single directory. The chosen structure is designed to scale
@@ -61,15 +70,34 @@
      * The directory that contains all the data record files. The structure
      * of content within this directory is controlled by this class.
      */
-    private final File directory;
+    private File directory;
+    
+    /**
+     * The name of the directory that contains all the data record files. The structure
+     * of content within this directory is controlled by this class.
+     */
+    private String path;
 
     /**
-     * Creates a data store based on the given directory.
+     * Creates a uninitialized data store.
      *
-     * @param directory data store directory
      */
-    public FileDataStore(File directory) {
-        this.directory = directory;
+    public FileDataStore() {
+    }
+    
+    /**
+     * Initialized the data store.
+     * If the path is not set, &lt;repository home&gt;/repository/datastore is used.
+     * This directory is automatically created if it does not yet exist.
+     * 
+     * @param config the repository configuration
+     */
+    public void init(String homeDir) {
+        if (path == null) {
+            path = homeDir + "/repository/datastore";
+        }
+        directory = new File(path);
+        directory.mkdirs();
     }
 
     /**
@@ -132,6 +160,9 @@
             }
             if (!file.exists()) {
                 temporary.renameTo(file);
+                if (!file.exists()) {
+                    throw new IOException("Can not rename " + temporary.getAbsolutePath() + " to " + file.getAbsolutePath() + " (media read only?)");
+                }
             } else {
                 long now = System.currentTimeMillis();
                 if (file.lastModified() < now) {
@@ -247,6 +278,24 @@
             }
         }
         return identifiers.iterator();
+    }
+
+    /**
+     * Get the name of the directory where this data store keeps the files.
+     * 
+     * @return the full path name
+     */
+    public String getPath() {
+        return path;
+    }
+
+    /**
+     * Set the name of the directory where this data store keeps the files.
+     * 
+     * @param path the full path name
+     */
+    public void setPath(String directoryName) {
+        this.path = directoryName;
     }
 
 }

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/bundle/util/BundleBinding.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/bundle/util/BundleBinding.java?rev=573209&r1=573208&r2=573209&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/bundle/util/BundleBinding.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/bundle/util/BundleBinding.java Thu Sep  6 03:07:41 2007
@@ -288,7 +288,7 @@
         writeModCount(out, bundle.getModCount());
 
         // set size of bundle
-        bundle.setSize(out.size()-size);
+        bundle.setSize(out.size() - size);
     }
 
     /**
@@ -305,7 +305,7 @@
         // type and modcount
         int type = in.readInt();
         entry.setModCount((short) ((type >> 16) & 0x0ffff));
-        type&=0x0ffff;
+        type &= 0x0ffff;
         entry.setType(type);
 
         // multiValued
@@ -369,8 +369,8 @@
                     int len = in.readInt();
                     byte[] bytes = new byte[len];
                     int pos = 0;
-                    while (pos<len) {
-                        pos+= in.read(bytes, pos, len-pos);
+                    while (pos < len) {
+                        pos += in.read(bytes, pos, len - pos);
                     }
                     val = InternalValue.valueOf(new String(bytes, "UTF-8"), type);
             }
@@ -522,8 +522,8 @@
                     try {
                         byte[] bytes = new byte[len];
                         int pos = 0;
-                        while (pos<len) {
-                            pos+= in.read(bytes, pos, len-pos);
+                        while (pos < len) {
+                            pos += in.read(bytes, pos, len - pos);
                         }
                         log.info("  string: " + new String(bytes, "UTF-8"));
                     } catch (IOException e) {
@@ -558,7 +558,7 @@
             InternalValue val = values[i];
             switch (state.getType()) {
                 case PropertyType.BINARY:
-                    if(InternalValue.USE_DATA_STORE) {
+                    if (InternalValue.USE_DATA_STORE && dataStore != null) {
                         out.writeInt(-2);
                         out.writeUTF(val.toString());
                         break;
@@ -622,7 +622,7 @@
                             try {
                                 int pos = 0;
                                 while (pos < size) {
-                                    int n = in.read(data, pos, (int) size-pos);
+                                    int n = in.read(data, pos, (int) size - pos);
                                     if (n < 0) {
                                         throw new EOFException();
                                     }

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/bundle/util/ItemStateBinding.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/bundle/util/ItemStateBinding.java?rev=573209&r1=573208&r2=573209&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/bundle/util/ItemStateBinding.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/bundle/util/ItemStateBinding.java Thu Sep  6 03:07:41 2007
@@ -64,12 +64,12 @@
     /**
      * serialization version 1
      */
-    public final static int VERSION_1 = 1;
+    public static final int VERSION_1 = 1;
 
     /**
      * current version
      */
-    public final static int VERSION_CURRENT = VERSION_1;
+    public static final int VERSION_CURRENT = VERSION_1;
 
     /**
      * the namespace index
@@ -288,7 +288,7 @@
         // type and modcount
         int type = in.readInt();
         state.setModCount((short) ((type >> 16) & 0x0ffff));
-        type&=0x0ffff;
+        type &= 0x0ffff;
         state.setType(type);
         // multiValued
         state.setMultiValued(in.readBoolean());
@@ -350,9 +350,9 @@
                     // Strings are serialized as <length><byte[]>
                     int len = in.readInt();
                     byte[] bytes = new byte[len];
-                    int pos=0;
+                    int pos = 0;
                     while (pos < len) {
-                        pos+= in.read(bytes, pos, len-pos);
+                        pos += in.read(bytes, pos, len - pos);
                     }
                     val = InternalValue.valueOf(new String(bytes, "UTF-8"), type);
             }
@@ -384,7 +384,7 @@
             switch (state.getType()) {
                 case PropertyType.BINARY:
                     try {
-                        if(InternalValue.USE_DATA_STORE) {
+                        if (InternalValue.USE_DATA_STORE && dataStore != null) {
                             out.writeInt(-2);
                             out.writeUTF(val.toString());
                             break;
@@ -424,7 +424,7 @@
                             try {
                                 int pos = 0;
                                 while (pos < size) {
-                                    int n = in.read(data, pos, (int) size-pos);
+                                    int n = in.read(data, pos, (int) size - pos);
                                     if (n < 0) {
                                         throw new EOFException();
                                     }
@@ -483,9 +483,9 @@
     public UUID readUUID(DataInputStream in) throws IOException {
         if (in.readBoolean()) {
             byte[] bytes = new byte[16];
-            int pos=0;
+            int pos = 0;
             while (pos < 16) {
-                pos += in.read(bytes, pos, 16-pos);
+                pos += in.read(bytes, pos, 16 - pos);
             }
             return new UUID(bytes);
         } else {
@@ -517,9 +517,9 @@
     public NodeId readID(DataInputStream in) throws IOException {
         if (in.readBoolean()) {
             byte[] bytes = new byte[16];
-            int pos=0;
+            int pos = 0;
             while (pos < 16) {
-                pos += in.read(bytes, pos, 16-pos);
+                pos += in.read(bytes, pos, 16 - pos);
             }
             return new NodeId(new UUID(bytes));
         } else {
@@ -608,7 +608,7 @@
      */
     public QName readIndexedQName(DataInputStream in) throws IOException {
         int index = in.readInt();
-        if (index<0) {
+        if (index < 0) {
             return null;
         } else {
             String uri = nsIndex.indexToString(index);

Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/value/BLOBInResource.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/value/BLOBInResource.java?rev=573209&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/value/BLOBInResource.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/value/BLOBInResource.java Thu Sep  6 03:07:41 2007
@@ -0,0 +1,154 @@
+/*
+ * 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 org.apache.jackrabbit.core.fs.FileSystemException;
+import org.apache.jackrabbit.core.fs.FileSystemResource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import javax.jcr.RepositoryException;
+
+/**
+ * Represents binary data which is stored in a file system resource.
+ */
+public class BLOBInResource extends BLOBFileValue {
+    
+    /**
+     * The default logger
+     */
+    private static final Logger LOG = LoggerFactory.getLogger(BLOBInResource.class);
+    
+    /**
+     * the prefix of the string representation of this value
+     */    
+    private static final String PREFIX = "fsResource:";
+    
+    /**
+     * underlying file system resource
+     */
+    private final FileSystemResource fsResource;
+    
+    /**
+     * the file length
+     */    
+    private final long length;
+    
+    /**
+     * Creates a new instance from a stream.
+     *
+     * @param in the input stream
+     * @throws IOException 
+     */    
+    private BLOBInResource(FileSystemResource fsResource) throws IOException {
+        try {
+            if (!fsResource.exists()) {
+                throw new IOException(fsResource.getPath()
+                        + ": the specified resource does not exist");
+            }
+            length = fsResource.length();
+        } catch (FileSystemException fse) {
+            throw new IOException(fsResource.getPath()
+                    + ": Error while creating value: " + fse.toString());
+        }
+        this.fsResource = fsResource;
+    }
+
+    /**
+     * Creates a new instance from a file system resource.
+     *
+     * @param fsResource the resource
+     */    
+    static BLOBInResource getInstance(FileSystemResource fsResource) throws IOException {
+        return new BLOBInResource(fsResource);
+    }
+    
+    /**
+     * {@inheritDoc}
+     */
+    public void delete(boolean pruneEmptyParentDirs) {
+        try {
+            fsResource.delete(pruneEmptyParentDirs);
+        } catch (FileSystemException fse) {
+            // ignore
+            LOG.warn("Error while deleting BLOBFileValue: " + fse.getMessage());
+        }
+        
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void discard() {
+        // this instance is not backed by temporarily allocated resource/buffer
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public long getLength() {
+        return length;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public InputStream getStream() throws IllegalStateException, RepositoryException {
+        try {
+            return fsResource.getInputStream();
+        } catch (FileSystemException fse) {
+            throw new RepositoryException(fsResource.getPath()
+                    + ": the specified resource does not exist", fse);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String toString() {
+        return PREFIX +  fsResource.toString();
+    }    
+    
+    /**
+     * {@inheritDoc}
+     */
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof BLOBInResource) {
+            BLOBInResource other = (BLOBInResource) obj;
+            return length == other.length && fsResource.equals(other.fsResource);
+        }
+        return false;
+    }
+    
+    /**
+     * Returns zero to satisfy the Object equals/hashCode contract.
+     * This class is mutable and not meant to be used as a hash key.
+     *
+     * @return always zero
+     * @see Object#hashCode()
+     */
+    public int hashCode() {
+        return 0;
+    }    
+    
+}

Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/value/BLOBInResource.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/value/BLOBInTempFile.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/value/BLOBInTempFile.java?rev=573209&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/value/BLOBInTempFile.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/value/BLOBInTempFile.java Thu Sep  6 03:07:41 2007
@@ -0,0 +1,172 @@
+/*
+ * 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 org.apache.jackrabbit.util.TransientFileFactory;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import javax.jcr.RepositoryException;
+
+/**
+ * Represents binary data which is stored in a temporary file.
+ */
+public class BLOBInTempFile extends BLOBFileValue {
+    
+    /**
+     * the prefix of the string representation of this value
+     */    
+    private static final String PREFIX = "file:";
+    
+    private File file;
+    private long length;
+    private final boolean temp;
+    
+    /**
+     * Creates a new instance from a stream.
+     *
+     * @param in the input stream
+     * @throws IOException 
+     */    
+    private BLOBInTempFile(InputStream in, boolean temp) throws IOException {
+        this.temp = temp;
+        OutputStream out = null;
+        try {
+            TransientFileFactory fileFactory = TransientFileFactory.getInstance();
+            file = fileFactory.createTransientFile("bin", null, null);
+            out = new FileOutputStream(file);
+            byte[] buffer = new byte[4 * 1024];
+            while (true) {
+                int len = in.read(buffer);
+                if (len < 0) {
+                    break;
+                }
+                out.write(buffer, 0, len);
+                length += len;                
+            }
+        } finally {
+            if (out != null) {
+                out.close();
+            }
+            in.close();
+        }
+    }
+
+    /**
+     * Creates a new instance from file.
+     *
+     * @param in the input stream
+     */    
+    private BLOBInTempFile(File file, boolean temp) {
+        this.file = file;
+        this.length = file.length();
+        this.temp = temp;
+    }
+
+    /**
+     * Creates a new instance from a stream.
+     *
+     * @param in the stream
+     */    
+    static BLOBInTempFile getInstance(InputStream in, boolean temp) throws IOException {
+        return new BLOBInTempFile(in, temp);
+    }
+    
+    /**
+     * Creates a new instance from a file.
+     *
+     * @param file the file
+     */    
+    static BLOBInTempFile getInstance(File file, boolean temp) throws IOException {
+        return new BLOBInTempFile(file, temp);
+    }    
+    
+    /**
+     * {@inheritDoc}
+     */
+    public void delete(boolean pruneEmptyParentDirs) {
+        file.delete();
+        length = -1;
+        file = null;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void discard() {
+        if (temp) {
+            delete(true);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public long getLength() {
+        return length;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public InputStream getStream() throws IllegalStateException, RepositoryException {
+        try {
+            return new FileInputStream(file);
+        } catch (FileNotFoundException fnfe) {
+            throw new RepositoryException("file backing binary value not found", fnfe);
+        }        
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String toString() {
+        return PREFIX + file.toString();
+    }    
+    
+    /**
+     * {@inheritDoc}
+     */
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof BLOBInTempFile) {
+            BLOBInTempFile other = (BLOBInTempFile) obj;
+            return (file == other.file) || (length == other.length && file != null && file.equals(other.file));
+        }
+        return false;
+    }
+    
+    /**
+     * Returns zero to satisfy the Object equals/hashCode contract.
+     * This class is mutable and not meant to be used as a hash key.
+     *
+     * @return always zero
+     * @see Object#hashCode()
+     */
+    public int hashCode() {
+        return 0;
+    }    
+    
+}

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=573209&r1=573208&r2=573209&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 Thu Sep  6 03:07:41 2007
@@ -122,11 +122,7 @@
             case PropertyType.BINARY:
                 try {
                     if (USE_DATA_STORE) {
-                        if (store == null) {
-                            return new InternalValue(BLOBInTempFile.getInstance(value.getStream()));
-                        } else {
-                            return new InternalValue(getBLOBFileValue(store, value.getStream()));
-                        }
+                        return new InternalValue(getBLOBFileValue(store, value.getStream()));
                     }
                     if (value instanceof BLOBFileValue) {
                         return new InternalValue((BLOBFileValue) value);
@@ -169,7 +165,6 @@
                 }
             case PropertyType.STRING:
                 return create(value.getString());
-
             default:
                 throw new IllegalArgumentException("illegal value");
         }
@@ -235,17 +230,18 @@
      */
     public static InternalValue createTemporary(InputStream value) throws IOException {
         if (USE_DATA_STORE) {        
-            return new InternalValue(BLOBInTempFile.getInstance(value));
+            return new InternalValue(getBLOBFileValue(null, value));
         }
         return new InternalValue(new BLOBValue(value, true));
     }
     
     /**
-     * Create an internal value that is backed by a temporary file (if data store usage is disabled)
-     * or (if it is enabled) in the data store.
+     * Create an internal value that is backed by a temporary file 
+     * (if data store usage is disabled or the store is null)
+     * or in the data store if it is not null and enabled.
      * 
      * @param value the stream
-     * @param store the data store
+     * @param store the data store or null to use a temporary file
      * @return the internal value
      */
     public static InternalValue createTemporary(InputStream value, DataStore store) throws IOException {
@@ -262,6 +258,9 @@
      * @throws IOException
      */
     public static InternalValue create(InputStream value) throws IOException {
+        if (USE_DATA_STORE) {
+            return new InternalValue(getBLOBFileValue(null, value));
+        }
         return new InternalValue(new BLOBValue(value, false));
     }
 
@@ -270,8 +269,10 @@
      * @return
      * @throws IOException
      */
-    public static InternalValue create(FileSystemResource value)
-            throws IOException {
+    public static InternalValue create(FileSystemResource value) throws IOException {
+        if (USE_DATA_STORE) {
+            return new InternalValue(BLOBInResource.getInstance(value));
+        }        
         return new InternalValue(new BLOBValue(value));
     }
 
@@ -281,6 +282,9 @@
      * @throws IOException
      */
     public static InternalValue create(File value) throws IOException {
+        if (USE_DATA_STORE) {
+            return new InternalValue(BLOBInTempFile.getInstance(value, false));
+        }                
         return new InternalValue(new BLOBValue(value));
     }
     
@@ -292,7 +296,7 @@
      * @return the value
      */    
     public static InternalValue create(DataStore store, String id) {
-        assert USE_DATA_STORE;
+        assert USE_DATA_STORE && store != null;
         return new InternalValue(getBLOBFileValue(store, id));
     }
 
@@ -613,7 +617,11 @@
         } else {
             // a few bytes are already read, need to re-build the input stream
             in = new SequenceInputStream(new ByteArrayInputStream(buffer, 0, pos), in);
-            return BLOBInDataStore.getInstance(store, in);
+            if (store != null) {
+                return BLOBInDataStore.getInstance(store, in);
+            } else {
+                return BLOBInTempFile.getInstance(in, true);
+            }
         }
     }
 

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/BufferedStringValue.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/BufferedStringValue.java?rev=573209&r1=573208&r2=573209&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/BufferedStringValue.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/BufferedStringValue.java Thu Sep  6 03:07:41 2007
@@ -34,6 +34,7 @@
 import java.io.FileOutputStream;
 import java.io.FileReader;
 import java.io.IOException;
+import java.io.InputStream;
 import java.io.OutputStreamWriter;
 import java.io.Reader;
 import java.io.StringReader;
@@ -285,6 +286,10 @@
                 } else {
                     // >= 65kb: deserialize BINARY type
                     // using Reader and temporay file
+                    if (InternalValue.USE_DATA_STORE) {
+                        Base64ReaderInputStream in = new Base64ReaderInputStream(reader());
+                        return InternalValue.createTemporary(in);
+                    }
                     TransientFileFactory fileFactory = TransientFileFactory.getInstance();
                     File tmpFile = fileFactory.createTransientFile("bin", null, null);
                     FileOutputStream out = new FileOutputStream(tmpFile);
@@ -305,6 +310,47 @@
             }
         } catch (IOException e) {
             throw new RepositoryException("Error accessing property value", e);
+        }
+    }
+    
+    private static class Base64ReaderInputStream extends InputStream {
+
+        private static final int BUFFER_SIZE = 1024;
+        private final char[] chars;
+        private final ByteArrayOutputStream out;
+        private final Reader reader;
+        private int pos;
+        private int remaining;
+        private byte[] buffer;
+
+        public Base64ReaderInputStream(Reader reader) {
+            chars = new char[BUFFER_SIZE];
+            this.reader = reader;
+            out = new ByteArrayOutputStream(BUFFER_SIZE);
+        }
+
+        private void fillBuffer() throws IOException {
+            int len = reader.read(chars, 0, BUFFER_SIZE);
+            if (len < 0) {
+                remaining = -1;
+                return;
+            }
+            Base64.decode(chars, 0, len, out);
+            buffer = out.toByteArray();
+            pos = 0;
+            remaining = buffer.length;
+            out.reset();
+        }
+
+        public int read() throws IOException {
+            if (remaining == 0) {
+                fillBuffer();
+            }
+            if (remaining < 0) {
+                return -1;
+            }
+            remaining--;
+            return buffer[pos++] & 0xff;
         }
     }