You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by an...@apache.org on 2006/07/12 15:33:27 UTC

svn commit: r421270 [17/23] - in /jackrabbit/trunk/contrib/spi: ./ commons/ commons/src/ commons/src/main/ commons/src/main/java/ commons/src/main/java/org/ commons/src/main/java/org/apache/ commons/src/main/java/org/apache/jackrabbit/ commons/src/main...

Propchange: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/TransientChangeLog.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/TransientChangeLog.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url

Added: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/TransientItemStateListener.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/TransientItemStateListener.java?rev=421270&view=auto
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/TransientItemStateListener.java (added)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/TransientItemStateListener.java Wed Jul 12 06:33:19 2006
@@ -0,0 +1,46 @@
+/*
+ * 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.jcr2spi.state;
+
+/**
+ * <code>TransientItemStateListener</code> extends {@link ItemStateListener}
+ * and adds to callbacks: {@link #stateOverlaid(ItemState)} and
+ * {@link #stateUncovering(ItemState)}.
+ */
+public interface TransientItemStateListener extends ItemStateListener {
+
+    /**
+     * Called when an <code>ItemState</code> has been overlaid by some
+     * other state that now takes its identity. This notification is sent
+     * on the state being overlaid.
+     *
+     * @param overlayer the <code>ItemState</code> that overlays this state
+     */
+    public void stateOverlaid(ItemState overlayer);
+
+    /**
+     * Called when an <code>ItemState</code> is about to no longer overlay some
+     * other item state. This notification is sent on the state overlaying
+     * another state.
+     *
+     * @param overlayer the <code>ItemState</code> that overlaid another item
+     *                  state. To get the overlaid state, invoke {@link
+     *                  ItemState#getOverlayedState()}
+     */
+    public void stateUncovering(ItemState overlayer);
+
+}

Propchange: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/TransientItemStateListener.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/TransientItemStateListener.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url

Added: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/TransientItemStateManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/TransientItemStateManager.java?rev=421270&view=auto
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/TransientItemStateManager.java (added)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/TransientItemStateManager.java Wed Jul 12 06:33:19 2006
@@ -0,0 +1,144 @@
+/*
+ * 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.jcr2spi.state;
+
+import org.apache.jackrabbit.jcr2spi.operation.Operation;
+import org.apache.jackrabbit.spi.NodeId;
+import org.apache.jackrabbit.name.QName;
+
+import java.util.Iterator;
+
+/**
+ * <code>TransientItemStateManager</code> ...
+ */
+interface TransientItemStateManager extends ItemStateManager {
+
+    /**
+     * @return the number of entries
+     */
+    public int getEntriesCount();
+
+    /**
+     * @return the number of entries in attic
+     */
+    public int getEntriesInAtticCount();
+
+    /**
+     * @return an iterator over all entries
+     */
+    public Iterator getEntries();
+
+    /**
+     * @return an iterator over all entries in attic
+     */
+    public Iterator getEntriesInAttic();
+
+    /**
+     * Adds an operation to this transient item state manager.
+     *
+     * @param operationType the operation.
+     * @throws IllegalStateException if <code>operationType</code> is not
+     * compatible with the previously executed operation (invalid sequence of
+     * operations).
+     */
+    public void addOperation(Operation operationType) throws IllegalStateException;
+
+    //----------------< methods for creating & discarding ItemState instances >
+
+    /**
+     * DIFF JACKRABBIT: does not throw ItemStateException
+     * Creates a new transient {@link NodeState} that does not overlay any other
+     * {@link NodeState}.
+     *
+     * @param id the <code>NodeId</code> of the new node state.
+     * @param nodeTypeName name of the node type of the new node state.
+     * @param parentId the parent id of the new node state.
+     * @return a new transient {@link NodeState}.
+     */
+    NodeState createNodeState(NodeId id, QName nodeTypeName,
+                              NodeId parentId);
+
+    /**
+     * DIFF JACKRABBIT: does not throw ItemStateException
+     * @param overlayedState
+     * @return
+     */
+    NodeState createNodeState(NodeState overlayedState);
+
+    /**
+     * DIFF JACKRABBIT: does not throw ItemStateException
+     * @param parentId
+     * @param propName
+     * @return
+     */
+    PropertyState createPropertyState(NodeId parentId, QName propName);
+
+    /**
+     * DIFF JACKRABBIT: does not throw ItemStateException
+     * @param overlayedState
+     * @return
+     */
+    PropertyState createPropertyState(PropertyState overlayedState);
+
+    /**
+     * Disposes the specified instance, i.e. discards it and removes it from
+     * the map.
+     *
+     * @param state the <code>ItemState</code> instance that should be disposed
+     * @see ItemState#discard()
+     */
+    public void disposeItemState(ItemState state);
+
+    /**
+     * Transfers the specified instance from the 'active' map to the attic.
+     *
+     * @param state the <code>ItemState</code> instance that should be moved to
+     *              the attic
+     */
+    public void moveItemStateToAttic(ItemState state);
+
+    /**
+     * Disposes the specified instance in the attic, i.e. discards it and
+     * removes it from the attic.
+     *
+     * @param state the <code>ItemState</code> instance that should be disposed
+     * @see ItemState#discard()
+     */
+    public void disposeItemStateInAttic(ItemState state);
+
+    /**
+     * Disposes all transient item states in the cache and in the attic.
+     */
+    public void disposeAllItemStates();
+
+    /**
+     * Return the attic item state provider that holds all items
+     * moved into the attic.
+     *
+     * @return attic
+     */
+    public ItemStateManager getAttic();
+
+    //-----------------------------------< methods for controlling operations >
+
+    /**
+     * Disposes a collection of {@link org.apache.jackrabbit.jcr2spi.operation.Operation}s.
+     *
+     * @param operations the operations.
+     */
+    public void disposeOperations(Iterator operations);
+}

Propchange: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/TransientItemStateManager.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/TransientItemStateManager.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url

Added: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/UpdatableItemStateManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/UpdatableItemStateManager.java?rev=421270&view=auto
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/UpdatableItemStateManager.java (added)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/UpdatableItemStateManager.java Wed Jul 12 06:33:19 2006
@@ -0,0 +1,50 @@
+/*
+ * 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.jcr2spi.state;
+
+import org.apache.jackrabbit.jcr2spi.operation.Operation;
+
+import javax.jcr.RepositoryException;
+
+/**
+ * Identifies an <code>ItemStateManager</code> that allows updating
+ * items.
+ */
+public interface UpdatableItemStateManager extends ItemStateManager {
+
+    /**
+     * Executes the given operation and modifies the affected item states accordingly.
+     *
+     * @param operation
+     * @throws RepositoryException
+     */
+    public void execute(Operation operation) throws RepositoryException;
+
+    /**
+     * Executes the operations passed with the given change log and modifies the
+     * affected item states accordingly.
+     *
+     * @param changes
+     * @throws RepositoryException
+     */
+    public void execute(ChangeLog changes) throws RepositoryException;
+
+    /**
+     * Disposes this <code>UpdatableItemStateManager</code> and frees resources.
+     */
+    void dispose();
+}

Propchange: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/UpdatableItemStateManager.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/UpdatableItemStateManager.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url

Added: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/util/Dumpable.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/util/Dumpable.java?rev=421270&view=auto
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/util/Dumpable.java (added)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/util/Dumpable.java Wed Jul 12 06:33:19 2006
@@ -0,0 +1,35 @@
+/*
+ * 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.jcr2spi.util;
+
+import java.io.PrintStream;
+
+/**
+ * Utility interface for internal use.
+ * <p/>
+ * A <code>Dumpable</code> object supports dumping its state in a human readable
+ * format for diagnostic/debug purposes.
+ */
+public interface Dumpable {
+    /**
+     * Dumps the state of this instance in a human readable format for
+     * diagnostic purposes.
+     *
+     * @param ps stream to dump state to
+     */
+    void dump(PrintStream ps);
+}

Propchange: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/util/Dumpable.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/util/Dumpable.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url

Added: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/util/ReferenceChangeTracker.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/util/ReferenceChangeTracker.java?rev=421270&view=auto
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/util/ReferenceChangeTracker.java (added)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/util/ReferenceChangeTracker.java Wed Jul 12 06:33:19 2006
@@ -0,0 +1,117 @@
+/*
+ * 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.jcr2spi.util;
+
+import org.apache.jackrabbit.jcr2spi.state.PropertyState;
+import org.apache.jackrabbit.spi.NodeId;
+import org.apache.jackrabbit.value.QValue;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.jcr.PropertyType;
+import javax.jcr.RepositoryException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+
+/**
+ * Simple helper class that can be used to keep track of uuid mappings
+ * (e.g. if the uuid of an imported or copied node is mapped to a new uuid)
+ * and processed (e.g. imported or copied) reference properties that might
+ * need correcting depending on the uuid mappings.
+ */
+public class ReferenceChangeTracker {
+
+    private static Logger log = LoggerFactory.getLogger(ReferenceChangeTracker.class);
+
+    /**
+     * mapping <original uuid> to <new uuid> of mix:referenceable nodes
+     */
+    private final HashMap uuidMap = new HashMap();
+    /**
+     * list of processed reference properties that might need correcting
+     */
+    private final ArrayList references = new ArrayList();
+
+    /**
+     * Creates a new instance.
+     */
+    public ReferenceChangeTracker() {
+    }
+
+    /**
+     * Resets all internal state.
+     */
+    public void clear() {
+        uuidMap.clear();
+        references.clear();
+    }
+
+    /**
+     * Store the given uuid mapping for later lookup using
+     * <code>#adjustReferences(UpdatableItemStateManager, ItemStateValidator)</code>.
+     *
+     * @param oldNodeId old nodeId
+     * @param newNodeId new nodeId
+     */
+    public void mappedNodeIds(NodeId oldNodeId, NodeId newNodeId) {
+        if (oldNodeId.equals(newNodeId) || oldNodeId.getUUID() == null) {
+            // only remember if uuid exists and has changed
+            return;
+        }
+        uuidMap.put(oldNodeId.getUUID(), newNodeId.getUUID());
+    }
+
+    /**
+     * Returns the new UUID to which <code>oldUUID</code> has been mapped
+     * or <code>null</code> if no such mapping exists.
+     *
+     * @param oldReference old uuid represented by the given <code>QValue</code>
+     * @return mapped new QValue of the reference value or <code>null</code> if no such mapping exists
+     * @see #mappedNodeIds(NodeId,NodeId)
+     */
+    public QValue getMappedReference(QValue oldReference) {
+        QValue remapped = null;
+        if (oldReference.getType() == PropertyType.REFERENCE) {
+            try {
+                String oldValue = oldReference.getString();
+                String newValue = uuidMap.get(oldValue).toString();
+                remapped = QValue.create(newValue, PropertyType.REFERENCE);
+            } catch (RepositoryException e) {
+                log.error("Unexpected error while creating internal value.", e);
+            }
+        }
+        return remapped;
+    }
+
+    // DIFF JR: meth. signature: PropertyState instead of Object
+    /**
+     * Store the given reference property for later resolution.
+     *
+     * @param refPropertyState reference property state
+     */
+    public void processedReference(PropertyState refPropertyState) {
+        // make sure only not-null states of type Reference are remembered
+        if (refPropertyState != null && refPropertyState.getType() == PropertyType.REFERENCE) {
+            references.add(refPropertyState);
+        }
+    }
+
+    public Iterator getReferences() {
+        return references.iterator();
+    }
+}

Propchange: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/util/ReferenceChangeTracker.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/util/ReferenceChangeTracker.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url

Added: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/version/DefaultVersionManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/version/DefaultVersionManager.java?rev=421270&view=auto
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/version/DefaultVersionManager.java (added)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/version/DefaultVersionManager.java Wed Jul 12 06:33:19 2006
@@ -0,0 +1,62 @@
+/*
+ * 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.jcr2spi.version;
+
+import org.slf4j.LoggerFactory;
+import org.slf4j.Logger;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.UnsupportedRepositoryOperationException;
+import org.apache.jackrabbit.spi.NodeId;
+import java.util.Collection;
+
+/**
+ * <code>DefaultVersionManager</code>...
+ */
+public class DefaultVersionManager implements VersionManager {
+
+    private static Logger log = LoggerFactory.getLogger(DefaultVersionManager.class);
+
+    public void checkin(NodeId nodeId) throws RepositoryException {
+        throw new UnsupportedRepositoryOperationException("Versioning ist not supported by this repository.");
+    }
+
+    public void checkout(NodeId nodeId) throws RepositoryException {
+        throw new UnsupportedRepositoryOperationException("Versioning ist not supported by this repository.");
+    }
+
+    public boolean isCheckedOut(NodeId nodeId) throws RepositoryException {
+        log.debug("Versioning is not supported by this repository.");
+        return true;
+    }
+
+    public void restore(NodeId nodeId, NodeId versionId, boolean removeExisting) throws RepositoryException {
+        throw new UnsupportedRepositoryOperationException("Versioning ist not supported by this repository.");
+    }
+
+    public void restore(NodeId[] versionIds, boolean removeExisting) throws RepositoryException {
+        throw new UnsupportedRepositoryOperationException("Versioning ist not supported by this repository.");
+    }
+
+    public Collection merge(NodeId nodeId, String workspaceName, boolean bestEffort) throws RepositoryException {
+        throw new UnsupportedRepositoryOperationException("Versioning ist not supported by this repository.");
+    }
+
+    public void resolveMergeConflict(NodeId nodeId, NodeId versionId, boolean done) throws RepositoryException {
+        throw new UnsupportedRepositoryOperationException("Versioning ist not supported by this repository.");
+    }
+}
\ No newline at end of file

Propchange: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/version/DefaultVersionManager.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/version/DefaultVersionManager.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url

Added: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/version/VersionHistoryImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/version/VersionHistoryImpl.java?rev=421270&view=auto
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/version/VersionHistoryImpl.java (added)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/version/VersionHistoryImpl.java Wed Jul 12 06:33:19 2006
@@ -0,0 +1,405 @@
+/*
+ * 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.jcr2spi.version;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.apache.jackrabbit.jcr2spi.NodeImpl;
+import org.apache.jackrabbit.jcr2spi.ItemManager;
+import org.apache.jackrabbit.jcr2spi.SessionImpl;
+import org.apache.jackrabbit.jcr2spi.ItemLifeCycleListener;
+import org.apache.jackrabbit.jcr2spi.LazyItemIterator;
+import org.apache.jackrabbit.jcr2spi.operation.AddLabel;
+import org.apache.jackrabbit.jcr2spi.operation.Operation;
+import org.apache.jackrabbit.jcr2spi.operation.RemoveLabel;
+import org.apache.jackrabbit.jcr2spi.operation.Remove;
+import org.apache.jackrabbit.jcr2spi.state.NodeState;
+import org.apache.jackrabbit.jcr2spi.state.ItemStateException;
+import org.apache.jackrabbit.name.QName;
+import org.apache.jackrabbit.name.NameException;
+import org.apache.jackrabbit.name.NoPrefixDeclaredException;
+import org.apache.jackrabbit.spi.NodeId;
+import org.apache.jackrabbit.name.Path;
+import org.apache.jackrabbit.spi.PropertyId;
+
+import javax.jcr.version.VersionHistory;
+import javax.jcr.version.Version;
+import javax.jcr.version.VersionIterator;
+import javax.jcr.version.VersionException;
+import javax.jcr.RepositoryException;
+import javax.jcr.ReferentialIntegrityException;
+import javax.jcr.AccessDeniedException;
+import javax.jcr.UnsupportedRepositoryOperationException;
+import javax.jcr.Item;
+import javax.jcr.Node;
+import javax.jcr.Property;
+import javax.jcr.nodetype.NodeDefinition;
+import java.util.Set;
+import java.util.Iterator;
+import java.util.HashSet;
+import java.util.List;
+import java.util.ArrayList;
+
+/**
+ * <code>VersionHistoryImpl</code>...
+ */
+public class VersionHistoryImpl extends NodeImpl implements VersionHistory {
+
+    private static Logger log = LoggerFactory.getLogger(VersionHistoryImpl.class);
+
+    private final NodeState vhState;
+    private final NodeState labelNodeState;
+
+    public VersionHistoryImpl(ItemManager itemMgr, SessionImpl session,
+                              NodeState state, NodeDefinition definition,
+                              ItemLifeCycleListener[] listeners) throws VersionException {
+        super(itemMgr, session, state, definition, listeners);
+
+        // retrieve nodestate of the jcr:versionLabels node
+        vhState = state;
+        if (vhState.hasChildNodeEntry(QName.JCR_VERSIONLABELS)) {
+            NodeState.ChildNodeEntry lnEntry = vhState.getChildNodeEntry(QName.JCR_VERSIONLABELS, Path.INDEX_DEFAULT);
+            try {
+                labelNodeState = (NodeState) itemStateMgr.getItemState(lnEntry.getId());
+            } catch (ItemStateException e) {
+                throw new VersionException("nt:versionHistory requires a mandatory, autocreated child node jcr:versionLabels.");
+            }
+        } else {
+            throw new VersionException("nt:versionHistory requires a mandatory, autocreated child node jcr:versionLabels.");
+        }
+    }
+
+    //-----------------------------------------------------< VersionHistory >---
+    /**
+     *
+     * @return
+     * @throws RepositoryException
+     * @see VersionHistory#getVersionableUUID()
+     */
+    public String getVersionableUUID() throws RepositoryException {
+        return getProperty(QName.JCR_VERSIONABLEUUID).getString();
+    }
+
+    /**
+     *
+     * @return
+     * @throws RepositoryException
+     * @see VersionHistory#getRootVersion()
+     */
+    public Version getRootVersion() throws RepositoryException {
+        NodeId vId = vhState.getChildNodeEntry(QName.JCR_ROOTVERSION, Path.INDEX_DEFAULT).getId();
+        return (Version) itemMgr.getItem(vId);
+    }
+
+    /**
+     *
+     * @return
+     * @throws RepositoryException
+     * @see VersionHistory#getAllVersions()
+     */
+    public VersionIterator getAllVersions() throws RepositoryException {
+        Iterator childIter = vhState.getChildNodeEntries().iterator();
+        Set versionIds = new HashSet();
+
+        // all child-nodes except from jcr:versionLabels point to Versions.
+        while (childIter.hasNext()) {
+            NodeState.ChildNodeEntry entry = (NodeState.ChildNodeEntry) childIter.next();
+            if (!QName.JCR_VERSIONLABELS.equals(entry.getName())) {
+                versionIds.add(entry.getId());
+            }
+        }
+        return new LazyItemIterator(itemMgr, versionIds);
+    }
+
+    /**
+     *
+     * @param versionName
+     * @return
+     * @throws VersionException
+     * @throws RepositoryException
+     * @see VersionHistory#getVersion(String)
+     */
+    public Version getVersion(String versionName) throws VersionException, RepositoryException {
+        NodeId vId = getVersionId(versionName);
+        return (Version) itemMgr.getItem(vId);
+    }
+
+    /**
+     *
+     * @param label
+     * @return
+     * @throws RepositoryException
+     * @see VersionHistory#getVersionByLabel(String)
+     */
+    public Version getVersionByLabel(String label) throws RepositoryException {
+        NodeId vId = getVersionIdByLabel(label);
+        return (Version) itemMgr.getItem(vId);
+    }
+
+    /**
+     *
+     * @param versionName
+     * @param label
+     * @param moveLabel
+     * @throws VersionException
+     * @throws RepositoryException
+     * @see VersionHistory#addVersionLabel(String, String, boolean)
+     */
+    public void addVersionLabel(String versionName, String label, boolean moveLabel) throws VersionException, RepositoryException {
+        QName qLabel = getQLabel(label);
+        // TODO: ev. delegate to versionmanager
+        Operation op = AddLabel.create(vhState.getNodeId(), getVersionId(versionName), qLabel, moveLabel);
+        itemStateMgr.execute(op);
+    }
+
+    /**
+     *
+     * @param label
+     * @throws VersionException
+     * @throws RepositoryException
+     * @see VersionHistory#removeVersionLabel(String)
+     */
+    public void removeVersionLabel(String label) throws VersionException, RepositoryException {
+        QName qLabel = getQLabel(label);
+        // TODO: ev. delegate to versionmanager
+        Operation op = RemoveLabel.create(vhState.getNodeId(), getVersionIdByLabel(label), qLabel);
+        itemStateMgr.execute(op);
+    }
+
+    /**
+     *
+     * @param label
+     * @return
+     * @throws RepositoryException
+     * @see VersionHistory#hasVersionLabel(String)
+     */
+    public boolean hasVersionLabel(String label) throws RepositoryException {
+        QName l = getQLabel(label);
+        QName[] qLabels = getQLabels();
+        for (int i = 0; i < qLabels.length; i++) {
+            if (qLabels[i].equals(l)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     *
+     * @param version
+     * @param string
+     * @return
+     * @throws VersionException
+     * @throws RepositoryException
+     * @see VersionHistory#hasVersionLabel(Version, String)
+     */
+    public boolean hasVersionLabel(Version version, String label) throws VersionException, RepositoryException {
+        checkValidVersion(version);
+        String vUUID = version.getUUID();
+        QName l = getQLabel(label);
+
+        QName[] qLabels = getQLabels();
+        for (int i = 0; i < qLabels.length; i++) {
+            if (qLabels[i].equals(l)) {
+                NodeId vId = getVersionIdByLabel(qLabels[i]);
+                return vUUID.equals(vId.getUUID());
+            }
+        }
+        return false;
+    }
+
+    /**
+     *
+     * @return
+     * @throws RepositoryException
+     * @see VersionHistory#getVersionLabels()
+     */
+    public String[] getVersionLabels() throws RepositoryException {
+        QName[] qLabels = getQLabels();
+        String[] labels = new String[qLabels.length];
+
+        for (int i = 0; i < qLabels.length; i++) {
+            try {
+                labels[i] = session.getNamespaceResolver().getJCRName(qLabels[i]);
+            } catch (NoPrefixDeclaredException e) {
+                // unexpected error. should not occur.
+                throw new RepositoryException(e);
+            }
+        }
+        return labels;
+    }
+
+    /**
+     *
+     * @param version
+     * @return
+     * @throws VersionException
+     * @throws RepositoryException
+     * @see VersionHistory#getVersionLabels(Version)
+     */
+    public String[] getVersionLabels(Version version) throws VersionException, RepositoryException {
+        checkValidVersion(version);
+        String vUUID = version.getUUID();
+
+        List vlabels = new ArrayList();
+        QName[] qLabels = getQLabels();
+        for (int i = 0; i < qLabels.length; i++) {
+            NodeId vId = getVersionIdByLabel(qLabels[i]);
+            if (vUUID.equals(vId.getUUID())) {
+                try {
+                    vlabels.add(session.getNamespaceResolver().getJCRName(qLabels[i]));
+                } catch (NoPrefixDeclaredException e) {
+                    // should never occur
+                    throw new RepositoryException("Unexpected error while accessing version label", e);
+                }
+            }
+        }
+        return (String[]) vlabels.toArray(new String[vlabels.size()]);
+    }
+
+    /**
+     *
+     * @param versionName
+     * @throws ReferentialIntegrityException
+     * @throws AccessDeniedException
+     * @throws UnsupportedRepositoryOperationException
+     * @throws VersionException
+     * @throws RepositoryException
+     * @see VersionHistory#removeVersion(String)
+     */
+    public void removeVersion(String versionName) throws ReferentialIntegrityException, AccessDeniedException, UnsupportedRepositoryOperationException, VersionException, RepositoryException {
+        try {
+            NodeId vId = getVersionId(versionName);
+            NodeState vState = (NodeState) itemStateMgr.getItemState(vId);
+
+            // TODO: ev. delegate to versionmanager
+            Operation rm = Remove.create(vState);
+            itemStateMgr.execute(rm);
+        } catch (ItemStateException e) {
+            throw new RepositoryException(e);
+        }
+    }
+
+    //---------------------------------------------------------------< Item >---
+    /**
+     *
+     * @param otherItem
+     * @return
+     * @see Item#isSame(Item)
+     */
+    public boolean isSame(Item otherItem) {
+        if (otherItem instanceof VersionHistoryImpl) {
+            // since all version histories are referenceable, protected and live
+            // in the same workspace, a simple comparison of the ids is sufficient
+            VersionHistoryImpl other = ((VersionHistoryImpl) otherItem);
+            return other.getId().equals(getId());
+        }
+        return false;
+    }
+
+    //------------------------------------------------------------< private >---
+    /**
+     *
+     * @return
+     */
+    private QName[] getQLabels() {
+        Set labelQNames = labelNodeState.getPropertyNames();
+        return (QName[]) labelQNames.toArray(new QName[labelQNames.size()]);
+    }
+
+    /**
+     *
+     * @param versionName
+     * @return
+     * @throws VersionException
+     * @throws RepositoryException
+     */
+    private NodeId getVersionId(String versionName) throws VersionException, RepositoryException {
+        try {
+            QName vQName = session.getNamespaceResolver().getQName(versionName);
+            NodeState.ChildNodeEntry vEntry = vhState.getChildNodeEntry(vQName, Path.INDEX_DEFAULT);
+            if (vEntry == null) {
+                throw new VersionException("Version '" + versionName + "' does not exist in this version history.");
+            } else {
+                return vEntry.getId();
+            }
+        } catch (NameException e) {
+            throw new RepositoryException(e);
+        }
+    }
+
+    /**
+     *
+     * @param label
+     * @return
+     * @throws VersionException
+     * @throws RepositoryException
+     */
+    private NodeId getVersionIdByLabel(String label) throws VersionException, RepositoryException {
+        QName qLabel = getQLabel(label);
+        return getVersionIdByLabel(qLabel);
+    }
+
+    /**
+     *
+     * @param qLabel
+     * @return
+     * @throws VersionException
+     * @throws RepositoryException
+     */
+    private NodeId getVersionIdByLabel(QName qLabel) throws VersionException, RepositoryException {
+        if (labelNodeState.hasPropertyName(qLabel)) {
+            // retrieve reference property value -> and convert it to a NodeId
+            PropertyId pId = labelNodeState.getPropertyId(qLabel);
+            Node version = ((Property) itemMgr.getItem(pId)).getNode();
+            return (NodeId) session.getHierarchyManager().getItemId(version);
+        } else {
+            throw new VersionException("Version with label '" + qLabel + "' does not exist.");
+        }
+    }
+
+    /**
+     *
+     * @param label
+     * @return
+     * @throws RepositoryException
+     */
+    private QName getQLabel(String label) throws RepositoryException {
+        try {
+            return session.getNamespaceResolver().getQName(label);
+        } catch (NameException e) {
+            String error = "Invalid version label: " + e.getMessage();
+            log.error(error);
+            throw new RepositoryException(error, e);
+        }
+    }
+
+    /**
+     * Checks if the specified version belongs to this <code>VersionHistory</code>.
+     * This method throws <code>VersionException</code> if {@link Version#getContainingHistory()}
+     * is not the same item than this <code>VersionHistory</code>.
+     *
+     * @param version
+     * @throws javax.jcr.version.VersionException
+     * @throws javax.jcr.RepositoryException
+     */
+    private void checkValidVersion(Version version) throws VersionException, RepositoryException {
+        if (!version.getContainingHistory().isSame(this)) {
+            throw new VersionException("Specified version '" + version.getName() + "' is not part of this history.");
+        }
+    }
+}
\ No newline at end of file

Propchange: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/version/VersionHistoryImpl.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/version/VersionHistoryImpl.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url

Added: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/version/VersionImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/version/VersionImpl.java?rev=421270&view=auto
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/version/VersionImpl.java (added)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/version/VersionImpl.java Wed Jul 12 06:33:19 2006
@@ -0,0 +1,129 @@
+/*
+ * 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.jcr2spi.version;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.apache.jackrabbit.jcr2spi.NodeImpl;
+import org.apache.jackrabbit.jcr2spi.ItemManager;
+import org.apache.jackrabbit.jcr2spi.SessionImpl;
+import org.apache.jackrabbit.jcr2spi.ItemLifeCycleListener;
+import org.apache.jackrabbit.jcr2spi.state.NodeState;
+import org.apache.jackrabbit.name.QName;
+
+import javax.jcr.version.Version;
+import javax.jcr.version.VersionHistory;
+import javax.jcr.RepositoryException;
+import javax.jcr.Value;
+import javax.jcr.Node;
+import javax.jcr.Item;
+import javax.jcr.nodetype.NodeDefinition;
+import java.util.Calendar;
+
+/**
+ * <code>VersionImpl</code>...
+ */
+public class VersionImpl extends NodeImpl implements Version {
+
+    private static Logger log = LoggerFactory.getLogger(VersionImpl.class);
+
+    public VersionImpl(ItemManager itemMgr, SessionImpl session, NodeState state, NodeDefinition definition, ItemLifeCycleListener[] listeners) {
+        super(itemMgr, session, state, definition, listeners);
+    }
+
+    //------------------------------------------------------------< Version >---
+    /**
+     *
+     * @return
+     * @throws RepositoryException
+     * @see Version#getContainingHistory()
+     */
+    public VersionHistory getContainingHistory() throws RepositoryException {
+        return (VersionHistory) getParent();
+    }
+
+    /**
+     *
+     * @return
+     * @throws RepositoryException
+     * @see Version#getCreated()
+     */
+    public Calendar getCreated() throws RepositoryException {
+        return getProperty(QName.JCR_CREATED).getDate();
+    }
+
+    /**
+     *
+     * @return
+     * @throws RepositoryException
+     * @see Version#getSuccessors()
+     */
+    public Version[] getSuccessors() throws RepositoryException {
+        return getVersions(QName.JCR_SUCCESSORS);
+    }
+
+    /**
+     *
+     * @return
+     * @throws RepositoryException
+     * @see Version#getPredecessors()
+     */
+    public Version[] getPredecessors() throws RepositoryException {
+        return getVersions(QName.JCR_PREDECESSORS);
+    }
+
+    //---------------------------------------------------------------< Item >---
+    /**
+     *
+     * @param otherItem
+     * @return
+     * @see Item#isSame(Item)
+     */
+    public boolean isSame(Item otherItem) {
+        if (otherItem instanceof VersionImpl) {
+            // since all versions are referenceable, protected and live
+            // in the same workspace, a simple comparision of the ids is sufficient
+            VersionImpl other = ((VersionImpl) otherItem);
+            return other.getId().equals(getId());
+        }
+        return false;
+    }
+    //------------------------------------------------------------< private >---
+    /**
+     *
+     * @param propertyName
+     * @return
+     */
+    private Version[] getVersions(QName propertyName) throws RepositoryException {
+        Version[] versions;
+        Value[] values = getProperty(propertyName).getValues();
+        if (values != null) {
+            versions = new Version[values.length];
+            for (int i = 0; i < values.length; i++) {
+                Node n = session.getNodeByUUID(values[i].getString());
+                if (n instanceof Version) {
+                    versions[i] = (Version) n;
+                } else {
+                    throw new RepositoryException("Version property contains invalid value not pointing to a 'Version'");
+                }
+            }
+        } else {
+            versions = new Version[0];
+        }
+        return versions;
+    }
+}
\ No newline at end of file

Propchange: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/version/VersionImpl.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/version/VersionImpl.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url

Added: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/version/VersionManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/version/VersionManager.java?rev=421270&view=auto
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/version/VersionManager.java (added)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/version/VersionManager.java Wed Jul 12 06:33:19 2006
@@ -0,0 +1,59 @@
+/*
+ * 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.jcr2spi.version;
+
+import org.apache.jackrabbit.spi.NodeId;
+
+import javax.jcr.RepositoryException;
+import java.util.Collection;
+
+/**
+ * <code>VersionManager</code>...
+ */
+public interface VersionManager {
+
+    public void checkin(NodeId nodeId) throws RepositoryException;
+
+    public void checkout(NodeId nodeId) throws RepositoryException;
+
+    public boolean isCheckedOut(NodeId nodeId) throws RepositoryException;
+
+    public void restore(NodeId nodeId, NodeId versionId, boolean removeExisting) throws RepositoryException;
+
+    public void restore(NodeId[] versionIds, boolean removeExisting) throws RepositoryException;
+
+    /**
+     *
+     * @param nodeId
+     * @param workspaceName
+     * @param bestEffort
+     * @return A Collection of <code>ItemId</code> containing the ids of those
+     * <code>Node</code>s that failed to be merged and need manual resolution
+     * by the user of the API.
+     * @see #resolveMergeConflict(NodeId, NodeId, boolean)
+     */
+    public Collection merge(NodeId nodeId, String workspaceName, boolean bestEffort) throws RepositoryException;
+
+    /**
+     * 
+     * @param nodeId
+     * @param versionId
+     * @param done
+     * @throws RepositoryException
+     */
+    public void resolveMergeConflict(NodeId nodeId, NodeId versionId, boolean done) throws RepositoryException;
+}
\ No newline at end of file

Propchange: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/version/VersionManager.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/version/VersionManager.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url

Added: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/version/VersionManagerImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/version/VersionManagerImpl.java?rev=421270&view=auto
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/version/VersionManagerImpl.java (added)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/version/VersionManagerImpl.java Wed Jul 12 06:33:19 2006
@@ -0,0 +1,129 @@
+/*
+ * 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.jcr2spi.version;
+
+import org.apache.jackrabbit.jcr2spi.state.NodeState;
+import org.apache.jackrabbit.jcr2spi.state.UpdatableItemStateManager;
+import org.apache.jackrabbit.jcr2spi.state.PropertyState;
+import org.apache.jackrabbit.jcr2spi.state.ItemStateException;
+import org.apache.jackrabbit.jcr2spi.observation.InternalEventListener;
+import org.apache.jackrabbit.jcr2spi.operation.Operation;
+import org.apache.jackrabbit.jcr2spi.operation.Checkout;
+import org.apache.jackrabbit.jcr2spi.operation.Checkin;
+import org.apache.jackrabbit.jcr2spi.operation.Restore;
+import org.apache.jackrabbit.jcr2spi.operation.ResolveMergeConflict;
+import org.apache.jackrabbit.jcr2spi.operation.Merge;
+import org.slf4j.LoggerFactory;
+import org.slf4j.Logger;
+
+import javax.jcr.RepositoryException;
+import org.apache.jackrabbit.name.QName;
+import org.apache.jackrabbit.spi.EventIterator;
+import org.apache.jackrabbit.spi.Event;
+import org.apache.jackrabbit.spi.NodeId;
+import org.apache.jackrabbit.spi.PropertyId;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.ArrayList;
+
+/**
+ * <code>VersionManagerImpl</code>...
+ */
+public class VersionManagerImpl implements VersionManager {
+
+    private static Logger log = LoggerFactory.getLogger(VersionManagerImpl.class);
+
+    private final UpdatableItemStateManager stateManager;
+
+    public VersionManagerImpl(UpdatableItemStateManager stateManager) {
+        this.stateManager = stateManager;
+    }
+
+    public void checkin(NodeId nodeId) throws RepositoryException {
+        Operation ci = Checkin.create(nodeId);
+        stateManager.execute(ci);
+    }
+
+    public void checkout(NodeId nodeId) throws RepositoryException {
+        Operation co = Checkout.create(nodeId);
+        stateManager.execute(co);
+    }
+
+    public boolean isCheckedOut(NodeId nodeId) throws RepositoryException {
+        try {
+            NodeState nodeState = (NodeState) stateManager.getItemState(nodeId);
+            // search nearest ancestor that is versionable
+            /**
+             * FIXME should not only rely on existence of jcr:isCheckedOut property
+             * but also verify that node.isNodeType("mix:versionable")==true;
+             * this would have a negative impact on performance though...
+             */
+            while (!nodeState.hasPropertyName(QName.JCR_ISCHECKEDOUT)) {
+                if (nodeState.getParentId() == null) {
+                    // reached root state without finding a jcr:isCheckedOut property
+                    return true;
+                }
+                nodeState = (NodeState) stateManager.getItemState(nodeState.getParentId());
+            }
+            PropertyId propId = nodeState.getPropertyId(QName.JCR_ISCHECKEDOUT);
+            PropertyState propState = (PropertyState) stateManager.getItemState(propId);
+
+            Boolean b = Boolean.valueOf(propState.getValue().getString());
+            return b.booleanValue();
+        } catch (ItemStateException e) {
+            // should not occur
+            throw new RepositoryException(e);
+        }
+    }
+
+    public void restore(NodeId nodeId, NodeId versionId, boolean removeExisting) throws RepositoryException {
+        Operation op = Restore.create(nodeId, versionId, removeExisting);
+        stateManager.execute(op);
+    }
+
+    public void restore(NodeId[] versionIds, boolean removeExisting) throws RepositoryException {
+        Operation op = Restore.create(versionIds, removeExisting);
+        stateManager.execute(op);
+    }
+
+    public Collection merge(NodeId nodeId, String workspaceName, boolean bestEffort) throws RepositoryException {
+        // TODO find better solution to build the mergeFailed-collection
+        final List failedIds = new ArrayList();
+        InternalEventListener mergeFailedCollector = new InternalEventListener() {
+            public void onEvent(EventIterator events, boolean isLocal) {
+                if (isLocal) {
+                    while (events.hasNext()) {
+                        Event ev = events.nextEvent();
+                        if (ev.getType() == Event.PROPERTY_ADDED && QName.JCR_MERGEFAILED.equals(ev.getQPath().getNameElement().getName())) {
+                            failedIds.add(ev.getParentId());
+                        }
+                    }
+                }
+            }
+        };
+
+        Operation op = Merge.create(nodeId, workspaceName, bestEffort, mergeFailedCollector);
+        stateManager.execute(op);
+        return failedIds;
+    }
+
+    public void resolveMergeConflict(NodeId nodeId, NodeId versionId, boolean done) throws RepositoryException {
+        Operation op = ResolveMergeConflict.create(nodeId, versionId, done);
+        stateManager.execute(op);
+    }
+}
\ No newline at end of file

Propchange: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/version/VersionManagerImpl.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/version/VersionManagerImpl.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url

Added: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/xml/AbstractSAXEventGenerator.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/xml/AbstractSAXEventGenerator.java?rev=421270&view=auto
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/xml/AbstractSAXEventGenerator.java (added)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/xml/AbstractSAXEventGenerator.java Wed Jul 12 06:33:19 2006
@@ -0,0 +1,326 @@
+/*
+ * 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.jcr2spi.xml;
+
+import org.apache.jackrabbit.name.SessionNamespaceResolver;
+import org.apache.jackrabbit.name.NamespaceResolver;
+import org.apache.jackrabbit.name.NameException;
+import org.apache.jackrabbit.name.QName;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.SAXException;
+import org.slf4j.LoggerFactory;
+import org.slf4j.Logger;
+
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.Property;
+import javax.jcr.PropertyIterator;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+
+/**
+ * <code>AbstractSAXEventGenerator</code> serves as the base class for
+ * <code>SysViewSAXEventGenerator</code> and <code>DocViewSAXEventGenerator</code>
+ * <p/>
+ * It traverses a tree of <code>Node</code> & <code>Property</code>
+ * instances, and calls the abstract methods
+ * <ul>
+ * <li><code>{@link #entering(Node, int)}</code></li>
+ * <li><code>{@link #enteringProperties(Node, int)}</code></li>
+ * <li><code>{@link #leavingProperties(Node, int)}</code></li>
+ * <li><code>{@link #leaving(Node, int)}</code></li>
+ * <li><code>{@link #entering(Property, int)}</code></li>
+ * <li><code>{@link #leaving(Property, int)}</code></li>
+ * </ul>
+ * for every item it encounters.
+ */
+abstract class AbstractSAXEventGenerator {
+
+    private static Logger log = LoggerFactory.getLogger(AbstractSAXEventGenerator.class);
+
+    /**
+     * the session to be used for resolving namespace mappings
+     */
+    protected final Session session;
+    /**
+     * the session's namespace resolver
+     */
+    protected final NamespaceResolver nsResolver;
+
+    /**
+     * the content handler to feed the SAX events to
+     */
+    protected final ContentHandler contentHandler;
+
+    protected final Node startNode;
+    protected final boolean skipBinary;
+    protected final boolean noRecurse;
+
+    /**
+     * The jcr:primaryType property name (allowed for session-local prefix mappings)
+     */
+    protected final String jcrPrimaryType;
+    /**
+     * The jcr:mixinTypes property name (allowed for session-local prefix mappings)
+     */
+    protected final String jcrMixinTypes;
+    /**
+     * The jcr:uuid property name (allowed for session-local prefix mappings)
+     */
+    protected final String jcrUUID;
+    /**
+     * The jcr:root node name (allowed for session-local prefix mappings)
+     */
+    protected final String jcrRoot;
+    /**
+     * The jcr:xmltext node name (allowed for session-local prefix mappings)
+     */
+    protected final String jcrXMLText;
+    /**
+     * The jcr:xmlCharacters property name (allowed for session-local prefix mappings)
+     */
+    protected final String jcrXMLCharacters;
+
+    /**
+     * Constructor
+     *
+     * @param node           the node state which should be serialized
+     * @param noRecurse      if true, only <code>node</code> and its properties will
+     *                       be serialized; otherwise the entire hierarchy starting with
+     *                       <code>node</code> will be serialized.
+     * @param skipBinary     flag governing whether binary properties are to be serialized.
+     * @param contentHandler the content handler to feed the SAX events to
+     * @throws RepositoryException if an error occurs
+     */
+    protected AbstractSAXEventGenerator(Node node, boolean noRecurse,
+                                        boolean skipBinary,
+                                        ContentHandler contentHandler)
+            throws RepositoryException {
+        startNode = node;
+        session = node.getSession();
+        nsResolver = new SessionNamespaceResolver(session);
+
+        this.contentHandler = contentHandler;
+        this.skipBinary = skipBinary;
+        this.noRecurse = noRecurse;
+
+        // resolve the names of some wellknown properties
+        // allowing for session-local prefix mappings
+        try {
+            jcrPrimaryType = nsResolver.getJCRName(QName.JCR_PRIMARYTYPE);
+            jcrMixinTypes = nsResolver.getJCRName(QName.JCR_MIXINTYPES);
+            jcrUUID = nsResolver.getJCRName(QName.JCR_UUID);
+            jcrRoot = nsResolver.getJCRName(QName.JCR_ROOT);
+            jcrXMLText = nsResolver.getJCRName(QName.JCR_XMLTEXT);
+            jcrXMLCharacters = nsResolver.getJCRName(QName.JCR_XMLCHARACTERS);
+        } catch (NameException e) {
+            // should never get here...
+            String msg = "internal error: failed to resolve namespace mappings";
+            log.error(msg, e);
+            throw new RepositoryException(msg, e);
+        }
+    }
+
+    /**
+     * Serializes the hierarchy of nodes and properties.
+     *
+     * @throws RepositoryException if an error occurs while traversing the hierarchy
+     * @throws SAXException        if an error occured while feeding the events
+     *                             to the content handler
+     */
+    public void serialize() throws RepositoryException, SAXException {
+        // start document and declare namespaces
+        contentHandler.startDocument();
+        startNamespaceDeclarations();
+
+        // serialize node and subtree
+        process(startNode, 0);
+
+        // clear namespace declarations and end document
+        endNamespaceDeclarations();
+        contentHandler.endDocument();
+    }
+
+    /**
+     * @throws RepositoryException
+     * @throws SAXException
+     */
+    protected void startNamespaceDeclarations()
+            throws RepositoryException, SAXException {
+        // start namespace declarations
+        String[] prefixes = session.getNamespacePrefixes();
+        for (int i = 0; i < prefixes.length; i++) {
+            String prefix = prefixes[i];
+            if (QName.NS_XML_PREFIX.equals(prefix)) {
+                // skip 'xml' prefix as this would be an illegal namespace declaration
+                continue;
+            }
+            String uri = session.getNamespaceURI(prefix);
+            contentHandler.startPrefixMapping(prefix, uri);
+        }
+    }
+
+    /**
+     * @throws RepositoryException
+     * @throws SAXException
+     */
+    protected void endNamespaceDeclarations()
+            throws RepositoryException, SAXException {
+        // end namespace declarations
+        String[] prefixes = session.getNamespacePrefixes();
+        for (int i = 0; i < prefixes.length; i++) {
+            String prefix = prefixes[i];
+            if (QName.NS_XML_PREFIX.equals(prefix)) {
+                // skip 'xml' prefix as this would be an illegal namespace declaration
+                continue;
+            }
+            contentHandler.endPrefixMapping(prefix);
+        }
+    }
+
+    /**
+     * @param node
+     * @param level
+     * @throws RepositoryException
+     * @throws SAXException
+     */
+    protected void process(Node node, int level)
+            throws RepositoryException, SAXException {
+        // enter node
+        entering(node, level);
+
+        // enter properties
+        enteringProperties(node, level);
+
+        // serialize jcr:primaryType, jcr:mixinTypes & jcr:uuid first:
+        // jcr:primaryType
+        if (node.hasProperty(jcrPrimaryType)) {
+            process(node.getProperty(jcrPrimaryType), level + 1);
+        } else {
+            String msg = "internal error: missing jcr:primaryType property on node "
+                    + node.getPath();
+            log.debug(msg);
+            throw new RepositoryException(msg);
+        }
+        // jcr:mixinTypes
+        if (node.hasProperty(jcrMixinTypes)) {
+            process(node.getProperty(jcrMixinTypes), level + 1);
+        }
+        // jcr:uuid
+        if (node.hasProperty(jcrUUID)) {
+            process(node.getProperty(jcrUUID), level + 1);
+        }
+
+        // serialize remaining properties
+        PropertyIterator propIter = node.getProperties();
+        while (propIter.hasNext()) {
+            Property prop = propIter.nextProperty();
+            String name = prop.getName();
+            if (jcrPrimaryType.equals(name)
+                    || jcrMixinTypes.equals(name)
+                    || jcrUUID.equals(name)) {
+                continue;
+            }
+            // serialize property
+            process(prop, level + 1);
+        }
+
+        // leaving properties
+        leavingProperties(node, level);
+
+        if (!noRecurse) {
+            // child nodes
+            NodeIterator nodeIter = node.getNodes();
+            while (nodeIter.hasNext()) {
+                Node childNode = nodeIter.nextNode();
+                // recurse
+                process(childNode, level + 1);
+            }
+        }
+
+        // leaving node
+        leaving(node, level);
+    }
+
+    /**
+     * @param prop
+     * @param level
+     * @throws RepositoryException
+     * @throws SAXException
+     */
+    protected void process(Property prop, int level)
+            throws RepositoryException, SAXException {
+        // serialize property
+        entering(prop, level);
+        leaving(prop, level);
+    }
+
+    /**
+     * @param node
+     * @param level
+     * @throws RepositoryException
+     * @throws SAXException
+     */
+    protected abstract void entering(Node node, int level)
+            throws RepositoryException, SAXException;
+
+    /**
+     * @param node
+     * @param level
+     * @throws RepositoryException
+     * @throws SAXException
+     */
+    protected abstract void enteringProperties(Node node, int level)
+            throws RepositoryException, SAXException;
+
+    /**
+     * @param node
+     * @param level
+     * @throws RepositoryException
+     * @throws SAXException
+     */
+    protected abstract void leavingProperties(Node node, int level)
+            throws RepositoryException, SAXException;
+
+    /**
+     * @param node
+     * @param level
+     * @throws RepositoryException
+     * @throws SAXException
+     */
+    protected abstract void leaving(Node node, int level)
+            throws RepositoryException, SAXException;
+
+    /**
+     * @param prop
+     * @param level
+     * @throws RepositoryException
+     * @throws SAXException
+     */
+    protected abstract void entering(Property prop, int level)
+            throws RepositoryException, SAXException;
+
+    /**
+     * @param prop
+     * @param level
+     * @throws RepositoryException
+     * @throws SAXException
+     */
+    protected abstract void leaving(Property prop, int level)
+            throws RepositoryException, SAXException;
+
+}

Propchange: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/xml/AbstractSAXEventGenerator.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/xml/AbstractSAXEventGenerator.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url

Added: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/xml/DocViewImportHandler.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/xml/DocViewImportHandler.java?rev=421270&view=auto
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/xml/DocViewImportHandler.java (added)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/xml/DocViewImportHandler.java Wed Jul 12 06:33:19 2006
@@ -0,0 +1,281 @@
+/*
+ * 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.jcr2spi.xml;
+
+import org.apache.jackrabbit.name.NamespaceResolver;
+import org.apache.jackrabbit.name.NameException;
+import org.apache.jackrabbit.name.QName;
+import org.apache.jackrabbit.util.ISO9075;
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+import org.slf4j.LoggerFactory;
+import org.slf4j.Logger;
+
+import javax.jcr.PropertyType;
+import javax.jcr.RepositoryException;
+import org.apache.jackrabbit.spi.NodeId;
+import org.apache.jackrabbit.spi.IdFactory;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.util.ArrayList;
+import java.util.Stack;
+
+/**
+ * <code>DocViewImportHandler</code> processes Document View XML SAX events
+ * and 'translates' them into <code>{@link Importer}</code> method calls.
+ */
+class DocViewImportHandler extends TargetImportHandler {
+
+    private static Logger log = LoggerFactory.getLogger(DocViewImportHandler.class);
+
+    /**
+     * stack of NodeInfo instances; an instance is pushed onto the stack
+     * in the startElement method and is popped from the stack in the
+     * endElement method.
+     */
+    private final Stack stack = new Stack();
+    // buffer used to merge adjacent character data
+    private BufferedStringValue textHandler = new BufferedStringValue();
+
+    /**
+     * Constructs a new <code>DocViewImportHandler</code>.
+     *
+     * @param importer
+     * @param nsContext
+     */
+    DocViewImportHandler(Importer importer, NamespaceResolver nsContext, IdFactory idFactory) {
+        super(importer, nsContext, idFactory);
+    }
+
+    /**
+     * Appends the given character data to the internal buffer.
+     *
+     * @param ch     the characters to be appended
+     * @param start  the index of the first character to append
+     * @param length the number of characters to append
+     * @throws SAXException if an error occurs
+     * @see #characters(char[], int, int)
+     * @see #ignorableWhitespace(char[], int, int)
+     * @see #processCharacters()
+     */
+    private void appendCharacters(char[] ch, int start, int length)
+            throws SAXException {
+        if (textHandler == null) {
+            textHandler = new BufferedStringValue();
+        }
+        try {
+            textHandler.append(ch, start, length);
+        } catch (IOException ioe) {
+            String msg = "internal error while processing internal buffer data";
+            log.error(msg, ioe);
+            throw new SAXException(msg, ioe);
+        }
+    }
+
+    /**
+     * Translates character data reported by the
+     * <code>{@link #characters(char[], int, int)}</code> &
+     * <code>{@link #ignorableWhitespace(char[], int, int)}</code> SAX events
+     * into a  <code>jcr:xmltext</code> child node with one
+     * <code>jcr:xmlcharacters</code> property.
+     *
+     * @throws SAXException if an error occurs
+     * @see #appendCharacters(char[], int, int)
+     */
+    private void processCharacters()
+            throws SAXException {
+        try {
+            if (textHandler != null && textHandler.length() > 0) {
+                // there is character data that needs to be added to
+                // the current node
+
+                // check for pure whitespace character data
+                Reader reader = textHandler.reader();
+                try {
+                    int ch;
+                    while ((ch = reader.read()) != -1) {
+                        if (ch > 0x20) {
+                            break;
+                        }
+                    }
+                    if (ch == -1) {
+                        // the character data consists of pure whitespace, ignore
+                        log.debug("ignoring pure whitespace character data...");
+                        // reset handler
+                        textHandler.dispose();
+                        textHandler = null;
+                        return;
+                    }
+                } finally {
+                    reader.close();
+                }
+
+                Importer.NodeInfo node =
+                        new Importer.NodeInfo(QName.JCR_XMLTEXT, null, null, null);
+                Importer.TextValue[] values =
+                        new Importer.TextValue[]{textHandler};
+                ArrayList props = new ArrayList();
+                Importer.PropInfo prop =
+                        new Importer.PropInfo(QName.JCR_XMLCHARACTERS, PropertyType.STRING, values);
+                props.add(prop);
+                // call Importer
+                importer.startNode(node, props, nsContext);
+                importer.endNode(node);
+
+                // reset handler
+                textHandler.dispose();
+                textHandler = null;
+            }
+        } catch (IOException ioe) {
+            String msg = "internal error while processing internal buffer data";
+            log.error(msg, ioe);
+            throw new SAXException(msg, ioe);
+        } catch (RepositoryException re) {
+            throw new SAXException(re);
+        }
+    }
+
+    //-------------------------------------------------------< ContentHandler >
+
+    /**
+     * {@inheritDoc}
+     * <p/>
+     * See also {@link DocViewSAXEventGenerator#leavingProperties(javax.jcr.Node, int)}
+     * regarding special handling of multi-valued properties on export.
+     */
+    public void startElement(String namespaceURI, String localName,
+                             String qName, Attributes atts)
+            throws SAXException {
+        // process buffered character data
+        processCharacters();
+
+        try {
+            QName nodeName = new QName(namespaceURI, localName);
+            // decode node name
+            nodeName = ISO9075.decode(nodeName);
+
+            // properties
+            NodeId id = null;
+            QName nodeTypeName = null;
+            QName[] mixinTypes = null;
+
+            ArrayList props = new ArrayList(atts.getLength());
+            for (int i = 0; i < atts.getLength(); i++) {
+                QName propName = new QName(atts.getURI(i), atts.getLocalName(i));
+                // decode property name
+                propName = ISO9075.decode(propName);
+
+                // value(s)
+                String attrValue = atts.getValue(i);
+                Importer.TextValue[] propValues;
+
+                // always assume single-valued property for the time being
+                // until a way of properly serializing/detecting multi-valued
+                // properties on re-import is found (see JCR-325);
+                // see also DocViewSAXEventGenerator#leavingProperties(Node, int)
+                // todo proper multi-value serialization support
+                propValues = new Importer.TextValue[1];
+                propValues[0] = new StringValue(attrValue);
+
+                if (propName.equals(QName.JCR_PRIMARYTYPE)) {
+                    // jcr:primaryType
+                    if (attrValue.length() > 0) {
+                        try {
+                            nodeTypeName = nsContext.getQName(attrValue);
+                        } catch (NameException ne) {
+                            throw new SAXException("illegal jcr:primaryType value: "
+                                    + attrValue, ne);
+                        }
+                    }
+                } else if (propName.equals(QName.JCR_MIXINTYPES)) {
+                    // jcr:mixinTypes
+                    if (propValues.length > 0) {
+                        mixinTypes = new QName[propValues.length];
+                        for (int j = 0; j < propValues.length; j++) {
+                            String val = ((StringValue) propValues[j]).retrieve();
+                            try {
+                                mixinTypes[j] = nsContext.getQName(val);
+                            } catch (NameException ne) {
+                                throw new SAXException("illegal jcr:mixinTypes value: "
+                                        + val, ne);
+                            }
+                        }
+                    }
+                } else if (propName.equals(QName.JCR_UUID)) {
+                    // jcr:uuid
+                    if (attrValue.length() > 0) {
+                        id = idFactory.createNodeId(attrValue);
+                    }
+                } else {
+                    props.add(new Importer.PropInfo(propName, PropertyType.UNDEFINED, propValues));
+                }
+            }
+
+            Importer.NodeInfo node = new Importer.NodeInfo(nodeName, nodeTypeName, mixinTypes, id);
+            // all information has been collected, now delegate to importer
+            importer.startNode(node, props, nsContext);
+            // push current node data onto stack
+            stack.push(node);
+        } catch (RepositoryException re) {
+            throw new SAXException(re);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void characters(char[] ch, int start, int length)
+            throws SAXException {
+        /**
+         * buffer data reported by the characters event;
+         * will be processed on the next endElement or startElement event.
+         */
+        appendCharacters(ch, start, length);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void ignorableWhitespace(char[] ch, int start, int length)
+            throws SAXException {
+        /**
+         * buffer data reported by the ignorableWhitespace event;
+         * will be processed on the next endElement or startElement event.
+         */
+        appendCharacters(ch, start, length);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void endElement(String namespaceURI, String localName, String qName)
+            throws SAXException {
+        // process buffered character data
+        processCharacters();
+
+        Importer.NodeInfo node = (Importer.NodeInfo) stack.peek();
+        try {
+            // call Importer
+            importer.endNode(node);
+        } catch (RepositoryException re) {
+            throw new SAXException(re);
+        }
+        // we're done with this node, pop it from stack
+        stack.pop();
+    }
+}

Propchange: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/xml/DocViewImportHandler.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/xml/DocViewImportHandler.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url

Added: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/xml/DocViewSAXEventGenerator.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/xml/DocViewSAXEventGenerator.java?rev=421270&view=auto
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/xml/DocViewSAXEventGenerator.java (added)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/xml/DocViewSAXEventGenerator.java Wed Jul 12 06:33:19 2006
@@ -0,0 +1,222 @@
+/*
+ * 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.jcr2spi.xml;
+
+import org.apache.jackrabbit.name.NameException;
+import org.apache.jackrabbit.name.QName;
+import org.apache.jackrabbit.util.ISO9075;
+import org.apache.jackrabbit.value.ValueHelper;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.AttributesImpl;
+import org.slf4j.LoggerFactory;
+import org.slf4j.Logger;
+
+import javax.jcr.Node;
+import javax.jcr.Property;
+import javax.jcr.PropertyType;
+import javax.jcr.RepositoryException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * A <code>DocViewSAXEventGenerator</code> instance can be used to generate
+ * SAX events representing the serialized form of an item in Document View XML.
+ */
+public class DocViewSAXEventGenerator extends AbstractSAXEventGenerator {
+
+    private static Logger log = LoggerFactory.getLogger(DocViewSAXEventGenerator.class);
+
+    public static final String CDATA_TYPE = "CDATA";
+
+    // used to temporarily store properties of a node
+    private final List props;
+
+    /**
+     * Constructor
+     *
+     * @param node           the node state which should be serialized
+     * @param noRecurse      if true, only <code>node</code> and its properties
+     *                       will be serialized; otherwise the entire hierarchy
+     *                       starting with <code>node</code> will be serialized.
+     * @param skipBinary     flag governing whether binary properties are to be
+     *                       serialized.
+     * @param contentHandler the content handler to feed the SAX events to
+     * @throws RepositoryException if an error occurs
+     */
+    public DocViewSAXEventGenerator(Node node, boolean noRecurse,
+                                    boolean skipBinary,
+                                    ContentHandler contentHandler)
+            throws RepositoryException {
+        super(node, noRecurse, skipBinary, contentHandler);
+
+        props = new ArrayList();
+    }
+
+    private QName getQName(String rawName) throws RepositoryException {
+        try {
+            return nsResolver.getQName(rawName);
+        } catch (NameException e) {
+            // should never get here...
+            String msg = "internal error: failed to resolve namespace mappings";
+            log.error(msg, e);
+            throw new RepositoryException(msg, e);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    protected void entering(Node node, int level)
+            throws RepositoryException, SAXException {
+        // nop
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    protected void enteringProperties(Node node, int level)
+            throws RepositoryException, SAXException {
+        // reset list of properties
+        props.clear();
+    }
+
+    /**
+     * {@inheritDoc}
+     * <p/>
+     * See also {@link DocViewImportHandler#startElement(String, String, String, org.xml.sax.Attributes)}
+     * regarding special handling of multi-valued properties on import.
+     */
+    protected void leavingProperties(Node node, int level)
+            throws RepositoryException, SAXException {
+        String name = node.getName();
+        if (name.equals(jcrXMLText)) {
+            // the node represents xml character data
+            Iterator iter = props.iterator();
+            while (iter.hasNext()) {
+                Property prop = (Property) iter.next();
+                String propName = prop.getName();
+                if (propName.equals(jcrXMLCharacters)) {
+                    // assume jcr:xmlcharacters is single-valued
+                    char[] chars = prop.getValue().getString().toCharArray();
+                    contentHandler.characters(chars, 0, chars.length);
+                }
+            }
+        } else {
+            // regular node
+
+            // element name
+            String elemName;
+            if (node.getDepth() == 0) {
+                // root node needs a name
+                elemName = jcrRoot;
+            } else {
+                // encode node name to make sure it's a valid xml name
+                elemName = ISO9075.encode(name);
+            }
+
+            // attributes (properties)
+            AttributesImpl attrs = new AttributesImpl();
+            Iterator iter = props.iterator();
+            while (iter.hasNext()) {
+                Property prop = (Property) iter.next();
+                String propName = prop.getName();
+
+                if (prop.getDefinition().isMultiple()) {
+                    // todo proper multi-value serialization support
+                    // skip multi-valued properties for the time being
+                    // until a way of properly handling/detecting multi-valued
+                    // properties on re-import is found (see JCR-325);
+                    // see also DocViewImportHandler#startElement()
+
+                    // skipping multi-valued properties entirely is legal
+                    // according to "6.4.2.5 Multi-value Properties" of the
+                    // jsr-170 specification
+                    continue;
+                }
+
+                // attribute name (encode property name to make sure it's a valid xml name)
+                String attrName = ISO9075.encode(propName);
+                QName qName = getQName(attrName);
+
+                // attribute value
+                if (prop.getType() == PropertyType.BINARY && skipBinary) {
+                    // add empty attribute
+                    attrs.addAttribute(qName.getNamespaceURI(),
+                            qName.getLocalName(), attrName, CDATA_TYPE, "");
+                } else {
+                    StringBuffer attrValue = new StringBuffer();
+                    // serialize single-valued property
+                    attrValue.append(ValueHelper.serialize(prop.getValue(), false));
+                    attrs.addAttribute(qName.getNamespaceURI(),
+                            qName.getLocalName(), attrName, CDATA_TYPE,
+                            attrValue.toString());
+                }
+            }
+            // start element (node)
+            QName qName = getQName(elemName);
+            contentHandler.startElement(qName.getNamespaceURI(),
+                    qName.getLocalName(), elemName, attrs);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    protected void leaving(Node node, int level)
+            throws RepositoryException, SAXException {
+        String name = node.getName();
+        if (name.equals(jcrXMLText)) {
+            // the node represents xml character data
+            // (already processed in leavingProperties(NodeImpl, int)
+            return;
+        }
+        // encode node name to make sure it's a valid xml name
+        name = ISO9075.encode(name);
+        // element name
+        String elemName;
+        if (node.getDepth() == 0) {
+            // root node needs a name
+            elemName = jcrRoot;
+        } else {
+            // encode node name to make sure it's a valid xml name
+            elemName = ISO9075.encode(name);
+        }
+
+        // end element (node)
+        QName qName = getQName(elemName);
+        contentHandler.endElement(qName.getNamespaceURI(), qName.getLocalName(),
+                elemName);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    protected void entering(Property prop, int level)
+            throws RepositoryException, SAXException {
+        props.add(prop);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    protected void leaving(Property prop, int level)
+            throws RepositoryException, SAXException {
+        // nop
+    }
+}