SLING-11469 simplify more code (#32)

simplified code and added some testcases
diff --git a/src/main/java/org/apache/sling/jcr/resource/internal/JcrListenerBaseConfig.java b/src/main/java/org/apache/sling/jcr/resource/internal/JcrListenerBaseConfig.java
index 88f7978..0112650 100644
--- a/src/main/java/org/apache/sling/jcr/resource/internal/JcrListenerBaseConfig.java
+++ b/src/main/java/org/apache/sling/jcr/resource/internal/JcrListenerBaseConfig.java
@@ -19,6 +19,8 @@
 package org.apache.sling.jcr.resource.internal;
 
 import java.io.Closeable;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Set;
 
 import javax.jcr.RepositoryException;
@@ -108,37 +110,24 @@
 
     }
     
-    private static void setFilterPaths(@NotNull OakEventFilter filter, @NotNull ObserverConfiguration config) {
+    protected static void setFilterPaths(@NotNull OakEventFilter filter, @NotNull ObserverConfiguration config) {
         final Set<String> paths = config.getPaths().toStringSet();
-        int globCount = 0;
-        int pathCount = 0;
+        // avoid any resizing of these lists
+        List<String> pathList = new ArrayList<>(paths.size());
+        List<String> globList = new ArrayList<>(paths.size());
+
         for (final String p : paths) {
             if (p.startsWith(Path.GLOB_PREFIX)) {
-                globCount++;
+                globList.add(p.substring(Path.GLOB_PREFIX.length()));
             } else {
-                pathCount++;
+                pathList.add(p);
             }
         }
-        final String[] pathArray = pathCount > 0 ? new String[pathCount] : null;
-        final String[] globArray = globCount > 0 ? new String[globCount] : null;
-        pathCount = 0;
-        globCount = 0;
-
-        // create arrays and remove global prefix
-        for (final String p : paths) {
-            if (p.startsWith(Path.GLOB_PREFIX) && globArray != null) {
-                globArray[globCount] = p.substring(Path.GLOB_PREFIX.length());
-                globCount++;
-            } else if (pathArray != null) {
-                pathArray[pathCount] = p;
-                pathCount++;
-            }
+        if (!globList.isEmpty()) {
+            filter.withIncludeGlobPaths(globList.toArray(new String[0]));
         }
-        if (globArray != null) {
-            filter.withIncludeGlobPaths(globArray);
-        }
-        if (pathArray != null) {
-            filter.setAdditionalPaths(pathArray);
+        if (!pathList.isEmpty()) {
+            filter.setAdditionalPaths(pathList.toArray(new String[0]));
         }
     }
 
diff --git a/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrResourceProvider.java b/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrResourceProvider.java
index 2fbe40b..b1a3d80 100644
--- a/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrResourceProvider.java
+++ b/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrResourceProvider.java
@@ -411,17 +411,14 @@
 
     @Override
     @NotNull
-    public Resource create(final @NotNull ResolveContext<JcrProviderState> ctx, final String path, final Map<String, Object> properties) throws PersistenceException {
-        // check for node type
-        final Object nodeObj = (properties != null ? properties.get(JcrConstants.JCR_PRIMARYTYPE) : null);
-        // check for sling:resourcetype
-        final String nodeType = getType(nodeObj, properties, ctx);
-        
+    public Resource create(final @NotNull ResolveContext<JcrProviderState> ctx, @Nullable final String path,
+            @Nullable final Map<String, Object> properties) throws PersistenceException {
+
         if (path == null) {
-            throw new PersistenceException("Unable to create node at " + path, null, path, null);
+            throw new PersistenceException("Unable to create node with [path=null]");
         }
-        Node node;
         try {
+            Node node;
             final int lastPos = path.lastIndexOf('/');
             final Node parent;
             if (lastPos == 0) {
@@ -430,6 +427,8 @@
                 parent = (Node) getSession(ctx).getItem(path.substring(0, lastPos));
             }
             final String name = path.substring(lastPos + 1);
+            // extract the nodetype
+            final String nodeType = getNodeType(properties, ctx);
             if (nodeType != null) {
                 node = parent.addNode(name, nodeType);
             } else {
@@ -446,29 +445,35 @@
         }
     }
     
-    private static @Nullable String getType(@Nullable Object nodeObj, @Nullable Map<String, Object> properties, @NotNull ResolveContext<JcrProviderState> ctx) {
-        if (nodeObj != null) {
-            return nodeObj.toString();
+    protected static @Nullable String getNodeType(@Nullable Map<String, Object> properties,
+            @NotNull ResolveContext<JcrProviderState> ctx) {
+        if (properties == null) {
+            return null;
         }
 
-        final Object rtObj = (properties != null ? properties.get(JcrResourceConstants.SLING_RESOURCE_TYPE_PROPERTY) : null);
-        boolean isNodeType = false;
-        if (rtObj != null) {
-            final String resourceType = rtObj.toString();
-            if (resourceType.indexOf(':') != -1 && resourceType.indexOf('/') == -1) {
+        final Object primaryTypeObj = properties.get(JcrConstants.JCR_PRIMARYTYPE);
+        if (primaryTypeObj != null) {
+            return primaryTypeObj.toString();
+        }
+
+        final Object resourceTypeObject = properties.get(JcrResourceConstants.SLING_RESOURCE_TYPE_PROPERTY);
+        if (resourceTypeObject != null) {
+            String resourceType = resourceTypeObject.toString();
+            if (looksLikeANodeType(resourceType)) {
                 try {
+                    // validate if it's really a nodetype
                     getSession(ctx).getWorkspace().getNodeTypeManager().getNodeType(resourceType);
-                    isNodeType = true;
+                    return resourceType;
                 } catch (final RepositoryException ignore) {
                     // we expect this, if this isn't a valid node type, therefore ignoring
                 }
             }
         }
-        if (isNodeType) {
-            return rtObj.toString();
-        } else {
-            return null;
-        }
+        return null;
+    }
+    
+    private static boolean looksLikeANodeType(final String resourceType) {
+        return resourceType.indexOf(':') != -1 && resourceType.indexOf('/') == -1;
     }
 
     private static void populateProperties(@NotNull Node node, @NotNull Map<String, Object> properties, @NotNull ResolveContext<JcrProviderState> ctx, @NotNull String path) throws PersistenceException {
diff --git a/src/test/java/org/apache/sling/jcr/resource/internal/JcrListenerBaseConfigTest.java b/src/test/java/org/apache/sling/jcr/resource/internal/JcrListenerBaseConfigTest.java
new file mode 100644
index 0000000..46ff2c2
--- /dev/null
+++ b/src/test/java/org/apache/sling/jcr/resource/internal/JcrListenerBaseConfigTest.java
@@ -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.sling.jcr.resource.internal;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import org.apache.jackrabbit.oak.jcr.observation.filter.OakEventFilter;
+import org.apache.sling.api.resource.path.Path;
+import org.apache.sling.api.resource.path.PathSet;
+import org.apache.sling.spi.resource.provider.ObserverConfiguration;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+
+
+public class JcrListenerBaseConfigTest {
+
+    @Test
+    public void setPathFilter() {
+
+        OakEventFilter filter = mock(OakEventFilter.class);
+        Path globbed = new Path("glob:/globbed/path");
+        Path nonglobbed = new Path("/nonglobbed/path");
+        ObserverConfiguration config = mock(ObserverConfiguration.class);
+        when(config.getPaths()).thenReturn(PathSet.fromPaths(globbed,nonglobbed));
+
+        JcrListenerBaseConfig.setFilterPaths(filter, config);
+
+        ArgumentCaptor<String> pathCaptor = ArgumentCaptor.forClass(String.class);
+        verify(filter).setAdditionalPaths(pathCaptor.capture());
+        assertEquals("/nonglobbed/path", pathCaptor.getValue());
+
+
+        ArgumentCaptor<String> globPathCaptor = ArgumentCaptor.forClass(String.class);
+        verify(filter).withIncludeGlobPaths(globPathCaptor.capture());
+        assertEquals("/globbed/path", globPathCaptor.getValue());
+    }
+}
diff --git a/src/test/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrResourceProviderTest.java b/src/test/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrResourceProviderTest.java
index 6fc48b5..ecac826 100644
--- a/src/test/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrResourceProviderTest.java
+++ b/src/test/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrResourceProviderTest.java
@@ -19,22 +19,30 @@
 package org.apache.sling.jcr.resource.internal.helper.jcr;
 
 import java.security.Principal;
+import java.util.HashMap;
+import java.util.Map;
 import java.util.concurrent.atomic.AtomicReference;
 
 import javax.jcr.Node;
 import javax.jcr.Repository;
 import javax.jcr.RepositoryException;
 import javax.jcr.Session;
-
+import org.apache.jackrabbit.JcrConstants;
 import org.apache.jackrabbit.oak.commons.PathUtils;
 import org.apache.sling.api.resource.PersistenceException;
 import org.apache.sling.api.resource.Resource;
+import org.apache.sling.jcr.resource.api.JcrResourceConstants;
 import org.apache.sling.jcr.resource.internal.HelperData;
 import org.apache.sling.spi.resource.provider.ResolveContext;
 import org.apache.sling.spi.resource.provider.ResourceContext;
 import org.jetbrains.annotations.NotNull;
+import org.junit.After;
 import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 import org.mockito.Mockito;
+import org.mockito.runners.MockitoJUnitRunner;
 import org.osgi.framework.ServiceReference;
 import org.osgi.service.component.ComponentContext;
 
@@ -42,13 +50,15 @@
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
+@RunWith(MockitoJUnitRunner.class)
 public class JcrResourceProviderTest extends SlingRepositoryTestBase {
 
     JcrResourceProvider jcrResourceProvider;
     Session session;
 
     @Override
-    protected void setUp() throws Exception {
+    @Before
+    public void setUp() throws Exception {
         super.setUp();
         // create the session
         session = getSession();
@@ -60,7 +70,8 @@
     }
 
     @Override
-    protected void tearDown() throws Exception {
+    @After
+    public void tearDown() throws Exception {
         try {
             if (session.nodeExists("/parent")) {
                 session.removeItem("/parent");
@@ -82,11 +93,13 @@
         return ctx;
     }
 
+    @Test
     public void testAdaptTo_Principal() {
         ResolveContext ctx = mockResolveContext();
         Assert.assertNotNull(jcrResourceProvider.adaptTo(ctx, Principal.class));
     }
 
+    @Test
     public void testOrderBefore() throws RepositoryException, PersistenceException {
         Node parentNode = session.getRootNode().addNode("parent", NT_UNSTRUCTURED);
         parentNode.addNode("child1", NT_UNSTRUCTURED);
@@ -121,6 +134,7 @@
         Assert.assertTrue(jcrResourceProvider.orderBefore(ctx, parent, "child2", null));
     }
 
+    @Test
     public void testGetParent() throws Exception {
         Node parentNode = session.getRootNode().addNode("parent", NT_UNSTRUCTURED);
         Node child = parentNode.addNode("child", NT_UNSTRUCTURED);
@@ -140,12 +154,70 @@
         assertNull(jcrResourceProvider.getParent(ctx, rootResource));
     }
 
+    @Test
     public void testGetParentDifferentResource() {
         Resource r = mock(Resource.class);
         when(r.getPath()).thenReturn("/test/path");
         Resource parent = jcrResourceProvider.getParent(mockResolveContext(), r);
         assertFalse(parent instanceof JcrNodeResource);
     }
+    
+    @Test
+    public void testGetNodeType() throws RepositoryException {
+        
+        Map<String,Object> properties = new HashMap<>();
+        ResolveContext<JcrProviderState> context = mock(ResolveContext.class);
+        // wire a mock jcrProviderState into the existing session (backed by a real repo)
+        JcrProviderState jcrProviderState = mock(JcrProviderState.class);
+        when(context.getProviderState()).thenReturn(jcrProviderState);
+        when(jcrProviderState.getSession()).thenReturn(session);
+
+        assertEquals(null, JcrResourceProvider.getNodeType(null, null));
+        properties.put("sling:alias","alias");
+        assertEquals(null, JcrResourceProvider.getNodeType(properties, context));
+        properties.put(JcrConstants.JCR_PRIMARYTYPE, "nt:unstructured");
+        assertEquals("nt:unstructured", JcrResourceProvider.getNodeType(properties, context));
+        
+        properties.clear();
+        properties.put(JcrResourceConstants.SLING_RESOURCE_TYPE_PROPERTY, "components/page");
+        assertEquals(null, JcrResourceProvider.getNodeType(properties, context));
+        
+        properties.put(JcrResourceConstants.SLING_RESOURCE_TYPE_PROPERTY, "nt:unstructured");
+        assertEquals("nt:unstructured", JcrResourceProvider.getNodeType(properties, context));
+        
+        properties.put(JcrResourceConstants.SLING_RESOURCE_TYPE_PROPERTY, "undefined:nodetype");
+        assertEquals(null, JcrResourceProvider.getNodeType(properties, context));
+    }
+    
+    @Test(expected=PersistenceException.class)
+    public void createWithNullPath() throws PersistenceException {
+        jcrResourceProvider.create(null, null, null);
+    }
+    
+    @Test
+    public void createResourceBelowRoot() throws PersistenceException, RepositoryException {
+        
+        Map<String,Object> properties = new HashMap<>();
+        properties.put(JcrConstants.JCR_PRIMARYTYPE, "nt:file");
+        
+        ResolveContext<JcrProviderState> context = mock(ResolveContext.class);
+        JcrProviderState jcrProviderState = mock(JcrProviderState.class);
+        when(context.getProviderState()).thenReturn(jcrProviderState);
+        when(jcrProviderState.getSession()).thenReturn(session);
+        
+        JcrNodeResource child = (JcrNodeResource) jcrResourceProvider.create(context, "/childnode", properties);
+        assertNotNull(child);
+        assertEquals("/childnode", child.getPath());
+        assertEquals("nt:file", child.getItem().getPrimaryNodeType().getName());
+        
+        properties.put("jcr:createdBy", "user");
+        JcrNodeResource grandchild = (JcrNodeResource) jcrResourceProvider.create(context, "/childnode/grandchild", properties);
+        assertNotNull(grandchild);
+        assertEquals("/childnode/grandchild", grandchild.getPath());
+        assertEquals("admin",grandchild.getItem().getProperty("jcr:createdBy").getString());
+        
+    }
+    
 
     private static void assertResources(Resource... resources) {
         for (Resource r : resources) {