You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by st...@apache.org on 2004/10/27 17:47:15 UTC
svn commit: rev 55707 - in incubator/jackrabbit/trunk: . src/java/org/apache/jackrabbit/core src/java/org/apache/jackrabbit/core/state src/java/org/apache/jackrabbit/core/state/obj src/java/org/apache/jackrabbit/core/state/xml xdocs
Author: stefan
Date: Wed Oct 27 08:47:13 2004
New Revision: 55707
Added:
incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/obj/
incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/obj/BLOBStore.java (contents, props changed)
incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/obj/ObjectPersistenceManager.java (contents, props changed)
Modified:
incubator/jackrabbit/trunk/ToDo.txt
incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/InternalValue.java
incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/ItemImpl.java
incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/RepositoryImpl.java
incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/SessionImpl.java
incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/Test.java
incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/PersistenceManager.java
incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/xml/XMLPersistenceManager.java
incubator/jackrabbit/trunk/xdocs/tasks.xml
Log:
- added new files-system based PersistenceManager
(org.apache.jackrabbit.core.state.obj.ObjectPersistenceManager)
implementation that uses more efficient serialization format
- misc. minor fixes
- updated todo.txt and tasks.xml
Modified: incubator/jackrabbit/trunk/ToDo.txt
==============================================================================
--- incubator/jackrabbit/trunk/ToDo.txt (original)
+++ incubator/jackrabbit/trunk/ToDo.txt Wed Oct 27 08:47:13 2004
@@ -5,7 +5,6 @@
is it complete :(
- locking
-- jta support
- access control (jaas)
- current persistence model (nodes and properties are stored in separate
files) leads to *very* slow performance in a normal filesystem;
@@ -25,7 +24,6 @@
- HierarchyManager: cache Path objects (key: ItemId, value: Path[]);
update cache on hierarchy changes (move, hardlink, remove, etc)
- inline @todo comments: resolve/implement
-- ItemState: hide STATUS_* flags, use set* and is* methods instead
- javaDoc, javaDoc, javaDoc
- logging: use commons logging instead of log4j
- logging: remove unnecessary output, check log categories/verbosity,
Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/InternalValue.java
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/InternalValue.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/InternalValue.java Wed Oct 27 08:47:13 2004
@@ -220,7 +220,7 @@
*/
public static InternalValue[] create(QName[] values) {
InternalValue[] ret = new InternalValue[values.length];
- for (int i=0; i<values.length; i++) {
+ for (int i = 0; i < values.length; i++) {
ret[i] = new InternalValue(values[i]);
}
return ret;
@@ -232,7 +232,7 @@
*/
public static InternalValue[] create(String[] values) {
InternalValue[] ret = new InternalValue[values.length];
- for (int i=0; i<values.length; i++) {
+ for (int i = 0; i < values.length; i++) {
ret[i] = new InternalValue(values[i]);
}
return ret;
Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/ItemImpl.java
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/ItemImpl.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/ItemImpl.java Wed Oct 27 08:47:13 2004
@@ -1089,7 +1089,6 @@
*/
ReferenceManager refMgr = wsp.getReferenceManager();
synchronized (refMgr) {
-
/**
* build list of transient descendents in the attic
* (i.e. those marked as 'removed')
Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/RepositoryImpl.java
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/RepositoryImpl.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/RepositoryImpl.java Wed Oct 27 08:47:13 2004
@@ -185,15 +185,7 @@
// ignore
}
}
- /**
- * use hard-coded uuid for root node rather than generating
- * a different uuid per repository instance; using a
- * hard-coded uuid makes it easier to copy/move entire
- * workspaces from one repository instance to another.
- */
- //rootNodeUUID = new UUID(new String(chars)).toString();
- rootNodeUUID = ROOT_NODE_UUID;
-
+ rootNodeUUID = new UUID(new String(chars)).toString();
} catch (Exception e) {
String msg = "failed to load persisted repository state";
log.error(msg, e);
@@ -201,8 +193,17 @@
}
} else {
// create new uuid
+/*
UUID rootUUID = UUID.randomUUID(); // version 4 uuid
rootNodeUUID = rootUUID.toString();
+*/
+ /**
+ * use hard-coded uuid for root node rather than generating
+ * a different uuid per repository instance; using a
+ * hard-coded uuid makes it easier to copy/move entire
+ * workspaces from one repository instance to another.
+ */
+ rootNodeUUID = ROOT_NODE_UUID;
try {
// persist uuid of the repository's root node
OutputStream out = uuidFile.getOutputStream();
@@ -221,7 +222,7 @@
// store uuid in text format for better readability
OutputStreamWriter writer = new OutputStreamWriter(out);
try {
- writer.write(rootUUID.toString());
+ writer.write(rootNodeUUID);
} finally {
try {
writer.close();
@@ -536,13 +537,6 @@
return;
}
- // persist repository properties
- try {
- storeRepProps();
- } catch (RepositoryException e) {
- log.error("failed to persist repository properties", e);
- }
-
// stop / dispose all ObservationManagers
for (Iterator it = wspObsMgrFactory.values().iterator(); it.hasNext();) {
ObservationManagerFactory obsMgr = (ObservationManagerFactory) it.next();
@@ -556,14 +550,37 @@
}
/**
- * todo free resources, shutdown workspaces, close sessions,
- * shutdown item state mgr's, persistence mgr's, etc.
+ * todo close sessions, close item state mgr's, free resources, etc.
*/
+
+ for (Iterator it = wspConfigs.values().iterator(); it.hasNext();) {
+ WorkspaceConfig wspConfig = (WorkspaceConfig) it.next();
+ try {
+ // close workspace file system
+ wspConfig.getFileSystem().close();
+ } catch (FileSystemException e) {
+ log.error("Error while closing filesystem of workspace " + wspConfig.getName(), e);
+ }
+ try {
+ // close persistence manager
+ wspConfig.getPersistenceManager().close();
+ } catch (Exception e) {
+ log.error("Error while closing persistence manager of workspace " + wspConfig.getName(), e);
+ }
+ }
+
+ // persist repository properties
+ try {
+ storeRepProps();
+ } catch (RepositoryException e) {
+ log.error("failed to persist repository properties", e);
+ }
+
try {
- // close master file system (this will also invalidate sub file systems)
+ // close repository file system
repStore.close();
} catch (FileSystemException e) {
- log.error("Error while closing filesystem", e);
+ log.error("Error while closing repository filesystem", e);
}
// make sure this instance is not used anymore
Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/SessionImpl.java
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/SessionImpl.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/SessionImpl.java Wed Oct 27 08:47:13 2004
@@ -121,7 +121,6 @@
WorkspaceConfig wspConfig)
throws RepositoryException {
this.rep = rep;
-
if (credentials instanceof SimpleCredentials) {
SimpleCredentials sc = (SimpleCredentials) credentials;
// clear password for security reasons
@@ -139,14 +138,11 @@
} else {
userId = null;
}
-
nsMappings = new TransientNamespaceMappings(rep.getNamespaceRegistry());
-
ntMgr = new NodeTypeManagerImpl(rep.getNodeTypeRegistry(), getNamespaceResolver());
String wspName = wspConfig.getName();
wsp = new WorkspaceImpl(wspConfig, rep.getWorkspaceStateManager(wspName),
rep.getWorkspaceReferenceManager(wspName), rep, this);
-
itemStateMgr = createSessionItemStateManager(wsp.getPersistentStateManager());
hierMgr = itemStateMgr.getHierarchyMgr();
itemMgr = createItemManager(itemStateMgr, hierMgr);
@@ -173,11 +169,8 @@
protected SessionImpl(RepositoryImpl rep, String userId, WorkspaceConfig wspConfig)
throws RepositoryException {
this.rep = rep;
-
this.userId = userId;
-
nsMappings = new TransientNamespaceMappings(rep.getNamespaceRegistry());
-
ntMgr = new NodeTypeManagerImpl(rep.getNodeTypeRegistry(), getNamespaceResolver());
String wspName = wspConfig.getName();
wsp = new WorkspaceImpl(wspConfig, rep.getWorkspaceStateManager(wspName),
@@ -203,7 +196,6 @@
* @return session item state manager
*/
protected SessionItemStateManager createSessionItemStateManager(PersistentItemStateProvider provider) {
-
return new SessionItemStateManager(rep.getRootNodeUUID(), provider, getNamespaceResolver());
}
@@ -214,7 +206,6 @@
*/
protected ItemManager createItemManager(SessionItemStateManager itemStateMgr,
HierarchyManager hierMgr) {
-
return new ItemManager(itemStateMgr, hierMgr, this,
ntMgr.getRootNodeDefinition(), rep.getRootNodeUUID());
}
Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/Test.java
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/Test.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/Test.java Wed Oct 27 08:47:13 2004
@@ -243,7 +243,7 @@
imported = root.getNode("imported");
}
- importNode(new File("d:/dev/jsr170/jackrabbit/src/java"), imported);
+ //importNode(new File("d:/dev/jsr170/jackrabbit/src/java"), imported);
if (root.hasNode("foo")) {
root.getNode("foo").remove();
@@ -294,7 +294,7 @@
System.out.println("repository properties:");
System.out.println(repProps);
- //((RepositoryImpl) r).shutdown();
+ ((RepositoryImpl) r).shutdown();
}
public static void importNode(File file, Node parent) throws Exception {
Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/PersistenceManager.java
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/PersistenceManager.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/PersistenceManager.java Wed Oct 27 08:47:13 2004
@@ -29,6 +29,11 @@
public void init(WorkspaceConfig wspConfig) throws Exception;
/**
+ * @throws Exception
+ */
+ public void close() throws Exception;
+
+ /**
* @param state
* @throws NoSuchItemStateException
* @throws ItemStateException
Added: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/obj/BLOBStore.java
==============================================================================
--- (empty file)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/obj/BLOBStore.java Wed Oct 27 08:47:13 2004
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2004 The Apache Software Foundation.
+ *
+ * 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.apache.jackrabbit.core.state.obj;
+
+import org.apache.jackrabbit.core.fs.FileSystemResource;
+import org.apache.jackrabbit.core.PropertyId;
+
+import java.io.InputStream;
+
+/**
+ * <code>BLOBStore</code> ...
+ */
+public interface BLOBStore {
+ /**
+ *
+ * @param id id of the property associated with the blob data
+ * @param index subscript of the value holding the blob data
+ * @param in
+ * @param size
+ * @return a string identifying the blob data
+ * @throws Exception
+ */
+ public String put(PropertyId id, int index, InputStream in, long size) throws Exception;
+
+ /**
+ *
+ * @param blobId
+ * @return
+ * @throws Exception
+ */
+ public FileSystemResource get(String blobId) throws Exception;
+
+ /**
+ *
+ * @param blobId
+ * @return
+ * @throws Exception
+ */
+ public boolean remove(String blobId) throws Exception;
+}
Added: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/obj/ObjectPersistenceManager.java
==============================================================================
--- (empty file)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/obj/ObjectPersistenceManager.java Wed Oct 27 08:47:13 2004
@@ -0,0 +1,746 @@
+/*
+ * Copyright 2004 The Apache Software Foundation.
+ *
+ * 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.apache.jackrabbit.core.state.obj;
+
+import org.apache.jackrabbit.core.BLOBFileValue;
+import org.apache.jackrabbit.core.InternalValue;
+import org.apache.jackrabbit.core.PropertyId;
+import org.apache.jackrabbit.core.QName;
+import org.apache.jackrabbit.core.config.WorkspaceConfig;
+import org.apache.jackrabbit.core.fs.*;
+import org.apache.jackrabbit.core.fs.FileSystem;
+import org.apache.jackrabbit.core.fs.local.LocalFileSystem;
+import org.apache.jackrabbit.core.nodetype.NodeDefId;
+import org.apache.jackrabbit.core.nodetype.PropDefId;
+import org.apache.jackrabbit.core.state.*;
+import org.apache.log4j.Logger;
+
+import javax.jcr.PropertyType;
+import java.io.*;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.*;
+
+/**
+ * <code>ObjectPersistenceManager</code> ...
+ */
+public class ObjectPersistenceManager implements BLOBStore, PersistenceManager {
+
+ private static Logger log = Logger.getLogger(ObjectPersistenceManager.class);
+
+ /**
+ * hexdigits for toString
+ */
+ private static final char[] HEXDIGITS = "0123456789abcdef".toCharArray();
+
+ /**
+ * The default encoding used in serialization
+ */
+ private static final String NODEFILENAME = ".node";
+
+ private static final String NODEREFSFILENAME = ".references";
+
+ private boolean initialized;
+
+ // file system where the item state is stored
+ private FileSystem itemStateFS;
+ // file system where BLOB data is stored
+ private FileSystem blobFS;
+
+ /**
+ * Creates a new <code>ObjectPersistenceManager</code> instance.
+ */
+ public ObjectPersistenceManager() {
+ initialized = false;
+ }
+
+ private static String buildNodeFolderPath(String uuid) {
+ StringBuffer sb = new StringBuffer();
+ char[] chars = uuid.toCharArray();
+ int cnt = 0;
+ for (int i = 0; i < chars.length; i++) {
+ if (chars[i] == '-') {
+ continue;
+ }
+ //if (cnt > 0 && cnt % 4 == 0) {
+ if (cnt == 2 || cnt == 4) {
+ sb.append('/');
+ }
+ sb.append(chars[i]);
+ cnt++;
+ }
+ return sb.toString();
+ }
+
+ private static String buildPropFilePath(String parentUUID, QName propName) {
+ String fileName;
+ try {
+ MessageDigest md5 = MessageDigest.getInstance("MD5");
+ md5.update(propName.getNamespaceURI().getBytes());
+ md5.update(propName.getLocalName().getBytes());
+ byte[] bytes = md5.digest();
+ char[] chars = new char[32];
+ for (int i = 0, j = 0; i < 16; i++) {
+ chars[j++] = HEXDIGITS[(bytes[i] >> 4) & 0x0f];
+ chars[j++] = HEXDIGITS[bytes[i] & 0x0f];
+ }
+ fileName = new String(chars);
+ } catch (NoSuchAlgorithmException nsae) {
+ // should never get here as MD5 should always be available in the JRE
+ String msg = "MD5 not available: ";
+ log.fatal(msg, nsae);
+ throw new InternalError(msg + nsae);
+ }
+ return buildNodeFolderPath(parentUUID) + "/" + fileName;
+ }
+
+ private static String buildBlobFilePath(String parentUUID, QName propName, int i) {
+ return buildNodeFolderPath(parentUUID) + "/"
+ + FileSystemPathUtil.escapeName(propName.toString()) + "." + i + ".bin";
+ }
+
+ private static String buildNodeFilePath(String uuid) {
+ return buildNodeFolderPath(uuid) + "/" + NODEFILENAME;
+ }
+
+ private static String buildNodeReferencesFilePath(String uuid) {
+ return buildNodeFolderPath(uuid) + "/" + NODEREFSFILENAME;
+ }
+
+ //------------------------------------------------< static helper methods >
+ /**
+ * Serializes the specified <code>state</code> object to the given
+ * <code>stream</code>.
+ *
+ * @param state <code>state</code> to serialize
+ * @param stream the stream where the <code>state</code> should be serialized to
+ * @throws Exception if an error occurs during the serialization
+ * @see #deserialize(PersistentNodeState, InputStream)
+ */
+ public static void serialize(PersistentNodeState state, OutputStream stream)
+ throws Exception {
+ DataOutputStream out = new DataOutputStream(stream);
+ // uuid
+ out.writeUTF(state.getUUID());
+ // primaryType
+ out.writeUTF(state.getNodeTypeName().toString());
+ // parentUUID
+ out.writeUTF(state.getParentUUID() == null ? "" : state.getParentUUID());
+ // definitionId
+ out.writeUTF(state.getDefinitionId().toString());
+ // parentUUIDs
+ Collection c = state.getParentUUIDs();
+ out.writeInt(c.size()); // count
+ for (Iterator iter = c.iterator(); iter.hasNext();) {
+ out.writeUTF((String) iter.next()); // uuid
+ }
+ // mixin types
+ c = state.getMixinTypeNames();
+ out.writeInt(c.size()); // count
+ for (Iterator iter = c.iterator(); iter.hasNext();) {
+ out.writeUTF(iter.next().toString()); // name
+ }
+ // properties (names)
+ c = state.getPropertyEntries();
+ out.writeInt(c.size()); // count
+ for (Iterator iter = c.iterator(); iter.hasNext();) {
+ NodeState.PropertyEntry entry = (NodeState.PropertyEntry) iter.next();
+ out.writeUTF(entry.getName().toString()); // name
+ }
+ // child nodes (list of name/uuid pairs)
+ c = state.getChildNodeEntries();
+ out.writeInt(c.size()); // count
+ for (Iterator iter = c.iterator(); iter.hasNext();) {
+ NodeState.ChildNodeEntry entry = (NodeState.ChildNodeEntry) iter.next();
+ out.writeUTF(entry.getName().toString()); // name
+ out.writeUTF(entry.getUUID()); // uuid
+ }
+ }
+
+ /**
+ * Deserializes a <code>state</code> object from the given <code>stream</code>.
+ *
+ * @param state <code>state</code> to deserialize
+ * @param stream the stream where the <code>state</code> should be deserialized from
+ * @throws Exception if an error occurs during the deserialization
+ * @see #serialize(PersistentNodeState, OutputStream)
+ */
+ public static void deserialize(PersistentNodeState state, InputStream stream)
+ throws Exception {
+ DataInputStream in = new DataInputStream(stream);
+ // check uuid
+ String s = in.readUTF();
+ if (!state.getUUID().equals(s)) {
+ String msg = "invalid serialized state: uuid mismatch";
+ log.error(msg);
+ throw new ItemStateException(msg);
+ }
+
+ // deserialize node state
+
+ // primaryType
+ s = in.readUTF();
+ state.setNodeTypeName(QName.valueOf(s));
+ // parentUUID
+ s = in.readUTF();
+ if (s.length() > 0) {
+ state.setParentUUID(s);
+ }
+ // definitionId
+ s = in.readUTF();
+ state.setDefinitionId(NodeDefId.valueOf(s));
+ // parentUUIDs
+ int count = in.readInt(); // count
+ List list = new ArrayList(count);
+ for (int i = 0; i < count; i++) {
+ list.add(in.readUTF()); // uuid
+ }
+ if (list.size() > 0) {
+ state.setParentUUIDs(list);
+ }
+ // mixin types
+ count = in.readInt(); // count
+ Set set = new HashSet(count);
+ for (int i = 0; i < count; i++) {
+ set.add(QName.valueOf(in.readUTF())); // name
+ }
+ if (set.size() > 0) {
+ state.setMixinTypeNames(set);
+ }
+ // properties (names)
+ count = in.readInt(); // count
+ for (int i = 0; i < count; i++) {
+ state.addPropertyEntry(QName.valueOf(in.readUTF())); // name
+ }
+ // child nodes (list of name/uuid pairs)
+ count = in.readInt(); // count
+ for (int i = 0; i < count; i++) {
+ QName name = QName.valueOf(in.readUTF()); // name
+ String s1 = in.readUTF(); // uuid
+ state.addChildNodeEntry(name, s1);
+ }
+ }
+
+ /**
+ * Serializes the specified <code>state</code> object to the given
+ * <code>stream</code>.
+ *
+ * @param state <code>state</code> to serialize
+ * @param stream the stream where the <code>state</code> should be serialized to
+ * @param blobStore handler for blob data
+ * @throws Exception if an error occurs during the serialization
+ * @see #deserialize(PersistentPropertyState, InputStream, BLOBStore)
+ */
+ public static void serialize(PersistentPropertyState state,
+ OutputStream stream,
+ BLOBStore blobStore)
+ throws Exception {
+ DataOutputStream out = new DataOutputStream(stream);
+ // type
+ out.writeInt(state.getType());
+ // definitionId
+ out.writeUTF(state.getDefinitionId().toString());
+ // values
+ InternalValue[] values = state.getValues();
+ out.writeInt(values.length); // count
+ for (int i = 0; i < values.length; i++) {
+ InternalValue val = values[i];
+ if (state.getType() == PropertyType.BINARY) {
+ // special handling required for binary value:
+ // spool binary value to file in blob store
+ BLOBFileValue blobVal = (BLOBFileValue) val.internalValue();
+ String blobId = blobStore.put((PropertyId) state.getId(), i, blobVal.getStream(), blobVal.getLength());
+ // store id of blob as property value
+ out.writeUTF(blobId); // value
+ // replace value instance with value
+ // backed by resource in blob store and delete temp file
+ values[i] = InternalValue.create(blobStore.get(blobId));
+ if (blobVal.isTempFile()) {
+ blobVal.delete();
+ blobVal = null;
+ }
+ } else {
+ out.writeUTF(val.toString()); // value
+ }
+ }
+ }
+
+ /**
+ * Deserializes a <code>state</code> object from the given <code>stream</code>.
+ *
+ * @param state <code>state</code> to deserialize
+ * @param stream the stream where the <code>state</code> should be deserialized from
+ * @param blobStore handler for blob data
+ * @throws Exception if an error occurs during the deserialization
+ * @see #serialize(PersistentPropertyState, OutputStream, BLOBStore)
+ */
+ public static void deserialize(PersistentPropertyState state,
+ InputStream stream,
+ BLOBStore blobStore)
+ throws Exception {
+ DataInputStream in = new DataInputStream(stream);
+
+ // type
+ int type = in.readInt();
+ state.setType(type);
+ // definitionId
+ String s = in.readUTF();
+ state.setDefinitionId(PropDefId.valueOf(s));
+ // values
+ int count = in.readInt(); // count
+ InternalValue[] values = new InternalValue[count];
+ for (int i = 0; i < count; i++) {
+ InternalValue val;
+ s = in.readUTF(); // value
+ if (type == PropertyType.BINARY) {
+ // special handling required for binary value:
+ // the value stores the id of the blob resource in the blob store
+ val = InternalValue.create(blobStore.get(s));
+ } else {
+ val = InternalValue.valueOf(s, type);
+ }
+ values[i] = val;
+ }
+ state.setValues(values);
+ }
+
+ /**
+ * Serializes the specified <code>NodeReferences</code> object to the given
+ * <code>stream</code>.
+ *
+ * @param refs object to serialize
+ * @param stream the stream where the object should be serialized to
+ * @throws IOException if an error occurs during the serialization
+ * @see #deserialize(NodeReferences, InputStream)
+ */
+ public static void serialize(NodeReferences refs, OutputStream stream)
+ throws IOException {
+ DataOutputStream out = new DataOutputStream(stream);
+
+ // references
+ Collection c = refs.getReferences();
+ out.writeInt(c.size()); // count
+ for (Iterator iter = c.iterator(); iter.hasNext();) {
+ PropertyId propId = (PropertyId) iter.next();
+ out.writeUTF(propId.toString()); // propertyId
+ }
+ }
+
+ /**
+ * Deserializes a <code>NodeReferences</code> object from the given
+ * <code>stream</code>.
+ *
+ * @param refs object to deserialize
+ * @param stream the stream where the object should be deserialized from
+ * @throws Exception if an error occurs during the deserialization
+ * @see #serialize(NodeReferences, OutputStream)
+ */
+ public static void deserialize(NodeReferences refs, InputStream stream)
+ throws Exception {
+ DataInputStream in = new DataInputStream(stream);
+
+ refs.clearAllReferences();
+
+ // references
+ int count = in.readInt(); // count
+ for (int i = 0; i < count; i++) {
+ refs.addReference(PropertyId.valueOf(in.readUTF())); // propertyId
+ }
+ }
+
+ //------------------------------------------------------------< BLOBStore >
+ /**
+ * @see BLOBStore#get
+ */
+ public FileSystemResource get(String blobId) throws Exception {
+ return new FileSystemResource(blobFS, blobId);
+ }
+
+ /**
+ * @see BLOBStore#put
+ */
+ public String put(PropertyId id, int index, InputStream in, long size) throws Exception {
+ String path = buildBlobFilePath(id.getParentUUID(), id.getName(), index);
+ OutputStream out = null;
+ FileSystemResource internalBlobFile = new FileSystemResource(blobFS, path);
+ internalBlobFile.makeParentDirs();
+ try {
+ out = new BufferedOutputStream(internalBlobFile.getOutputStream());
+ byte[] buffer = new byte[8192];
+ int read = 0;
+ while ((read = in.read(buffer)) > 0) {
+ out.write(buffer, 0, read);
+ }
+ } finally {
+ out.close();
+ }
+ return path;
+ }
+
+ /**
+ * @see BLOBStore#remove
+ */
+ public boolean remove(String blobId) throws Exception {
+ FileSystemResource res = new FileSystemResource(blobFS, blobId);
+ if (!res.exists()) {
+ return false;
+ }
+ res.delete();
+ // prune empty folders
+ String parentDir = FileSystemPathUtil.getParentDir(blobId);
+ while (!parentDir.equals(FileSystem.SEPARATOR)
+ && !blobFS.hasChildren(parentDir)) {
+ blobFS.deleteFolder(parentDir);
+ parentDir = FileSystemPathUtil.getParentDir(parentDir);
+ }
+ return true;
+ }
+
+ //---------------------------------------------------< PersistenceManager >
+ /**
+ * @see PersistenceManager#init
+ */
+ public void init(WorkspaceConfig wspConfig) throws Exception {
+ FileSystem wspFS = wspConfig.getFileSystem();
+ itemStateFS = new BasedFileSystem(wspFS, "/data");
+
+ /**
+ * store blob's in local file system in a sub directory
+ * of the workspace home directory
+ */
+ LocalFileSystem blobFS = new LocalFileSystem();
+ blobFS.setPath(wspConfig.getHomeDir() + "/blobs");
+ blobFS.init();
+ this.blobFS = blobFS;
+
+ initialized = true;
+ }
+
+ /**
+ * @see PersistenceManager#close
+ */
+ public synchronized void close() throws Exception {
+ if (!initialized) {
+ return;
+ }
+
+ try {
+ // close blob store
+ blobFS.close();
+ /**
+ * there's no need close the item state store because it
+ * is based in the workspace's file system which is
+ * closed by the repository
+ */
+ } finally {
+ initialized = false;
+ }
+ }
+
+ /**
+ * @see PersistenceManager#load(PersistentNodeState)
+ */
+ public synchronized void load(PersistentNodeState state)
+ throws NoSuchItemStateException, ItemStateException {
+ if (!initialized) {
+ throw new IllegalStateException("not initialized");
+ }
+
+ String uuid = state.getUUID();
+ String nodeFilePath = buildNodeFilePath(uuid);
+
+ try {
+ if (!itemStateFS.isFile(nodeFilePath)) {
+ throw new NoSuchItemStateException(uuid);
+ }
+ } catch (FileSystemException fse) {
+ String msg = "failed to read node state: " + uuid;
+ log.error(msg, fse);
+ throw new ItemStateException(msg, fse);
+ }
+
+ try {
+ BufferedInputStream in =
+ new BufferedInputStream(itemStateFS.getInputStream(nodeFilePath));
+ try {
+ deserialize(state, in);
+ return;
+ } catch (Exception e) {
+ String msg = "failed to read node state: " + uuid;
+ log.error(msg, e);
+ throw new ItemStateException(msg, e);
+ } finally {
+ in.close();
+ }
+ } catch (Exception e) {
+ String msg = "failed to read node state: " + uuid;
+ log.error(msg, e);
+ throw new ItemStateException(msg, e);
+ }
+ }
+
+ /**
+ * @see PersistenceManager#load(PersistentPropertyState)
+ */
+ public synchronized void load(PersistentPropertyState state)
+ throws NoSuchItemStateException, ItemStateException {
+ if (!initialized) {
+ throw new IllegalStateException("not initialized");
+ }
+
+ String parentUUID = state.getParentUUID();
+ QName propName = state.getName();
+ String propFilePath = buildPropFilePath(parentUUID, propName);
+
+ try {
+ if (!itemStateFS.isFile(propFilePath)) {
+ throw new NoSuchItemStateException(parentUUID + "/" + propName);
+ }
+ } catch (FileSystemException fse) {
+ String msg = "failed to read property state: " + parentUUID + "/" + propName;
+ log.error(msg, fse);
+ throw new ItemStateException(msg, fse);
+ }
+
+ try {
+ BufferedInputStream in =
+ new BufferedInputStream(itemStateFS.getInputStream(propFilePath));
+ try {
+ deserialize(state, in, this);
+ return;
+ } finally {
+ in.close();
+ }
+ } catch (Exception e) {
+ String msg = "failed to read property state: " + parentUUID + "/" + propName;
+ log.error(msg, e);
+ throw new ItemStateException(msg, e);
+ }
+ }
+
+ /**
+ * @see PersistenceManager#store
+ */
+ public synchronized void store(PersistentNodeState state) throws ItemStateException {
+ if (!initialized) {
+ throw new IllegalStateException("not initialized");
+ }
+
+ String uuid = state.getUUID();
+ String nodeFilePath = buildNodeFilePath(uuid);
+ FileSystemResource nodeFile = new FileSystemResource(itemStateFS, nodeFilePath);
+ try {
+ nodeFile.makeParentDirs();
+ BufferedOutputStream out = new BufferedOutputStream(nodeFile.getOutputStream());
+ try {
+ // serialize node state
+ serialize(state, out);
+ return;
+ } finally {
+ out.close();
+ }
+ } catch (Exception e) {
+ String msg = "failed to write node state: " + uuid;
+ log.error(msg, e);
+ throw new ItemStateException(msg, e);
+ }
+ }
+
+ /**
+ * @see PersistenceManager#store
+ */
+ public synchronized void store(PersistentPropertyState state) throws ItemStateException {
+ if (!initialized) {
+ throw new IllegalStateException("not initialized");
+ }
+
+ String propFilePath = buildPropFilePath(state.getParentUUID(), state.getName());
+ FileSystemResource propFile = new FileSystemResource(itemStateFS, propFilePath);
+ try {
+ propFile.makeParentDirs();
+ BufferedOutputStream out = new BufferedOutputStream(propFile.getOutputStream());
+ try {
+ // serialize property state
+ serialize(state, out, this);
+ return;
+ } finally {
+ out.close();
+ }
+ } catch (Exception e) {
+ String msg = "failed to store property state: " + state.getParentUUID() + "/" + state.getName();
+ log.error(msg, e);
+ throw new ItemStateException(msg, e);
+ }
+ }
+
+ /**
+ * @see PersistenceManager#destroy
+ */
+ public synchronized void destroy(PersistentNodeState state) throws ItemStateException {
+ if (!initialized) {
+ throw new IllegalStateException("not initialized");
+ }
+
+ String uuid = state.getUUID();
+ String nodeFilePath = buildNodeFilePath(uuid);
+ FileSystemResource nodeFile = new FileSystemResource(itemStateFS, nodeFilePath);
+ try {
+ nodeFile.delete();
+ // prune empty folders
+ String parentDir = FileSystemPathUtil.getParentDir(nodeFilePath);
+ while (!parentDir.equals(FileSystem.SEPARATOR)
+ && !itemStateFS.hasChildren(parentDir)) {
+ itemStateFS.deleteFolder(parentDir);
+ parentDir = FileSystemPathUtil.getParentDir(parentDir);
+ }
+ } catch (FileSystemException fse) {
+ String msg = "failed to delete node state: " + uuid;
+ log.error(msg, fse);
+ throw new ItemStateException(msg, fse);
+ }
+ }
+
+ /**
+ * @see PersistenceManager#destroy
+ */
+ public synchronized void destroy(PersistentPropertyState state) throws ItemStateException {
+ if (!initialized) {
+ throw new IllegalStateException("not initialized");
+ }
+
+ // delete binary values (stored as files)
+ InternalValue[] values = state.getValues();
+ if (values != null) {
+ for (int i = 0; i < values.length; i++) {
+ InternalValue val = values[i];
+ if (val != null) {
+ if (val.getType() == PropertyType.BINARY) {
+ BLOBFileValue blobVal = (BLOBFileValue) val.internalValue();
+ blobVal.delete();
+ }
+ }
+ }
+ }
+ // delete property file
+ String propFilePath = buildPropFilePath(state.getParentUUID(), state.getName());
+ FileSystemResource propFile = new FileSystemResource(itemStateFS, propFilePath);
+ try {
+ propFile.delete();
+ // prune empty folders
+ String parentDir = FileSystemPathUtil.getParentDir(propFilePath);
+ while (!parentDir.equals(FileSystem.SEPARATOR)
+ && !itemStateFS.hasChildren(parentDir)) {
+ itemStateFS.deleteFolder(parentDir);
+ parentDir = FileSystemPathUtil.getParentDir(parentDir);
+ }
+ } catch (FileSystemException fse) {
+ String msg = "failed to delete property state: " + state.getParentUUID() + "/" + state.getName();
+ log.error(msg, fse);
+ throw new ItemStateException(msg, fse);
+ }
+ }
+
+ /**
+ * @see PersistenceManager#load(NodeReferences)
+ */
+ public void load(NodeReferences refs)
+ throws NoSuchItemStateException, ItemStateException {
+ if (!initialized) {
+ throw new IllegalStateException("not initialized");
+ }
+
+ String uuid = refs.getTargetId().getUUID();
+ String refsFilePath = buildNodeReferencesFilePath(uuid);
+
+ try {
+ if (!itemStateFS.isFile(refsFilePath)) {
+ throw new NoSuchItemStateException(uuid);
+ }
+ } catch (FileSystemException fse) {
+ String msg = "failed to load references: " + uuid;
+ log.error(msg, fse);
+ throw new ItemStateException(msg, fse);
+ }
+
+ try {
+ BufferedInputStream in =
+ new BufferedInputStream(itemStateFS.getInputStream(refsFilePath));
+ try {
+ deserialize(refs, in);
+ return;
+ } finally {
+ in.close();
+ }
+ } catch (Exception e) {
+ String msg = "failed to load references: " + uuid;
+ log.error(msg, e);
+ throw new ItemStateException(msg, e);
+ }
+ }
+
+ /**
+ * @see PersistenceManager#store(NodeReferences)
+ */
+ public void store(NodeReferences refs) throws ItemStateException {
+ if (!initialized) {
+ throw new IllegalStateException("not initialized");
+ }
+
+ String uuid = refs.getTargetId().getUUID();
+ String refsFilePath = buildNodeReferencesFilePath(uuid);
+ FileSystemResource refsFile = new FileSystemResource(itemStateFS, refsFilePath);
+ try {
+ refsFile.makeParentDirs();
+ OutputStream out = new BufferedOutputStream(refsFile.getOutputStream());
+ try {
+ serialize(refs, out);
+ } finally {
+ out.close();
+ }
+ } catch (Exception e) {
+ String msg = "failed to store references: " + uuid;
+ log.error(msg, e);
+ throw new ItemStateException(msg, e);
+ }
+ }
+
+ /**
+ * @see PersistenceManager#destroy(NodeReferences)
+ */
+ public void destroy(NodeReferences refs) throws ItemStateException {
+ if (!initialized) {
+ throw new IllegalStateException("not initialized");
+ }
+
+ String uuid = refs.getTargetId().getUUID();
+ String refsFilePath = buildNodeReferencesFilePath(uuid);
+ FileSystemResource refsFile = new FileSystemResource(itemStateFS, refsFilePath);
+ try {
+ refsFile.delete();
+ // prune empty folders
+ String parentDir = FileSystemPathUtil.getParentDir(refsFilePath);
+ while (!parentDir.equals(FileSystem.SEPARATOR)
+ && !itemStateFS.hasChildren(parentDir)) {
+ itemStateFS.deleteFolder(parentDir);
+ parentDir = FileSystemPathUtil.getParentDir(parentDir);
+ }
+ } catch (FileSystemException fse) {
+ String msg = "failed to delete references: " + uuid;
+ log.error(msg, fse);
+ throw new ItemStateException(msg, fse);
+ }
+ }
+}
Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/xml/XMLPersistenceManager.java
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/xml/XMLPersistenceManager.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/xml/XMLPersistenceManager.java Wed Oct 27 08:47:13 2004
@@ -267,7 +267,7 @@
try {
val = InternalValue.create(new FileSystemResource(blobStore, text));
} catch (IOException ioe) {
- String msg = "error while reading serialized binary valuey";
+ String msg = "error while reading serialized binary value";
log.error(msg, ioe);
throw new ItemStateException(msg, ioe);
}
@@ -306,6 +306,27 @@
}
/**
+ * @see PersistenceManager#close
+ */
+ public synchronized void close() throws Exception {
+ if (!initialized) {
+ return;
+ }
+
+ try {
+ // close blob store
+ blobStore.close();
+ /**
+ * there's no need close the item state store because it
+ * is based in the workspace's file system which is
+ * closed by the repository
+ */
+ } finally {
+ initialized = false;
+ }
+ }
+
+ /**
* @see PersistenceManager#load(PersistentNodeState)
*/
public synchronized void load(PersistentNodeState state)
@@ -333,7 +354,6 @@
readState(rootElement, state);
return;
-
} finally {
in.close();
}
@@ -377,7 +397,6 @@
props.load(in);
readState(props, state);
return;
-
} finally {
in.close();
}
@@ -636,7 +655,6 @@
}
// store path to binary file as property value
props.setProperty(Integer.toString(i), binPath);
- // FIXME: hack!
// replace value instance with value
// backed by internal file and delete temp file
values[i] = InternalValue.create(internalBlobFile);
Modified: incubator/jackrabbit/trunk/xdocs/tasks.xml
==============================================================================
--- incubator/jackrabbit/trunk/xdocs/tasks.xml (original)
+++ incubator/jackrabbit/trunk/xdocs/tasks.xml Wed Oct 27 08:47:13 2004
@@ -10,9 +10,6 @@
locking
</task>
<task creator="stefan" assignedto="" startdate="" enddate="" effort="" status="">
- jta support
- </task>
- <task creator="stefan" assignedto="" startdate="" enddate="" effort="" status="">
access control (jaas)
</task>
<task creator="stefan" assignedto="" startdate="" enddate="" effort="" status="">
@@ -43,9 +40,6 @@
update cache on hierarchy changes (move, hardlink, remove, etc)
<task creator="stefan" assignedto="" startdate="" enddate="" effort="" status="">
inline @todo comments: resolve/implement
- </task>
- <task creator="stefan" assignedto="" startdate="" enddate="" effort="" status="">
- ItemState: hide STATUS_* flags, use set* and is* methods instead
</task>
<task creator="stefan" assignedto="" startdate="" enddate="" effort="" status="">
javaDoc, javaDoc, javaDoc