Author: sseifert Date: Tue Sep 9 12:47:37 2014 New Revision: 1623814 URL: http://svn.apache.org/r1623814 Log: SLING-3889 Make compatible to JCR resource
Added: sling/trunk/testing/resourceresolver-mock/src/main/java/org/apache/sling/testing/resourceresolver/MockPropertyResource.java (with props) sling/trunk/testing/resourceresolver-mock/src/main/java/org/apache/sling/testing/resourceresolver/MockValueMap.java (with props) sling/trunk/testing/resourceresolver-mock/src/test/ sling/trunk/testing/resourceresolver-mock/src/test/java/ sling/trunk/testing/resourceresolver-mock/src/test/java/org/ sling/trunk/testing/resourceresolver-mock/src/test/java/org/apache/ sling/trunk/testing/resourceresolver-mock/src/test/java/org/apache/sling/ sling/trunk/testing/resourceresolver-mock/src/test/java/org/apache/sling/testing/ sling/trunk/testing/resourceresolver-mock/src/test/java/org/apache/sling/testing/resourceresolver/ sling/trunk/testing/resourceresolver-mock/src/test/java/org/apache/sling/testing/resourceresolver/SlingCrudResourceResolverTest.java (with props) Modified: sling/trunk/testing/resourceresolver-mock/pom.xml sling/trunk/testing/resourceresolver-mock/src/main/java/org/apache/sling/testing/resourceresolver/MockResource.java sling/trunk/testing/resourceresolver-mock/src/main/java/org/apache/sling/testing/resourceresolver/MockResourceResolver.java Modified: sling/trunk/testing/resourceresolver-mock/pom.xml URL: http://svn.apache.org/viewvc/sling/trunk/testing/resourceresolver-mock/pom.xml?rev=1623814&r1=1623813&r2=1623814&view=diff ============================================================================== --- sling/trunk/testing/resourceresolver-mock/pom.xml (original) +++ sling/trunk/testing/resourceresolver-mock/pom.xml Tue Sep 9 12:47:37 2014 @@ -69,10 +69,24 @@ <groupId>org.osgi</groupId> <artifactId>org.osgi.compendium</artifactId> <version>4.3.0</version> + <scope>compile</scope> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> </dependency> + <dependency> + <groupId>commons-io</groupId> + <artifactId>commons-io</artifactId> + <version>2.4</version> + <scope>compile</scope> + </dependency> + + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <scope>test</scope> + </dependency> </dependencies> + </project> Added: sling/trunk/testing/resourceresolver-mock/src/main/java/org/apache/sling/testing/resourceresolver/MockPropertyResource.java URL: http://svn.apache.org/viewvc/sling/trunk/testing/resourceresolver-mock/src/main/java/org/apache/sling/testing/resourceresolver/MockPropertyResource.java?rev=1623814&view=auto ============================================================================== --- sling/trunk/testing/resourceresolver-mock/src/main/java/org/apache/sling/testing/resourceresolver/MockPropertyResource.java (added) +++ sling/trunk/testing/resourceresolver-mock/src/main/java/org/apache/sling/testing/resourceresolver/MockPropertyResource.java Tue Sep 9 12:47:37 2014 @@ -0,0 +1,81 @@ +/* + * 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.testing.resourceresolver; + +import org.apache.sling.api.resource.AbstractResource; +import org.apache.sling.api.resource.ResourceMetadata; +import org.apache.sling.api.resource.ResourceResolver; +import org.apache.sling.api.resource.ResourceUtil; +import org.apache.sling.api.resource.ValueMap; + +/** + * Resource that wraps a property value. + */ +class MockPropertyResource extends AbstractResource { + + private final String path; + private final ValueMap props; + private final String key; + private final ResourceResolver resolver; + private final ResourceMetadata rm = new ResourceMetadata(); + + public MockPropertyResource(final String path, + final ValueMap props, + final ResourceResolver resolver) { + this.path = path; + this.props = props; + this.key = ResourceUtil.getName(path); + this.resolver = resolver; + } + + @Override + public String getPath() { + return this.path; + } + + @Override + public String getResourceType() { + return null; + } + + @Override + public String getResourceSuperType() { + return null; + } + + @Override + public ResourceMetadata getResourceMetadata() { + return rm; + } + + @Override + public ResourceResolver getResourceResolver() { + return this.resolver; + } + + @Override + public <AdapterType> AdapterType adaptTo(Class<AdapterType> type) { + AdapterType value = props.get(key, type); + if (value!=null) { + return value; + } + return super.adaptTo(type); + } + +} Propchange: sling/trunk/testing/resourceresolver-mock/src/main/java/org/apache/sling/testing/resourceresolver/MockPropertyResource.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: sling/trunk/testing/resourceresolver-mock/src/main/java/org/apache/sling/testing/resourceresolver/MockPropertyResource.java ------------------------------------------------------------------------------ --- svn:keywords (added) +++ svn:keywords Tue Sep 9 12:47:37 2014 @@ -0,0 +1 @@ +LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author Propchange: sling/trunk/testing/resourceresolver-mock/src/main/java/org/apache/sling/testing/resourceresolver/MockPropertyResource.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Modified: sling/trunk/testing/resourceresolver-mock/src/main/java/org/apache/sling/testing/resourceresolver/MockResource.java URL: http://svn.apache.org/viewvc/sling/trunk/testing/resourceresolver-mock/src/main/java/org/apache/sling/testing/resourceresolver/MockResource.java?rev=1623814&r1=1623813&r2=1623814&view=diff ============================================================================== --- sling/trunk/testing/resourceresolver-mock/src/main/java/org/apache/sling/testing/resourceresolver/MockResource.java (original) +++ sling/trunk/testing/resourceresolver-mock/src/main/java/org/apache/sling/testing/resourceresolver/MockResource.java Tue Sep 9 12:47:37 2014 @@ -32,17 +32,19 @@ public class MockResource extends Abstra private final String path; - private final Map<String, Object> props; + private final ValueMap props; private final ResourceMetadata rm = new ResourceMetadata(); private final ResourceResolver resolver; + static final String JCR_PRIMARYTYPE = "jcr:primaryType"; + public MockResource(final String path, final Map<String, Object> props, final ResourceResolver resolver) { this.path = path; - this.props = props; + this.props = (props instanceof MockValueMap) ? (MockValueMap)props : new MockValueMap(props); this.resolver = resolver; } @@ -53,12 +55,17 @@ public class MockResource extends Abstra @Override public String getResourceType() { - return (String)this.props.get(ResourceResolver.PROPERTY_RESOURCE_TYPE); + String resourceType = this.props.get(ResourceResolver.PROPERTY_RESOURCE_TYPE, String.class); + if (resourceType == null) { + // fallback to jcr:primaryType if not resouce type exists (to mimick JCR resource behavior) + resourceType = this.props.get(JCR_PRIMARYTYPE, String.class); + } + return resourceType; } @Override public String getResourceSuperType() { - return (String)this.props.get("sling:resourceSuperType"); + return this.props.get("sling:resourceSuperType", String.class); } @Override @@ -85,7 +92,7 @@ public class MockResource extends Abstra @Override public ValueMap getValueMap() { - return new ValueMapDecorator(this.props); + return this.props; } @Override Modified: sling/trunk/testing/resourceresolver-mock/src/main/java/org/apache/sling/testing/resourceresolver/MockResourceResolver.java URL: http://svn.apache.org/viewvc/sling/trunk/testing/resourceresolver-mock/src/main/java/org/apache/sling/testing/resourceresolver/MockResourceResolver.java?rev=1623814&r1=1623813&r2=1623814&view=diff ============================================================================== --- sling/trunk/testing/resourceresolver-mock/src/main/java/org/apache/sling/testing/resourceresolver/MockResourceResolver.java (original) +++ sling/trunk/testing/resourceresolver-mock/src/main/java/org/apache/sling/testing/resourceresolver/MockResourceResolver.java Tue Sep 9 12:47:37 2014 @@ -36,6 +36,8 @@ import org.apache.sling.api.resource.Log import org.apache.sling.api.resource.PersistenceException; import org.apache.sling.api.resource.Resource; import org.apache.sling.api.resource.ResourceResolver; +import org.apache.sling.api.resource.ResourceUtil; +import org.apache.sling.api.resource.ValueMap; import org.osgi.service.event.Event; public class MockResourceResolver extends SlingAdaptable implements ResourceResolver { @@ -86,6 +88,25 @@ public class MockResourceResolver extend @Override public Resource getResource(final String path) { + Resource resource = getResourceInternal(path); + + // if not resource found check if this is a reference to a property + if (resource == null) { + String name = ResourceUtil.getName(path); + String parentPath = ResourceUtil.getParent(path); + Resource parentResource = getResourceInternal(parentPath); + if (parentResource!=null) { + ValueMap props = parentResource.getValueMap(); + if (props.containsKey(name)) { + return new MockPropertyResource(path, props, this); + } + } + } + + return resource; + } + + private Resource getResourceInternal(final String path) { if ( path.startsWith("/") ) { if ( this.deletedResources.contains(path) ) { return null; @@ -186,7 +207,6 @@ public class MockResourceResolver extend @Override public ResourceResolver clone(Map<String, Object> authenticationInfo) throws LoginException { - // TODO Auto-generated method stub return null; } @@ -202,7 +222,6 @@ public class MockResourceResolver extend @Override public String getUserID() { - // TODO Auto-generated method stub return null; } @@ -254,9 +273,10 @@ public class MockResourceResolver extend if ( properties == null ) { properties = new HashMap<String, Object>(); } - this.temporaryResources.put(path, properties); - - return new MockResource(path, properties, this); + + Resource mockResource = new MockResource(path, properties, this); + this.temporaryResources.put(path, mockResource.getValueMap()); + return mockResource; } @Override Added: sling/trunk/testing/resourceresolver-mock/src/main/java/org/apache/sling/testing/resourceresolver/MockValueMap.java URL: http://svn.apache.org/viewvc/sling/trunk/testing/resourceresolver-mock/src/main/java/org/apache/sling/testing/resourceresolver/MockValueMap.java?rev=1623814&view=auto ============================================================================== --- sling/trunk/testing/resourceresolver-mock/src/main/java/org/apache/sling/testing/resourceresolver/MockValueMap.java (added) +++ sling/trunk/testing/resourceresolver-mock/src/main/java/org/apache/sling/testing/resourceresolver/MockValueMap.java Tue Sep 9 12:47:37 2014 @@ -0,0 +1,109 @@ +/* + * 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.testing.resourceresolver; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Calendar; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +import org.apache.commons.io.IOUtils; +import org.apache.sling.api.wrappers.ValueMapDecorator; + +/** + * ValueMap for mocked resources to mimick JCR-like behavior. + * <p>Implements the following conversions:</p> + * <ul> + * <li>Converts all Date values to Calendar objects internally and vice versa.</li> + * <li>Converts InputStream to byte array and vice versa.</li> + * <ul> + */ +public class MockValueMap extends ValueMapDecorator { + + public MockValueMap() { + this(new HashMap<String, Object>()); + } + + public MockValueMap(Map<String,Object> map) { + super(convertForWrite(map)); + } + + @SuppressWarnings("unchecked") + @Override + public <T> T get(String name, Class<T> type) { + if (type==Date.class) { + Calendar calendar = super.get(name, Calendar.class); + if (calendar != null) { + return (T)calendar.getTime(); + } + else { + return null; + } + } + else if (type==InputStream.class) { + byte[] data = super.get(name, byte[].class); + if (data!=null) { + return (T)new ByteArrayInputStream(data); + } + else { + return null; + } + } + return super.get(name, type); + } + + @Override + public Object put(String key, Object value) { + return super.put(key, convertForWrite(value)); + } + + @SuppressWarnings("unchecked") + @Override + public void putAll(Map<? extends String, ?> map) { + super.putAll((Map<? extends String, ?>)convertForWrite(map)); + } + + private static Object convertForWrite(Object value) { + if (value instanceof Date) { + Calendar calendar = Calendar.getInstance(); + calendar.setTime((Date)value); + value = calendar; + } + else if (value instanceof InputStream) { + try { + value = IOUtils.toByteArray((InputStream)value); + } catch (IOException ex) { + throw new RuntimeException("Unable to convert input stream to byte array."); + } + } + return value; + } + + private static Map<String, Object> convertForWrite(Map<String, Object> map) { + Map<String,Object> newMap = new HashMap<String, Object>(); + for (Map.Entry<String, Object> entry : map.entrySet()) { + newMap.put(entry.getKey(), convertForWrite(entry.getValue())); + } + return newMap; + } + +} Propchange: sling/trunk/testing/resourceresolver-mock/src/main/java/org/apache/sling/testing/resourceresolver/MockValueMap.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: sling/trunk/testing/resourceresolver-mock/src/main/java/org/apache/sling/testing/resourceresolver/MockValueMap.java ------------------------------------------------------------------------------ --- svn:keywords (added) +++ svn:keywords Tue Sep 9 12:47:37 2014 @@ -0,0 +1 @@ +LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author Propchange: sling/trunk/testing/resourceresolver-mock/src/main/java/org/apache/sling/testing/resourceresolver/MockValueMap.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Added: sling/trunk/testing/resourceresolver-mock/src/test/java/org/apache/sling/testing/resourceresolver/SlingCrudResourceResolverTest.java URL: http://svn.apache.org/viewvc/sling/trunk/testing/resourceresolver-mock/src/test/java/org/apache/sling/testing/resourceresolver/SlingCrudResourceResolverTest.java?rev=1623814&view=auto ============================================================================== --- sling/trunk/testing/resourceresolver-mock/src/test/java/org/apache/sling/testing/resourceresolver/SlingCrudResourceResolverTest.java (added) +++ sling/trunk/testing/resourceresolver-mock/src/test/java/org/apache/sling/testing/resourceresolver/SlingCrudResourceResolverTest.java Tue Sep 9 12:47:37 2014 @@ -0,0 +1,187 @@ +/* + * 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.testing.resourceresolver; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Calendar; +import java.util.Date; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import org.apache.commons.io.IOUtils; +import org.apache.sling.api.resource.LoginException; +import org.apache.sling.api.resource.PersistenceException; +import org.apache.sling.api.resource.Resource; +import org.apache.sling.api.resource.ResourceResolver; +import org.apache.sling.api.resource.ValueMap; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +/** + * Implements simple write and read resource and values test + * Sling CRUD API is used to create the test data. + */ +public class SlingCrudResourceResolverTest { + + private static final String STRING_VALUE = "value1"; + private static final String[] STRING_ARRAY_VALUE = new String[] { "value1", "value2" }; + private static final int INTEGER_VALUE = 25; + private static final double DOUBLE_VALUE = 3.555d; + private static final boolean BOOLEAN_VALUE = true; + private static final Date DATE_VALUE = new Date(10000); + private static final Calendar CALENDAR_VALUE = Calendar.getInstance(); + private static final byte[] BINARY_VALUE = new byte[] { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 }; + + private static final String NT_UNSTRUCTURED = "nt:unstructured"; + + private ResourceResolver resourceResolver; + protected Resource testRoot; + + @Before + public final void setUp() throws IOException, LoginException { + this.resourceResolver = new MockResourceResolverFactory().getResourceResolver(null); + + // prepare some test data using Sling CRUD API + Resource rootNode = getTestRootResource(); + + Map<String, Object> props = new HashMap<String, Object>(); + props.put(MockResource.JCR_PRIMARYTYPE, NT_UNSTRUCTURED); + props.put("stringProp", STRING_VALUE); + props.put("stringArrayProp", STRING_ARRAY_VALUE); + props.put("integerProp", INTEGER_VALUE); + props.put("doubleProp", DOUBLE_VALUE); + props.put("booleanProp", BOOLEAN_VALUE); + props.put("dateProp", DATE_VALUE); + props.put("calendarProp", CALENDAR_VALUE); + props.put("binaryProp", new ByteArrayInputStream(BINARY_VALUE)); + Resource node1 = this.resourceResolver.create(rootNode, "node1", props); + + this.resourceResolver.create(node1, "node11", ValueMap.EMPTY); + this.resourceResolver.create(node1, "node12", ValueMap.EMPTY); + + this.resourceResolver.commit(); + } + + @After + public final void tearDown() { + this.testRoot = null; + } + + /** + * Return a test root resource, created on demand, with a unique path + * @throws PersistenceException + */ + private Resource getTestRootResource() throws PersistenceException { + if (this.testRoot == null) { + final Resource root = this.resourceResolver.getResource("/"); + this.testRoot = this.resourceResolver.create(root, "test", ValueMap.EMPTY); + } + return this.testRoot; + } + + @Test + public void testSimpleProperties() throws IOException { + Resource resource1 = this.resourceResolver.getResource(getTestRootResource().getPath() + "/node1"); + assertNotNull(resource1); + assertEquals("node1", resource1.getName()); + + ValueMap props = resource1.getValueMap(); + assertEquals(STRING_VALUE, props.get("stringProp", String.class)); + assertArrayEquals(STRING_ARRAY_VALUE, props.get("stringArrayProp", String[].class)); + assertEquals((Integer) INTEGER_VALUE, props.get("integerProp", Integer.class)); + assertEquals(DOUBLE_VALUE, props.get("doubleProp", Double.class), 0.0001); + assertEquals(BOOLEAN_VALUE, props.get("booleanProp", Boolean.class)); + } + + @Test + public void testDateProperty() throws IOException { + Resource resource1 = this.resourceResolver.getResource(getTestRootResource().getPath() + "/node1"); + ValueMap props = resource1.getValueMap(); + assertEquals(DATE_VALUE, props.get("dateProp", Date.class)); + } + + @Test + public void testDatePropertyToCalendar() throws IOException { + Resource resource1 = this.resourceResolver.getResource(getTestRootResource().getPath() + "/node1"); + ValueMap props = resource1.getValueMap(); + Calendar calendarValue = props.get("dateProp", Calendar.class); + assertNotNull(calendarValue); + assertEquals(DATE_VALUE, calendarValue.getTime()); + } + + @Test + public void testCalendarProperty() throws IOException { + Resource resource1 = this.resourceResolver.getResource(getTestRootResource().getPath() + "/node1"); + ValueMap props = resource1.getValueMap(); + assertEquals(CALENDAR_VALUE.getTime(), props.get("calendarProp", Calendar.class).getTime()); + } + + @Test + public void testCalendarPropertyToDate() throws IOException { + Resource resource1 = this.resourceResolver.getResource(getTestRootResource().getPath() + "/node1"); + ValueMap props = resource1.getValueMap(); + Date dateValue = props.get("calendarProp", Date.class); + assertNotNull(dateValue); + assertEquals(CALENDAR_VALUE.getTime(), dateValue); + } + + @Test + public void testListChildren() throws IOException { + Resource resource1 = this.resourceResolver.getResource(getTestRootResource().getPath() + "/node1"); + + Iterator<Resource> children = resource1.listChildren(); + assertEquals("node11", children.next().getName()); + assertEquals("node12", children.next().getName()); + assertFalse(children.hasNext()); + } + + @Test + public void testBinaryData() throws IOException { + Resource resource1 = this.resourceResolver.getResource(getTestRootResource().getPath() + "/node1"); + + Resource binaryPropResource = resource1.getChild("binaryProp"); + InputStream is = binaryPropResource.adaptTo(InputStream.class); + byte[] dataFromResource = IOUtils.toByteArray(is); + is.close(); + assertArrayEquals(BINARY_VALUE, dataFromResource); + + // read second time to ensure not the original input stream was returned + // and this time using another syntax + InputStream is2 = resource1.getValueMap().get("binaryProp", InputStream.class); + byte[] dataFromResource2 = IOUtils.toByteArray(is2); + is2.close(); + assertArrayEquals(BINARY_VALUE, dataFromResource2); + } + + @Test + public void testPrimaryTypeResourceType() throws PersistenceException { + Resource resource1 = this.resourceResolver.getResource(getTestRootResource().getPath() + "/node1"); + assertEquals(NT_UNSTRUCTURED, resource1.getResourceType()); + } + +} Propchange: sling/trunk/testing/resourceresolver-mock/src/test/java/org/apache/sling/testing/resourceresolver/SlingCrudResourceResolverTest.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: sling/trunk/testing/resourceresolver-mock/src/test/java/org/apache/sling/testing/resourceresolver/SlingCrudResourceResolverTest.java ------------------------------------------------------------------------------ --- svn:keywords (added) +++ svn:keywords Tue Sep 9 12:47:37 2014 @@ -0,0 +1 @@ +LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author Propchange: sling/trunk/testing/resourceresolver-mock/src/test/java/org/apache/sling/testing/resourceresolver/SlingCrudResourceResolverTest.java ------------------------------------------------------------------------------ svn:mime-type = text/plain