You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by ju...@apache.org on 2008/01/14 12:50:03 UTC

svn commit: r611778 - in /jackrabbit/sandbox/jackrabbit-ngp: ./ src/main/java/org/apache/jackrabbit/ngp/ src/main/java/org/apache/jackrabbit/ngp/node/ src/main/java/org/apache/jackrabbit/ngp/session/ src/main/java/org/apache/jackrabbit/ngp/store/ src/t...

Author: jukka
Date: Mon Jan 14 03:50:01 2008
New Revision: 611778

URL: http://svn.apache.org/viewvc?rev=611778&view=rev
Log:
ngp: Work in progress
   - Added very rough JCR-level implementation classes
     to make testing more natural
   - Prototyping a State pattern implementation for
     better handling Session and Node states
   - Added test cases for some trivial operations
   - Trying out a simpler "store" alternative to
     current "journal" code

Added:
    jackrabbit/sandbox/jackrabbit-ngp/src/main/java/org/apache/jackrabbit/ngp/NodeImpl.java
    jackrabbit/sandbox/jackrabbit-ngp/src/main/java/org/apache/jackrabbit/ngp/RepositoryImpl.java
    jackrabbit/sandbox/jackrabbit-ngp/src/main/java/org/apache/jackrabbit/ngp/SessionImpl.java
    jackrabbit/sandbox/jackrabbit-ngp/src/main/java/org/apache/jackrabbit/ngp/node/
    jackrabbit/sandbox/jackrabbit-ngp/src/main/java/org/apache/jackrabbit/ngp/node/BoundNode.java
    jackrabbit/sandbox/jackrabbit-ngp/src/main/java/org/apache/jackrabbit/ngp/node/ClosedNode.java
    jackrabbit/sandbox/jackrabbit-ngp/src/main/java/org/apache/jackrabbit/ngp/node/NodeState.java
    jackrabbit/sandbox/jackrabbit-ngp/src/main/java/org/apache/jackrabbit/ngp/node/StateSwitch.java
    jackrabbit/sandbox/jackrabbit-ngp/src/main/java/org/apache/jackrabbit/ngp/session/
    jackrabbit/sandbox/jackrabbit-ngp/src/main/java/org/apache/jackrabbit/ngp/session/BoundSession.java
    jackrabbit/sandbox/jackrabbit-ngp/src/main/java/org/apache/jackrabbit/ngp/session/ClosedSession.java
    jackrabbit/sandbox/jackrabbit-ngp/src/main/java/org/apache/jackrabbit/ngp/session/SessionState.java
    jackrabbit/sandbox/jackrabbit-ngp/src/main/java/org/apache/jackrabbit/ngp/session/StateSwitch.java
    jackrabbit/sandbox/jackrabbit-ngp/src/main/java/org/apache/jackrabbit/ngp/session/UnboundSession.java
    jackrabbit/sandbox/jackrabbit-ngp/src/main/java/org/apache/jackrabbit/ngp/store/
    jackrabbit/sandbox/jackrabbit-ngp/src/main/java/org/apache/jackrabbit/ngp/store/Record.java
    jackrabbit/sandbox/jackrabbit-ngp/src/main/java/org/apache/jackrabbit/ngp/store/Store.java
    jackrabbit/sandbox/jackrabbit-ngp/src/test/java/org/apache/jackrabbit/ngp/AbstractNodeTest.java
    jackrabbit/sandbox/jackrabbit-ngp/src/test/java/org/apache/jackrabbit/ngp/AbstractRepositoryTest.java
    jackrabbit/sandbox/jackrabbit-ngp/src/test/java/org/apache/jackrabbit/ngp/AbstractSessionTest.java
    jackrabbit/sandbox/jackrabbit-ngp/src/test/java/org/apache/jackrabbit/ngp/NodeTest.java
    jackrabbit/sandbox/jackrabbit-ngp/src/test/java/org/apache/jackrabbit/ngp/RepositoryTest.java
    jackrabbit/sandbox/jackrabbit-ngp/src/test/java/org/apache/jackrabbit/ngp/SessionTest.java
Modified:
    jackrabbit/sandbox/jackrabbit-ngp/pom.xml

Modified: jackrabbit/sandbox/jackrabbit-ngp/pom.xml
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-ngp/pom.xml?rev=611778&r1=611777&r2=611778&view=diff
==============================================================================
--- jackrabbit/sandbox/jackrabbit-ngp/pom.xml (original)
+++ jackrabbit/sandbox/jackrabbit-ngp/pom.xml Mon Jan 14 03:50:01 2008
@@ -27,7 +27,7 @@
   <artifactId>jackrabbit-ngp</artifactId>
   <version>SNAPSHOT</version>
   <name>Jackrabbit NGP</name>
-  <description>Experimental codebase for Jackrabbit Next Generation Persistence</description>
+  <description>Jackrabbit Next Generation Persistence</description>
 
   <dependencies>
     <dependency>
@@ -37,11 +37,38 @@
       <scope>provided</scope>
     </dependency>
     <dependency>
+      <groupId>org.apache.jackrabbit</groupId>
+      <artifactId>jackrabbit-jcr-commons</artifactId>
+      <version>1.4</version>
+    </dependency>
+    <dependency>
+      <groupId>commons-collections</groupId>
+      <artifactId>commons-collections</artifactId>
+      <version>3.1</version>
+    </dependency>
+    <dependency>
+      <groupId>commons-codec</groupId>
+      <artifactId>commons-codec</artifactId>
+      <version>1.3</version>
+    </dependency>
+    <dependency>
       <groupId>junit</groupId>
       <artifactId>junit</artifactId>
-      <version>3.8.1</version>
+      <version>4.4</version>
       <scope>test</scope>
     </dependency>
   </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <artifactId>maven-compiler-plugin</artifactId>
+        <configuration>
+          <source>1.5</source>
+          <target>1.5</target>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
 
 </project>

Added: jackrabbit/sandbox/jackrabbit-ngp/src/main/java/org/apache/jackrabbit/ngp/NodeImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-ngp/src/main/java/org/apache/jackrabbit/ngp/NodeImpl.java?rev=611778&view=auto
==============================================================================
--- jackrabbit/sandbox/jackrabbit-ngp/src/main/java/org/apache/jackrabbit/ngp/NodeImpl.java (added)
+++ jackrabbit/sandbox/jackrabbit-ngp/src/main/java/org/apache/jackrabbit/ngp/NodeImpl.java Mon Jan 14 03:50:01 2008
@@ -0,0 +1,321 @@
+/**
+ * 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.ngp;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Map;
+
+import javax.jcr.AccessDeniedException;
+import javax.jcr.InvalidItemStateException;
+import javax.jcr.Item;
+import javax.jcr.ItemExistsException;
+import javax.jcr.ItemNotFoundException;
+import javax.jcr.MergeException;
+import javax.jcr.NoSuchWorkspaceException;
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.PathNotFoundException;
+import javax.jcr.Property;
+import javax.jcr.PropertyIterator;
+import javax.jcr.ReferentialIntegrityException;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.UnsupportedRepositoryOperationException;
+import javax.jcr.Value;
+import javax.jcr.ValueFormatException;
+import javax.jcr.lock.Lock;
+import javax.jcr.lock.LockException;
+import javax.jcr.nodetype.ConstraintViolationException;
+import javax.jcr.nodetype.NoSuchNodeTypeException;
+import javax.jcr.nodetype.NodeDefinition;
+import javax.jcr.version.Version;
+import javax.jcr.version.VersionException;
+
+import org.apache.jackrabbit.commons.AbstractNode;
+import org.apache.jackrabbit.commons.iterator.NodeIteratorAdapter;
+import org.apache.jackrabbit.ngp.node.NodeState;
+
+public class NodeImpl extends AbstractNode {
+
+    private final Session session;
+
+    private final Node parent;
+
+    private final String name;
+
+    private final NodeState state;
+
+    NodeImpl(Session session, Node parent, String name, NodeState state) {
+        this.session = session;
+        this.parent = parent;
+        this.name = name;
+        this.state = state;
+    }
+
+    /**
+     * Returns the session this node belongs to.
+     *
+     * @return repository session
+     */
+    public Session getSession() {
+        return session;
+    }
+
+    public void refresh(boolean keepChanges) throws RepositoryException {
+        session.refresh(keepChanges);
+    }
+
+    public Node getParent() throws ItemNotFoundException {
+        if (parent != null) {
+            // TODO: Support moves
+            return parent;
+        } else {
+            throw new ItemNotFoundException("The root node has no parent");
+        }
+    }
+
+    public String getName() {
+        // TODO: Support renames
+        return name;
+    }
+
+    public int getIndex() throws RepositoryException {
+        // TODO: Support same-name-siblings
+        return 1;
+    }
+
+    public boolean isModified() {
+        return false;
+    }
+
+    public boolean isNew() {
+        return false;
+    }
+
+    public NodeIterator getNodes() throws RepositoryException {
+        synchronized (session) {
+            Map<String, NodeState> states = state.getNodes();
+            Collection<Node> nodes = new ArrayList<Node>(states.size());
+            for (Map.Entry<String, NodeState> entry : states.entrySet()) {
+                nodes.add(new NodeImpl(
+                        session, this, entry.getKey(), entry.getValue()));
+            }
+            return new NodeIteratorAdapter(nodes);
+        }
+    }
+
+    public void addMixin(String mixinName) throws NoSuchNodeTypeException,
+            VersionException, ConstraintViolationException, LockException,
+            RepositoryException {
+        // TODO Auto-generated method stub
+
+    }
+
+    public Node addNode(String relPath) throws ItemExistsException,
+            PathNotFoundException, VersionException,
+            ConstraintViolationException, LockException, RepositoryException {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public Node addNode(String relPath, String primaryNodeTypeName)
+            throws ItemExistsException, PathNotFoundException,
+            NoSuchNodeTypeException, LockException, VersionException,
+            ConstraintViolationException, RepositoryException {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public boolean canAddMixin(String mixinName)
+            throws NoSuchNodeTypeException, RepositoryException {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    public void cancelMerge(Version version) throws VersionException,
+            InvalidItemStateException, UnsupportedRepositoryOperationException,
+            RepositoryException {
+        // TODO Auto-generated method stub
+
+    }
+
+    public Version checkin() throws VersionException,
+            UnsupportedRepositoryOperationException, InvalidItemStateException,
+            LockException, RepositoryException {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public void checkout() throws UnsupportedRepositoryOperationException,
+            LockException, RepositoryException {
+        // TODO Auto-generated method stub
+
+    }
+
+    public void doneMerge(Version version) throws VersionException,
+            InvalidItemStateException, UnsupportedRepositoryOperationException,
+            RepositoryException {
+        // TODO Auto-generated method stub
+
+    }
+
+    public Version getBaseVersion()
+            throws UnsupportedRepositoryOperationException, RepositoryException {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public String getCorrespondingNodePath(String workspaceName)
+            throws ItemNotFoundException, NoSuchWorkspaceException,
+            AccessDeniedException, RepositoryException {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public NodeDefinition getDefinition() throws RepositoryException {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public Lock getLock() throws UnsupportedRepositoryOperationException,
+            LockException, AccessDeniedException, RepositoryException {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public Node getNode(String relPath) throws PathNotFoundException,
+            RepositoryException {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public NodeIterator getNodes(String namePattern) throws RepositoryException {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public Item getPrimaryItem() throws ItemNotFoundException,
+            RepositoryException {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public PropertyIterator getProperties() throws RepositoryException {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public PropertyIterator getProperties(String namePattern)
+            throws RepositoryException {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public PropertyIterator getReferences() throws RepositoryException {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public Lock lock(boolean isDeep, boolean isSessionScoped)
+            throws UnsupportedRepositoryOperationException, LockException,
+            AccessDeniedException, InvalidItemStateException,
+            RepositoryException {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public NodeIterator merge(String srcWorkspace, boolean bestEffort)
+            throws NoSuchWorkspaceException, AccessDeniedException,
+            MergeException, LockException, InvalidItemStateException,
+            RepositoryException {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public void orderBefore(String srcChildRelPath, String destChildRelPath)
+            throws UnsupportedRepositoryOperationException, VersionException,
+            ConstraintViolationException, ItemNotFoundException, LockException,
+            RepositoryException {
+        // TODO Auto-generated method stub
+
+    }
+
+    public void removeMixin(String mixinName) throws NoSuchNodeTypeException,
+            VersionException, ConstraintViolationException, LockException,
+            RepositoryException {
+        // TODO Auto-generated method stub
+
+    }
+
+    public void restore(Version version, String relPath, boolean removeExisting)
+            throws PathNotFoundException, ItemExistsException,
+            VersionException, ConstraintViolationException,
+            UnsupportedRepositoryOperationException, LockException,
+            InvalidItemStateException, RepositoryException {
+        // TODO Auto-generated method stub
+
+    }
+
+    public Property setProperty(String name, Value value)
+            throws ValueFormatException, VersionException, LockException,
+            ConstraintViolationException, RepositoryException {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public Property setProperty(String name, Value[] values)
+            throws ValueFormatException, VersionException, LockException,
+            ConstraintViolationException, RepositoryException {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public void unlock() throws UnsupportedRepositoryOperationException,
+            LockException, AccessDeniedException, InvalidItemStateException,
+            RepositoryException {
+        // TODO Auto-generated method stub
+
+    }
+
+    public void update(String srcWorkspaceName)
+            throws NoSuchWorkspaceException, AccessDeniedException,
+            LockException, InvalidItemStateException, RepositoryException {
+        // TODO Auto-generated method stub
+
+    }
+
+    public boolean isSame(Item otherItem) throws RepositoryException {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    public void remove() throws VersionException, LockException,
+            ConstraintViolationException, RepositoryException {
+        // TODO Auto-generated method stub
+
+    }
+
+    public void save() throws AccessDeniedException, ItemExistsException,
+            ConstraintViolationException, InvalidItemStateException,
+            ReferentialIntegrityException, VersionException, LockException,
+            NoSuchNodeTypeException, RepositoryException {
+        // TODO Auto-generated method stub
+
+    }
+
+}

Added: jackrabbit/sandbox/jackrabbit-ngp/src/main/java/org/apache/jackrabbit/ngp/RepositoryImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-ngp/src/main/java/org/apache/jackrabbit/ngp/RepositoryImpl.java?rev=611778&view=auto
==============================================================================
--- jackrabbit/sandbox/jackrabbit-ngp/src/main/java/org/apache/jackrabbit/ngp/RepositoryImpl.java (added)
+++ jackrabbit/sandbox/jackrabbit-ngp/src/main/java/org/apache/jackrabbit/ngp/RepositoryImpl.java Mon Jan 14 03:50:01 2008
@@ -0,0 +1,94 @@
+/**
+ * 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.ngp;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.jcr.Credentials;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.Workspace;
+
+import org.apache.jackrabbit.commons.AbstractRepository;
+import org.apache.jackrabbit.ngp.store.Store;
+
+public class RepositoryImpl extends AbstractRepository {
+
+    private static final Map<String, String> DESCRIPTORS =
+        new HashMap<String, String>();
+
+    static {
+        DESCRIPTORS.put(
+                SPEC_NAME_DESC,
+                "Content Repository API for Java(TM) Technology Specification");
+        DESCRIPTORS.put(SPEC_VERSION_DESC, "1.0");
+
+        DESCRIPTORS.put(REP_NAME_DESC, "Apache Jackrabbit NGP");
+        DESCRIPTORS.put(REP_VERSION_DESC, "SNAPSHOT");
+
+        DESCRIPTORS.put(REP_VENDOR_DESC, "Apache Software Foundation");
+        DESCRIPTORS.put(REP_VENDOR_URL_DESC, "http://jackrabbit.apache.org/");
+
+        // DESCRIPTORS.put(LEVEL_1_SUPPORTED, Boolean.TRUE.toString());
+        // DESCRIPTORS.put(LEVEL_2_SUPPORTED, Boolean.TRUE.toString());
+        // DESCRIPTORS.put(OPTION_LOCKING_SUPPORTED, Boolean.TRUE.toString());
+        // DESCRIPTORS.put(OPTION_OBSERVATION_SUPPORTED, Boolean.TRUE.toString());
+        // DESCRIPTORS.put(OPTION_QUERY_SQL_SUPPORTED, Boolean.TRUE.toString());
+        // DESCRIPTORS.put(OPTION_TRANSACTIONS_SUPPORTED, Boolean.TRUE.toString());
+        // DESCRIPTORS.put(OPTION_VERSIONING_SUPPORTED, Boolean.TRUE.toString());
+        // DESCRIPTORS.put(QUERY_XPATH_DOC_ORDER, Boolean.TRUE.toString());
+        // DESCRIPTORS.put(QUERY_XPATH_POS_INDEX, Boolean.TRUE.toString());
+    }
+
+    private final Store store;
+
+    public RepositoryImpl(Store store) {
+        this.store = store;
+    }
+
+    public RepositoryImpl(File directory) throws IOException {
+        this(new Store(directory));
+    }
+
+    public String getDescriptor(String key) {
+        return DESCRIPTORS.get(key);
+    }
+
+    public String[] getDescriptorKeys() {
+        return DESCRIPTORS.keySet().toArray(new String[DESCRIPTORS.size()]);
+    }
+
+    public Session login(Credentials credentials, String workspaceName)
+            throws RepositoryException {
+        if (credentials == null) {
+            credentials = new Credentials() {};
+        }
+        if (workspaceName == null) {
+            workspaceName = "";
+        }
+
+        Map<String, Object> attributes = new HashMap<String, Object>();
+        attributes.put(Credentials.class.getName(), credentials);
+        attributes.put(Workspace.class.getName(), workspaceName);
+
+        return new SessionImpl(this, attributes, store);
+    }
+
+}

Added: jackrabbit/sandbox/jackrabbit-ngp/src/main/java/org/apache/jackrabbit/ngp/SessionImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-ngp/src/main/java/org/apache/jackrabbit/ngp/SessionImpl.java?rev=611778&view=auto
==============================================================================
--- jackrabbit/sandbox/jackrabbit-ngp/src/main/java/org/apache/jackrabbit/ngp/SessionImpl.java (added)
+++ jackrabbit/sandbox/jackrabbit-ngp/src/main/java/org/apache/jackrabbit/ngp/SessionImpl.java Mon Jan 14 03:50:01 2008
@@ -0,0 +1,246 @@
+/**
+ * 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.ngp;
+
+import java.security.AccessControlException;
+import java.util.Map;
+
+import javax.jcr.AccessDeniedException;
+import javax.jcr.Credentials;
+import javax.jcr.InvalidItemStateException;
+import javax.jcr.ItemExistsException;
+import javax.jcr.ItemNotFoundException;
+import javax.jcr.NamespaceException;
+import javax.jcr.Node;
+import javax.jcr.PathNotFoundException;
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.jcr.SimpleCredentials;
+import javax.jcr.UnsupportedRepositoryOperationException;
+import javax.jcr.ValueFactory;
+import javax.jcr.Workspace;
+import javax.jcr.lock.LockException;
+import javax.jcr.nodetype.ConstraintViolationException;
+import javax.jcr.nodetype.NoSuchNodeTypeException;
+import javax.jcr.version.VersionException;
+
+import org.apache.jackrabbit.commons.AbstractSession;
+import org.apache.jackrabbit.ngp.session.ClosedSession;
+import org.apache.jackrabbit.ngp.session.StateSwitch;
+import org.apache.jackrabbit.ngp.session.UnboundSession;
+import org.apache.jackrabbit.ngp.store.Store;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.SAXException;
+
+public class SessionImpl extends AbstractSession {
+
+    private final Repository repository;
+
+    private final Map<String, Object> attributes;
+
+    private StateSwitch state;
+
+    SessionImpl(
+            Repository repository, Map<String, Object> attributes,
+            Store store) {
+        this.repository = repository;
+        this.attributes = attributes;
+        this.state = new StateSwitch();
+
+        state.setState(new UnboundSession(store, state));
+    }
+
+    /**
+     * Returns the repository this session belongs to.
+     *
+     * @return content repository
+     */
+    public Repository getRepository() {
+        return repository;
+    }
+
+    /**
+     * Returns the names of all the attributes associated with this session.
+     *
+     * @return attribute names
+     */
+    public String[] getAttributeNames() {
+        return attributes.keySet().toArray(new String[attributes.size()]);
+    }
+
+    /**
+     * Returns the value of the named attribute.
+     *
+     * @return attribute value, or <code>null</code> if not found
+     */
+    public Object getAttribute(String name) {
+        return attributes.get(name);
+    }
+
+    /**
+     * Returns the user id associated with the {@link SimpleCredentials}
+     * instance used when this session was created, or <code>null</code>
+     * if no or some other form of credentials was used.
+     *
+     * @return user id or <code>null</code>
+     */
+    public String getUserID() {
+        Credentials credentials = (Credentials)
+            getAttribute(Credentials.class.getName());
+        if (credentials instanceof SimpleCredentials) {
+            return ((SimpleCredentials) credentials).getUserID();
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Returns <code>true</code> if this session is usable by the client.
+     *
+     * @return state of this session
+     */
+    public boolean isLive() {
+        return state.isLive();
+    }
+
+    /**
+     * Refreshes this session to see the latest changes in the repository.
+     *
+     * @param keepChanges whether to keep transient changes
+     * @throws RepositoryException if the refresh fails
+     */
+    public synchronized void refresh(boolean keepChanges)
+            throws RepositoryException {
+        state.refresh(keepChanges);
+    }
+
+    /**
+     * Closes this session. Any unsaved state is discarded.
+     */
+    public synchronized void logout() {
+        state.setState(new ClosedSession());
+    }
+
+    public synchronized Node getRootNode() throws RepositoryException {
+        return new NodeImpl(this, null, "", state.getRootNode());
+    }
+
+    public void addLockToken(String lt) {
+        // TODO Auto-generated method stub
+
+    }
+
+    public void checkPermission(String absPath, String actions)
+            throws AccessControlException, RepositoryException {
+        // TODO Auto-generated method stub
+
+    }
+
+    public void exportDocumentView(String absPath,
+            ContentHandler contentHandler, boolean skipBinary, boolean noRecurse)
+            throws PathNotFoundException, SAXException, RepositoryException {
+        // TODO Auto-generated method stub
+
+    }
+
+    public void exportSystemView(String absPath, ContentHandler contentHandler,
+            boolean skipBinary, boolean noRecurse)
+            throws PathNotFoundException, SAXException, RepositoryException {
+        // TODO Auto-generated method stub
+
+    }
+
+    public ContentHandler getImportContentHandler(String parentAbsPath,
+            int uuidBehavior) throws PathNotFoundException,
+            ConstraintViolationException, VersionException, LockException,
+            RepositoryException {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public String[] getLockTokens() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public String getNamespacePrefix(String uri) throws NamespaceException,
+            RepositoryException {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public String[] getNamespacePrefixes() throws RepositoryException {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public String getNamespaceURI(String prefix) throws NamespaceException,
+            RepositoryException {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public Node getNodeByUUID(String uuid) throws ItemNotFoundException,
+            RepositoryException {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public ValueFactory getValueFactory()
+            throws UnsupportedRepositoryOperationException, RepositoryException {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public Workspace getWorkspace() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public boolean hasPendingChanges() throws RepositoryException {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    public void move(String srcAbsPath, String destAbsPath)
+            throws ItemExistsException, PathNotFoundException,
+            VersionException, ConstraintViolationException, LockException,
+            RepositoryException {
+        // TODO Auto-generated method stub
+
+    }
+
+    public void removeLockToken(String lt) {
+        // TODO Auto-generated method stub
+
+    }
+
+    public void save() throws AccessDeniedException, ItemExistsException,
+            ConstraintViolationException, InvalidItemStateException,
+            VersionException, LockException, NoSuchNodeTypeException,
+            RepositoryException {
+        // TODO Auto-generated method stub
+
+    }
+
+    public void setNamespacePrefix(String prefix, String uri)
+            throws NamespaceException, RepositoryException {
+        // TODO Auto-generated method stub
+
+    }
+
+}

Added: jackrabbit/sandbox/jackrabbit-ngp/src/main/java/org/apache/jackrabbit/ngp/node/BoundNode.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-ngp/src/main/java/org/apache/jackrabbit/ngp/node/BoundNode.java?rev=611778&view=auto
==============================================================================
--- jackrabbit/sandbox/jackrabbit-ngp/src/main/java/org/apache/jackrabbit/ngp/node/BoundNode.java (added)
+++ jackrabbit/sandbox/jackrabbit-ngp/src/main/java/org/apache/jackrabbit/ngp/node/BoundNode.java Mon Jan 14 03:50:01 2008
@@ -0,0 +1,103 @@
+/**
+ * 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.ngp.node;
+
+import java.io.DataInputStream;
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.jcr.RepositoryException;
+
+import org.apache.commons.collections.map.ReferenceMap;
+import org.apache.jackrabbit.ngp.store.Record;
+import org.apache.jackrabbit.ngp.store.Store;
+
+public class BoundNode implements NodeState {
+
+    private final Store store;
+
+    private final Record record;
+
+    private final ReferenceMap children = new ReferenceMap();
+
+    public BoundNode(Store store, Record record) {
+        this.store = store;
+        this.record = record;
+    }
+
+    public void refresh(Record record) throws RepositoryException {
+        if (!record.equals(this.record)) {
+            accept(new EntryVisitor() {
+                public void visit(String name, Record record)
+                        throws RepositoryException {
+                    StateSwitch child = (StateSwitch) children.get(name);
+                    if (child != null) {
+                        child.refresh(record);
+                    }
+                }
+            });
+        }
+    }
+
+    public Map<String, NodeState> getNodes() throws RepositoryException {
+        final Map<String, NodeState> nodes = new HashMap<String, NodeState>();
+        accept(new EntryVisitor() {
+            public void visit(String name, Record record) {
+                StateSwitch child = (StateSwitch) children.get(name);
+                if (child == null) {
+                    child = new StateSwitch();
+                    child.setState(new BoundNode(store, record));
+                    children.put(name, child);
+                }
+                nodes.put(name, child);
+            }
+        });
+        return nodes;
+    }
+
+    private interface EntryVisitor {
+
+        void visit(String name, Record record) throws RepositoryException;
+
+    }
+
+    public void accept(EntryVisitor visitor) throws RepositoryException {
+        if (record.getLength() > 0) {
+            try {
+                InputStream stream = record.getInputStream();
+                try {
+                    DataInputStream input = new DataInputStream(stream);
+                    byte[] id = new byte[20];
+                    while (true) {
+                        String name = input.readUTF();
+                        input.readFully(id);
+                        visitor.visit(name, store.getRecord(id));
+                    }
+                } catch (EOFException e) {
+                    // end of input, exit loop
+                } finally {
+                    stream.close();
+                }
+            } catch (IOException e) {
+                throw new RepositoryException("Unable to read node", e);
+            }
+        }
+    }
+}

Added: jackrabbit/sandbox/jackrabbit-ngp/src/main/java/org/apache/jackrabbit/ngp/node/ClosedNode.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-ngp/src/main/java/org/apache/jackrabbit/ngp/node/ClosedNode.java?rev=611778&view=auto
==============================================================================
--- jackrabbit/sandbox/jackrabbit-ngp/src/main/java/org/apache/jackrabbit/ngp/node/ClosedNode.java (added)
+++ jackrabbit/sandbox/jackrabbit-ngp/src/main/java/org/apache/jackrabbit/ngp/node/ClosedNode.java Mon Jan 14 03:50:01 2008
@@ -0,0 +1,36 @@
+/**
+ * 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.ngp.node;
+
+import java.util.Map;
+
+import javax.jcr.RepositoryException;
+
+import org.apache.jackrabbit.ngp.store.Record;
+
+public class ClosedNode implements NodeState {
+
+    private final String message = "This node is closed";
+
+    public void refresh(Record record) {
+    }
+
+    public Map<String, NodeState> getNodes() throws RepositoryException {
+        throw new RepositoryException(message);
+    }
+
+}

Added: jackrabbit/sandbox/jackrabbit-ngp/src/main/java/org/apache/jackrabbit/ngp/node/NodeState.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-ngp/src/main/java/org/apache/jackrabbit/ngp/node/NodeState.java?rev=611778&view=auto
==============================================================================
--- jackrabbit/sandbox/jackrabbit-ngp/src/main/java/org/apache/jackrabbit/ngp/node/NodeState.java (added)
+++ jackrabbit/sandbox/jackrabbit-ngp/src/main/java/org/apache/jackrabbit/ngp/node/NodeState.java Mon Jan 14 03:50:01 2008
@@ -0,0 +1,31 @@
+/**
+ * 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.ngp.node;
+
+import java.util.Map;
+
+import javax.jcr.RepositoryException;
+
+import org.apache.jackrabbit.ngp.store.Record;
+
+public interface NodeState {
+
+    void refresh(Record record) throws RepositoryException;
+
+    Map<String, NodeState> getNodes() throws RepositoryException;
+
+}

Added: jackrabbit/sandbox/jackrabbit-ngp/src/main/java/org/apache/jackrabbit/ngp/node/StateSwitch.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-ngp/src/main/java/org/apache/jackrabbit/ngp/node/StateSwitch.java?rev=611778&view=auto
==============================================================================
--- jackrabbit/sandbox/jackrabbit-ngp/src/main/java/org/apache/jackrabbit/ngp/node/StateSwitch.java (added)
+++ jackrabbit/sandbox/jackrabbit-ngp/src/main/java/org/apache/jackrabbit/ngp/node/StateSwitch.java Mon Jan 14 03:50:01 2008
@@ -0,0 +1,41 @@
+/**
+ * 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.ngp.node;
+
+import java.util.Map;
+
+import javax.jcr.RepositoryException;
+
+import org.apache.jackrabbit.ngp.store.Record;
+
+public class StateSwitch implements NodeState {
+
+    private NodeState state = new ClosedNode();
+
+    public void setState(NodeState state) {
+        this.state = state;
+    }
+
+    public void refresh(Record record) throws RepositoryException {
+        state.refresh(record);
+    }
+
+    public Map<String, NodeState> getNodes() throws RepositoryException {
+        return state.getNodes();
+    }
+
+}

Added: jackrabbit/sandbox/jackrabbit-ngp/src/main/java/org/apache/jackrabbit/ngp/session/BoundSession.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-ngp/src/main/java/org/apache/jackrabbit/ngp/session/BoundSession.java?rev=611778&view=auto
==============================================================================
--- jackrabbit/sandbox/jackrabbit-ngp/src/main/java/org/apache/jackrabbit/ngp/session/BoundSession.java (added)
+++ jackrabbit/sandbox/jackrabbit-ngp/src/main/java/org/apache/jackrabbit/ngp/session/BoundSession.java Mon Jan 14 03:50:01 2008
@@ -0,0 +1,47 @@
+/**
+ * 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.ngp.session;
+
+import java.io.IOException;
+
+import javax.jcr.RepositoryException;
+
+import org.apache.jackrabbit.ngp.node.NodeState;
+import org.apache.jackrabbit.ngp.store.Store;
+
+public class BoundSession extends UnboundSession {
+
+    private final NodeState root;
+
+    public BoundSession(Store store, StateSwitch change, NodeState root) {
+        super(store, change);
+        this.root = root;
+    }
+
+    public void refresh(boolean keepChanges) throws RepositoryException {
+        try {
+            root.refresh(store.getDefaultRecord());
+        } catch (IOException e) {
+            throw new RepositoryException("Failed to refresh session", e);
+        }
+    }
+
+    public NodeState getRootNode() {
+        return root;
+    }
+
+}

Added: jackrabbit/sandbox/jackrabbit-ngp/src/main/java/org/apache/jackrabbit/ngp/session/ClosedSession.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-ngp/src/main/java/org/apache/jackrabbit/ngp/session/ClosedSession.java?rev=611778&view=auto
==============================================================================
--- jackrabbit/sandbox/jackrabbit-ngp/src/main/java/org/apache/jackrabbit/ngp/session/ClosedSession.java (added)
+++ jackrabbit/sandbox/jackrabbit-ngp/src/main/java/org/apache/jackrabbit/ngp/session/ClosedSession.java Mon Jan 14 03:50:01 2008
@@ -0,0 +1,39 @@
+/**
+ * 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.ngp.session;
+
+import javax.jcr.RepositoryException;
+
+import org.apache.jackrabbit.ngp.node.NodeState;
+
+public class ClosedSession implements SessionState {
+
+    private final String message = "This session is closed";
+
+    public boolean isLive() {
+        return false;
+    }
+
+    public void refresh(boolean keepChanges) throws RepositoryException {
+        throw new RepositoryException(message);
+    }
+
+    public NodeState getRootNode() throws RepositoryException {
+        throw new RepositoryException(message);
+    }
+
+}

Added: jackrabbit/sandbox/jackrabbit-ngp/src/main/java/org/apache/jackrabbit/ngp/session/SessionState.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-ngp/src/main/java/org/apache/jackrabbit/ngp/session/SessionState.java?rev=611778&view=auto
==============================================================================
--- jackrabbit/sandbox/jackrabbit-ngp/src/main/java/org/apache/jackrabbit/ngp/session/SessionState.java (added)
+++ jackrabbit/sandbox/jackrabbit-ngp/src/main/java/org/apache/jackrabbit/ngp/session/SessionState.java Mon Jan 14 03:50:01 2008
@@ -0,0 +1,31 @@
+/**
+ * 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.ngp.session;
+
+import javax.jcr.RepositoryException;
+
+import org.apache.jackrabbit.ngp.node.NodeState;
+
+public interface SessionState {
+
+    boolean isLive();
+
+    void refresh(boolean keepChanges) throws RepositoryException;
+
+    NodeState getRootNode() throws RepositoryException;
+
+}

Added: jackrabbit/sandbox/jackrabbit-ngp/src/main/java/org/apache/jackrabbit/ngp/session/StateSwitch.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-ngp/src/main/java/org/apache/jackrabbit/ngp/session/StateSwitch.java?rev=611778&view=auto
==============================================================================
--- jackrabbit/sandbox/jackrabbit-ngp/src/main/java/org/apache/jackrabbit/ngp/session/StateSwitch.java (added)
+++ jackrabbit/sandbox/jackrabbit-ngp/src/main/java/org/apache/jackrabbit/ngp/session/StateSwitch.java Mon Jan 14 03:50:01 2008
@@ -0,0 +1,43 @@
+/**
+ * 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.ngp.session;
+
+import javax.jcr.RepositoryException;
+
+import org.apache.jackrabbit.ngp.node.NodeState;
+
+public class StateSwitch implements SessionState {
+
+    private SessionState state = new ClosedSession();
+
+    public void setState(SessionState state) {
+        this.state = state;
+    }
+
+    public boolean isLive() {
+        return state.isLive();
+    }
+
+    public void refresh(boolean keepChanges) throws RepositoryException {
+        state.refresh(keepChanges);
+    }
+
+    public NodeState getRootNode() throws RepositoryException {
+        return state.getRootNode();
+    }
+
+}
\ No newline at end of file

Added: jackrabbit/sandbox/jackrabbit-ngp/src/main/java/org/apache/jackrabbit/ngp/session/UnboundSession.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-ngp/src/main/java/org/apache/jackrabbit/ngp/session/UnboundSession.java?rev=611778&view=auto
==============================================================================
--- jackrabbit/sandbox/jackrabbit-ngp/src/main/java/org/apache/jackrabbit/ngp/session/UnboundSession.java (added)
+++ jackrabbit/sandbox/jackrabbit-ngp/src/main/java/org/apache/jackrabbit/ngp/session/UnboundSession.java Mon Jan 14 03:50:01 2008
@@ -0,0 +1,58 @@
+/**
+ * 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.ngp.session;
+
+import java.io.IOException;
+
+import javax.jcr.RepositoryException;
+
+import org.apache.jackrabbit.ngp.node.BoundNode;
+import org.apache.jackrabbit.ngp.node.NodeState;
+import org.apache.jackrabbit.ngp.store.Store;
+
+public class UnboundSession implements SessionState {
+
+    protected final Store store;
+
+    protected final StateSwitch state;
+
+    public UnboundSession(Store store, StateSwitch state) {
+        this.store = store;
+        this.state = state;
+    }
+
+    public boolean isLive() {
+        return true;
+    }
+
+    public void refresh(boolean keepChanges) throws RepositoryException {
+        if (!keepChanges) {
+            state.setState(new UnboundSession(store, state));
+        }
+    }
+
+    public NodeState getRootNode() throws RepositoryException {
+        try {
+            NodeState root = new BoundNode(store, store.getDefaultRecord());
+            state.setState(new BoundSession(store, state, root));
+            return root;
+        } catch (IOException e) {
+            throw new RepositoryException("Unable to access the root node", e);
+        }
+    }
+
+}

Added: jackrabbit/sandbox/jackrabbit-ngp/src/main/java/org/apache/jackrabbit/ngp/store/Record.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-ngp/src/main/java/org/apache/jackrabbit/ngp/store/Record.java?rev=611778&view=auto
==============================================================================
--- jackrabbit/sandbox/jackrabbit-ngp/src/main/java/org/apache/jackrabbit/ngp/store/Record.java (added)
+++ jackrabbit/sandbox/jackrabbit-ngp/src/main/java/org/apache/jackrabbit/ngp/store/Record.java Mon Jan 14 03:50:01 2008
@@ -0,0 +1,53 @@
+/**
+ * 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.ngp.store;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+
+import org.apache.commons.codec.binary.Hex;
+
+public class Record {
+
+    private final byte[] digest;
+
+    private final File file;
+
+    Record(File directory, byte[] digest) {
+        this.digest = digest;
+        this.file = new File(directory, new String(Hex.encodeHex(digest)));
+    }
+
+    byte[] getDigest() {
+        return digest;
+    }
+
+    File getFile() {
+        return file;
+    }
+
+    public long getLength() {
+        return file.length();
+    }
+
+    public InputStream getInputStream() throws FileNotFoundException {
+        return new FileInputStream(file);
+    }
+
+}

Added: jackrabbit/sandbox/jackrabbit-ngp/src/main/java/org/apache/jackrabbit/ngp/store/Store.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-ngp/src/main/java/org/apache/jackrabbit/ngp/store/Store.java?rev=611778&view=auto
==============================================================================
--- jackrabbit/sandbox/jackrabbit-ngp/src/main/java/org/apache/jackrabbit/ngp/store/Store.java (added)
+++ jackrabbit/sandbox/jackrabbit-ngp/src/main/java/org/apache/jackrabbit/ngp/store/Store.java Mon Jan 14 03:50:01 2008
@@ -0,0 +1,150 @@
+/**
+ * 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.ngp.store;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.RandomAccessFile;
+import java.nio.channels.FileLock;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Arrays;
+
+public class Store {
+
+    private final File directory;
+
+    private final File log;
+
+    public Store(File directory) throws IOException {
+        this.directory = directory;
+        this.log = new File(directory, "store.log");
+
+        directory.mkdirs();
+        log.createNewFile();
+
+        Record empty = addRecord(new ByteArrayInputStream(new byte[0]));
+        setDefaultRecord(empty, null);
+    }
+
+    private MessageDigest newMessageDigest() throws IOException {
+        try {
+            return MessageDigest.getInstance("SHA-1");
+        } catch (NoSuchAlgorithmException e) {
+            throw new IOException("SHA-1 not supported");
+        }
+    }
+
+    public Record getRecord(byte[] id) throws IOException {
+        Record record = new Record(directory, id);
+        if (!record.getFile().exists()) {
+            throw new IOException("Record not found: " + record);
+        }
+        return record;
+    }
+
+    public Record addRecord(InputStream stream) throws IOException {
+        MessageDigest digest = newMessageDigest();
+        File file = File.createTempFile("store", "temporary", directory);
+        try {
+            OutputStream output = new FileOutputStream(file);
+            try {
+                byte[] buffer = new byte[16 * 1024];
+                int n = stream.read(buffer);
+                while (n != -1) {
+                    output.write(buffer, 0, n);
+                    n = stream.read(buffer);
+                }
+            } finally {
+                output.close();
+            }
+
+            Record record = new Record(directory, digest.digest());
+            File target = record.getFile();
+            if (!target.exists()) {
+                if (!file.renameTo(target)) {
+                    throw new IOException("Record creation failed: " + record);
+                }
+            }
+            return record;
+        } finally {
+            file.delete();
+        }
+    }
+
+    public Record getDefaultRecord() throws IOException {
+        RandomAccessFile file = new RandomAccessFile(log, "r");
+        try {
+            long position = (file.length() / 20 - 1) * 20;
+            if (position < 0) {
+                throw new IOException("No default record");
+            }
+            FileLock lock = file.getChannel().lock(position, 20, true);
+            try {
+                byte[] buffer = new byte[20];
+                file.seek(position);
+                file.readFully(buffer);
+                return getRecord(buffer);
+            } finally {
+                lock.release();
+            }
+        } finally {
+            file.close();
+        }
+    }
+
+    public boolean setDefaultRecord(Record record, Record previous)
+            throws IOException {
+        RandomAccessFile file = new RandomAccessFile(log, "rw");
+        try {
+            long position = (file.length() / 20 - 1) * 20;
+            if ((position < 0) != (previous == null)) {
+                return false;
+            }
+
+            FileLock lock = file.getChannel().lock(position + 20, 20, false);
+            try {
+                if (previous != null) {
+                    byte[] buffer = new byte[20];
+                    file.seek(position);
+                    file.readFully(buffer);
+                    if (!Arrays.equals(previous.getDigest(), buffer)) {
+                        return false;
+                    }
+                }
+
+                if (file.length() >= position + 40) {
+                    return false;
+                }
+
+                file.seek(position + 20);
+                file.write(record.getDigest());
+                file.getChannel().force(false);
+                return file.length() >= position + 40;
+            } finally {
+                lock.release();
+            }
+        } finally {
+            file.close();
+        }
+    }
+
+}

Added: jackrabbit/sandbox/jackrabbit-ngp/src/test/java/org/apache/jackrabbit/ngp/AbstractNodeTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-ngp/src/test/java/org/apache/jackrabbit/ngp/AbstractNodeTest.java?rev=611778&view=auto
==============================================================================
--- jackrabbit/sandbox/jackrabbit-ngp/src/test/java/org/apache/jackrabbit/ngp/AbstractNodeTest.java (added)
+++ jackrabbit/sandbox/jackrabbit-ngp/src/test/java/org/apache/jackrabbit/ngp/AbstractNodeTest.java Mon Jan 14 03:50:01 2008
@@ -0,0 +1,36 @@
+/**
+ * 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.ngp;
+
+import javax.jcr.Node;
+
+import org.junit.Before;
+
+public class AbstractNodeTest extends AbstractSessionTest {
+
+    protected Node root;
+
+    protected Node node;
+
+    @Before
+    public void setUp() throws Exception {
+        super.setUp();
+        root = session.getRootNode();
+        node = root.getNode("test");
+    }
+
+}

Added: jackrabbit/sandbox/jackrabbit-ngp/src/test/java/org/apache/jackrabbit/ngp/AbstractRepositoryTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-ngp/src/test/java/org/apache/jackrabbit/ngp/AbstractRepositoryTest.java?rev=611778&view=auto
==============================================================================
--- jackrabbit/sandbox/jackrabbit-ngp/src/test/java/org/apache/jackrabbit/ngp/AbstractRepositoryTest.java (added)
+++ jackrabbit/sandbox/jackrabbit-ngp/src/test/java/org/apache/jackrabbit/ngp/AbstractRepositoryTest.java Mon Jan 14 03:50:01 2008
@@ -0,0 +1,56 @@
+/**
+ * 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.ngp;
+
+import java.io.File;
+
+import javax.jcr.Repository;
+
+import org.junit.After;
+import org.junit.Before;
+
+public class AbstractRepositoryTest {
+
+    private File directory;
+
+    protected Repository repository;
+
+    @Before
+    public void setUp() throws Exception {
+        directory = File.createTempFile("jackrabbit-ngp", "test");
+        directory.delete();
+        directory.mkdir();
+
+        repository = new RepositoryImpl(directory);
+    }
+
+    @After
+    public void tearDown() {
+        delete(directory);
+    }
+
+    private void delete(File file) {
+        File[] children = file.listFiles();
+        if (children != null) {
+            for (File child : children) {
+                delete(child);
+            }
+        }
+        file.delete();
+    }
+
+}

Added: jackrabbit/sandbox/jackrabbit-ngp/src/test/java/org/apache/jackrabbit/ngp/AbstractSessionTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-ngp/src/test/java/org/apache/jackrabbit/ngp/AbstractSessionTest.java?rev=611778&view=auto
==============================================================================
--- jackrabbit/sandbox/jackrabbit-ngp/src/test/java/org/apache/jackrabbit/ngp/AbstractSessionTest.java (added)
+++ jackrabbit/sandbox/jackrabbit-ngp/src/test/java/org/apache/jackrabbit/ngp/AbstractSessionTest.java Mon Jan 14 03:50:01 2008
@@ -0,0 +1,42 @@
+/**
+ * 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.ngp;
+
+import javax.jcr.Session;
+
+import org.junit.After;
+import org.junit.Before;
+
+public class AbstractSessionTest extends AbstractRepositoryTest {
+
+    protected Session session;
+
+    @Before
+    public void setUp() throws Exception {
+        super.setUp();
+        session = repository.login();
+    }
+
+    @After
+    public void tearDown() {
+        if (session != null) {
+            session.logout();
+        }
+        super.tearDown();
+    }
+
+}

Added: jackrabbit/sandbox/jackrabbit-ngp/src/test/java/org/apache/jackrabbit/ngp/NodeTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-ngp/src/test/java/org/apache/jackrabbit/ngp/NodeTest.java?rev=611778&view=auto
==============================================================================
--- jackrabbit/sandbox/jackrabbit-ngp/src/test/java/org/apache/jackrabbit/ngp/NodeTest.java (added)
+++ jackrabbit/sandbox/jackrabbit-ngp/src/test/java/org/apache/jackrabbit/ngp/NodeTest.java Mon Jan 14 03:50:01 2008
@@ -0,0 +1,72 @@
+/**
+ * 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.ngp;
+
+import static org.junit.Assert.*;
+import static org.junit.matchers.IsCollectionContaining.*;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+import javax.jcr.Credentials;
+import javax.jcr.ItemNotFoundException;
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.jcr.Workspace;
+
+import org.junit.Test;
+
+public class NodeTest extends AbstractNodeTest {
+
+    @Test
+    public void testGetRepository() {
+        assertEquals(repository, session.getRepository());
+    }
+
+    @Test
+    public void testGetAttributeNames() {
+        Collection<String> names = Arrays.asList(session.getAttributeNames());
+        assertThat(names, hasItem(Credentials.class.getName()));
+        assertThat(names, hasItem(Workspace.class.getName()));
+    }
+
+    @Test
+    public void testGetAttribute() {
+        Object credentials = session.getAttribute(Credentials.class.getName());
+        assertTrue(credentials instanceof Credentials);
+        Object workspaceName = session.getAttribute(Workspace.class.getName());
+        assertTrue(workspaceName instanceof String);
+    }
+
+    @Test
+    public void testGetRootNode() throws RepositoryException {
+        Node root = session.getRootNode();
+        assertNotNull(root);
+        assertEquals(session, root.getSession());
+        assertEquals("", root.getName());
+        assertEquals(1, root.getIndex());
+        assertEquals("/", root.getPath());
+        assertEquals(0, root.getDepth());
+
+        try {
+            root.getParent();
+            fail("Root node has a parent");
+        } catch (ItemNotFoundException expected) {
+        }
+    }
+
+}

Added: jackrabbit/sandbox/jackrabbit-ngp/src/test/java/org/apache/jackrabbit/ngp/RepositoryTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-ngp/src/test/java/org/apache/jackrabbit/ngp/RepositoryTest.java?rev=611778&view=auto
==============================================================================
--- jackrabbit/sandbox/jackrabbit-ngp/src/test/java/org/apache/jackrabbit/ngp/RepositoryTest.java (added)
+++ jackrabbit/sandbox/jackrabbit-ngp/src/test/java/org/apache/jackrabbit/ngp/RepositoryTest.java Mon Jan 14 03:50:01 2008
@@ -0,0 +1,88 @@
+/**
+ * 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.ngp;
+
+import static javax.jcr.Repository.*;
+import static org.junit.Assert.*;
+import static org.junit.matchers.IsCollectionContaining.*;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+
+import org.junit.Test;
+
+public class RepositoryTest extends AbstractRepositoryTest {
+
+    @Test
+    public void testGetDescriptorKeys() {
+        Collection<String> keys = Arrays.asList(repository.getDescriptorKeys());
+        assertThat(keys, hasItem(SPEC_NAME_DESC));
+        assertThat(keys, hasItem(SPEC_VERSION_DESC));
+
+        assertThat(keys, hasItem(REP_NAME_DESC));
+        assertThat(keys, hasItem(REP_VERSION_DESC));
+
+        assertThat(keys, hasItem(REP_VENDOR_DESC));
+        assertThat(keys, hasItem(REP_VENDOR_URL_DESC));
+
+        // assertThat(keys, hasItem(LEVEL_1_SUPPORTED));
+        // assertThat(keys, hasItem(LEVEL_2_SUPPORTED));
+        // assertThat(keys, hasItem(OPTION_LOCKING_SUPPORTED));
+        // assertThat(keys, hasItem(OPTION_OBSERVATION_SUPPORTED));
+        // assertThat(keys, hasItem(OPTION_QUERY_SQL_SUPPORTED));
+        // assertThat(keys, hasItem(OPTION_TRANSACTIONS_SUPPORTED));
+        // assertThat(keys, hasItem(OPTION_VERSIONING_SUPPORTED));
+        // assertThat(keys, hasItem(QUERY_XPATH_DOC_ORDER));
+        // assertThat(keys, hasItem(QUERY_XPATH_POS_INDEX));
+    }
+
+    @Test
+    public void testGetDescriptor() {
+        assertEquals(
+                "Content Repository API for Java(TM) Technology Specification",
+                repository.getDescriptor(SPEC_NAME_DESC));
+        assertEquals("1.0", repository.getDescriptor(SPEC_VERSION_DESC));
+
+        assertEquals(
+                "Apache Jackrabbit NGP",
+                repository.getDescriptor(REP_NAME_DESC));
+        assertEquals("SNAPSHOT", repository.getDescriptor(REP_VERSION_DESC));
+
+        assertEquals(
+                "Apache Software Foundation",
+                repository.getDescriptor(REP_VENDOR_DESC));
+        assertEquals(
+                "http://jackrabbit.apache.org/",
+                repository.getDescriptor(REP_VENDOR_URL_DESC));
+    }
+
+    @Test
+    public void testLogin() {
+        try {
+            Session session = repository.login();
+            assertTrue(session.isLive());
+            session.logout();
+            assertFalse(session.isLive());
+        } catch (RepositoryException e) {
+            fail("Default login failed");
+        }
+    }
+
+}

Added: jackrabbit/sandbox/jackrabbit-ngp/src/test/java/org/apache/jackrabbit/ngp/SessionTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-ngp/src/test/java/org/apache/jackrabbit/ngp/SessionTest.java?rev=611778&view=auto
==============================================================================
--- jackrabbit/sandbox/jackrabbit-ngp/src/test/java/org/apache/jackrabbit/ngp/SessionTest.java (added)
+++ jackrabbit/sandbox/jackrabbit-ngp/src/test/java/org/apache/jackrabbit/ngp/SessionTest.java Mon Jan 14 03:50:01 2008
@@ -0,0 +1,72 @@
+/**
+ * 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.ngp;
+
+import static org.junit.Assert.*;
+import static org.junit.matchers.IsCollectionContaining.*;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+import javax.jcr.Credentials;
+import javax.jcr.ItemNotFoundException;
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.jcr.Workspace;
+
+import org.junit.Test;
+
+public class SessionTest extends AbstractSessionTest {
+
+    @Test
+    public void testGetRepository() {
+        assertEquals(repository, session.getRepository());
+    }
+
+    @Test
+    public void testGetAttributeNames() {
+        Collection<String> names = Arrays.asList(session.getAttributeNames());
+        assertThat(names, hasItem(Credentials.class.getName()));
+        assertThat(names, hasItem(Workspace.class.getName()));
+    }
+
+    @Test
+    public void testGetAttribute() {
+        Object credentials = session.getAttribute(Credentials.class.getName());
+        assertTrue(credentials instanceof Credentials);
+        Object workspaceName = session.getAttribute(Workspace.class.getName());
+        assertTrue(workspaceName instanceof String);
+    }
+
+    @Test
+    public void testGetRootNode() throws RepositoryException {
+        Node root = session.getRootNode();
+        assertNotNull(root);
+        assertEquals(session, root.getSession());
+        assertEquals("", root.getName());
+        assertEquals(1, root.getIndex());
+        assertEquals("/", root.getPath());
+        assertEquals(0, root.getDepth());
+
+        try {
+            root.getParent();
+            fail("Root node has a parent");
+        } catch (ItemNotFoundException expected) {
+        }
+    }
+
+}