Index: oak-core/src/test/java/org/apache/jackrabbit/oak/core/ImmutableTreeTest.java
===================================================================
--- oak-core/src/test/java/org/apache/jackrabbit/oak/core/ImmutableTreeTest.java	(revision 1651659)
+++ oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/tree/impl/ImmutableTreeTest.java	(revision )
@@ -16,30 +16,38 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.jackrabbit.oak.core;
+package org.apache.jackrabbit.oak.plugins.tree.impl;
 
+import java.util.List;
+
+import com.google.common.collect.Lists;
+import org.apache.jackrabbit.JcrConstants;
 import org.apache.jackrabbit.oak.NodeStoreFixture;
 import org.apache.jackrabbit.oak.OakBaseTest;
 import org.apache.jackrabbit.oak.api.CommitFailedException;
 import org.apache.jackrabbit.oak.api.ContentSession;
+import org.apache.jackrabbit.oak.api.PropertyState;
 import org.apache.jackrabbit.oak.api.Root;
 import org.apache.jackrabbit.oak.api.Tree;
-import org.apache.jackrabbit.oak.plugins.tree.impl.ImmutableTree;
+import org.apache.jackrabbit.oak.spi.commit.CommitInfo;
+import org.apache.jackrabbit.oak.spi.commit.EmptyHook;
+import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 
 import static org.apache.jackrabbit.oak.OakAssert.assertSequence;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
 
 
 public class ImmutableTreeTest extends OakBaseTest {
 
     private Root root;
-    private MutableTree mutableTree;
+    private ImmutableTree immutable;
 
     public ImmutableTreeTest(NodeStoreFixture fixture) {
         super(fixture);
@@ -54,12 +62,21 @@
         Tree tree = root.getTree("/");
         Tree x = tree.addChild("x");
         Tree y = x.addChild("y");
-        Tree z = y.addChild("z");
+        y.addChild("z");
+        Tree orderable = tree.addChild("orderable");
+        orderable.setOrderableChildren(true);
+        orderable.setProperty(JcrConstants.JCR_PRIMARYTYPE, JcrConstants.NT_UNSTRUCTURED);
         root.commit();
 
+        NodeBuilder nb = store.getRoot().builder();
+        nb.child(":hidden");
+        store.merge(nb, EmptyHook.INSTANCE, CommitInfo.EMPTY);
+
         // Acquire a fresh new root to avoid problems from lingering state
         root = session.getLatestRoot();
-        mutableTree = (MutableTree) root.getTree("/");
+        Tree mutableTree = root.getTree("/");
+
+        immutable = new ImmutableTree(((AbstractTree) mutableTree).getNodeState());
     }
 
     @After
@@ -69,7 +86,6 @@
 
     @Test
     public void testGetPath() {
-        ImmutableTree immutable = new ImmutableTree(mutableTree.getNodeState());
         assertEquals("/", immutable.getPath());
 
         immutable = immutable.getChild("x");
@@ -84,75 +100,176 @@
 
     @Test
     public void testGetNodeState() {
-        ImmutableTree tree = new ImmutableTree(mutableTree.getNodeState());
-        assertNotNull(tree.getNodeState());
+        assertNotNull(immutable.getNodeState());
 
-        for (Tree child : tree.getChildren()) {
+        for (Tree child : immutable.getChildren()) {
             assertTrue(child instanceof ImmutableTree);
             assertNotNull(((ImmutableTree) child).getNodeState());
         }
     }
 
     @Test
-    public void testRoot() {
-        ImmutableTree tree = new ImmutableTree(mutableTree.getNodeState());
-        assertTrue(tree.isRoot());
-        try {
-            tree.getParent();
-            fail();
+    public void testRootIsRoot() {
+        assertTrue(immutable.isRoot());
-        }
+    }
-        catch (IllegalStateException expected) { }
-        assertEquals("", tree.getName());
+
+    @Test(expected = IllegalStateException.class)
+    public void testRootGetParent() {
+        immutable.getParent();
     }
 
     @Test
     public void testGetParent() {
-        ImmutableTree tree = new ImmutableTree(mutableTree.getNodeState());
-        try {
-            tree.getParent();
-            fail();
-        }
-        catch (IllegalStateException expected) { }
-
-        ImmutableTree child = tree.getChild("x");
+        ImmutableTree child = immutable.getChild("x");
         assertNotNull(child.getParent());
         assertEquals("/", child.getParent().getPath());
+    }
 
+    @Test(expected = UnsupportedOperationException.class)
+    public void testGetParentDisconnected() {
+        ImmutableTree child = immutable.getChild("x");
         ImmutableTree disconnected = new ImmutableTree(ImmutableTree.ParentProvider.UNSUPPORTED, child.getName(), child.getNodeState());
-        try {
-            disconnected.getParent();
+        disconnected.getParent();
-        } catch (UnsupportedOperationException e) {
-            // success
-        }
+    }
+
+    @Test
+    public void testGetName() {
+        assertEquals("x", immutable.getChild("x").getName());
     }
-    
+
     @Test
+    public void testHiddenGetName() {
+        assertEquals(":hidden", immutable.getChild(":hidden").getName());
+    }
+
+    @Test
+    public void testNonExistingGetName() {
+        assertEquals("nonExisting", immutable.getChild("nonExisting").getName());
+    }
+
+    @Test
+    public void testRootGetName() {
+        assertEquals("", immutable.getName());
+    }
+
+    @Test
+    public void testExists() {
+        ImmutableTree child = immutable.getChild("x");
+        assertTrue(child.exists());
+    }
+
+    @Test
+    public void testHiddenExists() {
+        ImmutableTree hidden = immutable.getChild(":hidden");
+        assertTrue(hidden.exists());
+    }
+
+    @Test
+    public void testNonExisting() {
+        ImmutableTree child = immutable.getChild("nonExisting");
+        assertNotNull(child);
+        assertFalse(child.exists());
+    }
+
+    @Test
+    public void testRootGetStatus() {
+        assertSame(Tree.Status.UNCHANGED, immutable.getStatus());
+    }
+
+    @Test
+    public void testGetStatus() {
+        assertSame(Tree.Status.UNCHANGED, immutable.getChild("x").getStatus());
+    }
+
+    @Test
+    public void testHiddenGetStatus() {
+        assertSame(Tree.Status.UNCHANGED, immutable.getChild(":hidden").getStatus());
+    }
+
+    @Test
+    public void testNonExistingGetStatus() {
+        assertSame(Tree.Status.UNCHANGED, immutable.getChild("nonExisting").getStatus());
+    }
+
+    @Test
+    public void testHasChild() {
+        assertTrue(immutable.hasChild("x"));
+    }
+
+    @Test
+    public void testHasHiddenChild() {
+        assertTrue(immutable.hasChild(":hidden"));
+    }
+
+    @Test
+    public void testGetHiddenNode() {
+        ImmutableTree hidden = immutable.getChild(":hidden");
+        assertNotNull(hidden);
+    }
+
+
+    @Test
+    public void testHasHiddenProperty() {
+        ImmutableTree orderable = immutable.getChild("orderable");
+        assertTrue(orderable.hasProperty(TreeConstants.OAK_CHILD_ORDER));
+    }
+
+    @Test
+    public void testGetHiddenProperty() {
+        ImmutableTree orderable = immutable.getChild("orderable");
+        assertNotNull(orderable.getProperty(TreeConstants.OAK_CHILD_ORDER));
+    }
+
+    @Test
+    public void testGetPropertyStatus() {
+        ImmutableTree orderable = immutable.getChild("orderable");
+        assertSame(Tree.Status.UNCHANGED, orderable.getPropertyStatus(TreeConstants.OAK_CHILD_ORDER));
+    }
+
+    @Test
+    public void testGetProperties() {
+        ImmutableTree orderable = immutable.getChild("orderable");
+        List<String> propNames = Lists.newArrayList(TreeConstants.OAK_CHILD_ORDER, JcrConstants.JCR_PRIMARYTYPE);
+
+        for (PropertyState ps : orderable.getProperties()) {
+            assertTrue(propNames.remove(ps.getName()));
+        }
+        assertEquals(2, orderable.getPropertyCount());
+    }
+
+    @Test
+    public void testGetPropertyCount() {
+        ImmutableTree orderable = immutable.getChild("orderable");
+        assertEquals(2, orderable.getPropertyCount());
+    }
+
+    @Test
     public void orderBefore() throws Exception {
-    	 MutableTree t = (MutableTree) root.getTree("/x/y/z");
+        Tree t = root.getTree("/x/y/z");
-   
-         t.addChild("node1");
-         t.addChild("node2");
-         t.addChild("node3");
-        
-         
-         t.getChild("node1").orderBefore("node2");
-         t.getChild("node3").orderBefore(null);
-         
-         root.commit();
-         
+
+        t.addChild("node1");
+        t.addChild("node2");
+        t.addChild("node3");
+
+
+        t.getChild("node1").orderBefore("node2");
+        t.getChild("node3").orderBefore(null);
+
+        root.commit();
+
-         ImmutableTree tree = new ImmutableTree(t.getNodeState());
+        ImmutableTree tree = new ImmutableTree(((AbstractTree) t).getNodeState());
-         assertSequence(tree.getChildren(), "node1", "node2", "node3");
- 
-         t.getChild("node3").orderBefore("node2");         
-         root.commit();        
-         
+        assertSequence(tree.getChildren(), "node1", "node2", "node3");
+
+        t.getChild("node3").orderBefore("node2");
+        root.commit();
+
-         tree = new ImmutableTree(t.getNodeState());
+        tree = new ImmutableTree(((AbstractTree) t).getNodeState());
-         assertSequence(tree.getChildren(), "node1", "node3", "node2");         
-         
-         t.getChild("node1").orderBefore(null);
-         root.commit();
-         
+        assertSequence(tree.getChildren(), "node1", "node3", "node2");
+
+        t.getChild("node1").orderBefore(null);
+        root.commit();
+
-         tree = new ImmutableTree(t.getNodeState());
+        tree = new ImmutableTree(((AbstractTree) t).getNodeState());
-         assertSequence(tree.getChildren(), "node3", "node2", "node1");
+        assertSequence(tree.getChildren(), "node3", "node2", "node1");
     }
 }
Index: oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/tree/impl/ImmutableTree.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/tree/impl/ImmutableTree.java	(revision 1651659)
+++ oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/tree/impl/ImmutableTree.java	(revision )
@@ -17,11 +17,13 @@
 package org.apache.jackrabbit.oak.plugins.tree.impl;
 
 import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.Iterables.transform;
 
 import javax.annotation.CheckForNull;
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
+import com.google.common.base.Function;
 import com.google.common.base.Objects;
 import org.apache.jackrabbit.oak.api.PropertyState;
 import org.apache.jackrabbit.oak.api.Tree;
@@ -64,6 +66,12 @@
  *     upon hierarchy related methods like {@link #getParent()}, {@link #getPath()}</li>
  * </ul>
  *
+ * <h3>Filtering 'hidden' items</h3>
+ * This {@code Tree} implementation reflects the item hierarchy as exposed by the
+ * underlying {@code NodeState}. In contrast to the mutable implementations it
+ * does not filter out 'hidden' items as identified by
+ * {@code org.apache.jackrabbit.oak.spi.state.NodeStateUtils#isHidden(String)}.
+ *
  * <h3>Equality and hash code</h3>
  * In contrast to {@link org.apache.jackrabbit.oak.core.MutableTree} the {@code ImmutableTree} implements
  * {@link Object#equals(Object)} and {@link Object#hashCode()}: Two {@code ImmutableTree}s
@@ -101,6 +109,7 @@
         this.parentProvider = checkNotNull(parentProvider);
     }
 
+    //-------------------------------------------------------< AbstractTree >---
     @Override
     @Nonnull
     protected ImmutableTree createChild(String name) {
@@ -137,17 +146,27 @@
     }
 
     @Override
-    public boolean hasChild(@Nonnull String name) {
-        return state.hasChildNode(checkNotNull(name));
-    }
-
-    @Override
     @Nonnull
     public Status getStatus() {
         return Status.UNCHANGED;
     }
 
     @Override
+    public boolean exists() {
+        return state.exists();
+    }
+
+    @Override
+    public boolean hasProperty(String name) {
+        return state.hasProperty(name);
+    }
+
+    @Override
+    public PropertyState getProperty(String name) {
+        return state.getProperty(name);
+    }
+
+    @Override
     @CheckForNull
     public Status getPropertyStatus(@Nonnull String name) {
         if (hasProperty(name)) {
@@ -155,6 +174,37 @@
         } else {
             return null;
         }
+    }
+
+    @Override
+    public Iterable<? extends PropertyState> getProperties() {
+        return state.getProperties();
+    }
+
+    @Override
+    public boolean hasChild(String name) {
+        return state.hasChildNode(checkNotNull(name));
+    }
+
+    @Override
+    public long getChildrenCount(long max) {
+        if (max < 0) {
+            max = Long.MAX_VALUE;
+        }
+        return state.getChildNodeCount(max);
+    }
+
+    @Nonnull
+    @Override
+    public Iterable<Tree> getChildren() {
+        Iterable<Tree> children = transform(getChildNames(),
+                new Function<String, Tree>() {
+                    @Override
+                    public Tree apply(String name) {
+                        return createChild(name);
+                    }
+                });
+        return children;
     }
 
     @Override
