blob: 5d250b5c8169b4f06affe5f0df0ce1489dd8c3f9 [file] [log] [blame]
/*
* 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.scripting.javascript.wrapper;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.jcr.Item;
import javax.jcr.NamespaceException;
import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.Property;
import javax.jcr.PropertyIterator;
import javax.jcr.PropertyType;
import javax.jcr.RepositoryException;
import javax.jcr.Value;
import org.apache.jackrabbit.JcrConstants;
import org.apache.sling.api.SlingConstants;
import org.apache.sling.api.resource.Resource;
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;
import org.apache.sling.api.wrappers.ValueMapDecorator;
import org.apache.sling.commons.testing.sling.MockResourceResolver;
import org.apache.sling.jcr.resource.JcrResourceConstants;
import org.apache.sling.scripting.javascript.RepositoryScriptingTestBase;
import org.apache.sling.scripting.javascript.internal.ScriptEngineHelper;
import org.jetbrains.annotations.NotNull;
import org.mozilla.javascript.Wrapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ScriptableResourceTest extends RepositoryScriptingTestBase {
private Node node;
private static final ResourceResolver RESOURCE_RESOLVER = new MockResourceResolver();
private static final String RESOURCE_TYPE = "testWrappedResourceType";
private static final String RESOURCE_SUPER_TYPE = "testWrappedResourceSuperType";
private static final Logger LOGGER = LoggerFactory.getLogger(ScriptableResourceTest.class);
@Override
protected void setUp() throws Exception {
super.setUp();
node = getNewNode();
try {
node.getSession().getWorkspace().getNamespaceRegistry().registerNamespace(
SlingConstants.NAMESPACE_PREFIX,
JcrResourceConstants.SLING_NAMESPACE_URI);
} catch (NamespaceException ne) {
// don't care, might happen if already registered
}
}
public void testDefaultValuePath() throws Exception {
final ScriptEngineHelper.Data data = new ScriptEngineHelper.Data();
data.put("resource", new TestResource(node));
// the path of the resource
assertEquals(node.getPath(), script.evalToString("out.print(resource)",
data));
assertEquals(node.getPath(), script.eval("resource.path", data));
assertEquals(node.getPath(), script.eval("resource.getPath()", data));
}
public void testResourceType() throws Exception {
// set resource and resource super type
node.setProperty(JcrResourceConstants.SLING_RESOURCE_TYPE_PROPERTY,
RESOURCE_TYPE);
node.setProperty(
JcrResourceConstants.SLING_RESOURCE_SUPER_TYPE_PROPERTY,
RESOURCE_SUPER_TYPE);
final ScriptEngineHelper.Data data = new ScriptEngineHelper.Data();
data.put("resource", new TestResource(node));
// the resourceType of the resource
assertEquals(RESOURCE_TYPE, script.eval("resource.type", data));
assertEquals(RESOURCE_TYPE, script.eval("resource.resourceType", data));
assertEquals(RESOURCE_TYPE, script.eval("resource.getResourceType()",
data));
}
public void testChildren() throws Exception {
node.addNode("first-child");
node.addNode("second-child");
final ScriptEngineHelper.Data data = new ScriptEngineHelper.Data();
data.put("resource", new TestResource(node));
assertEquals(2.0, script.eval("resource.getChildren().length", data));
assertEquals("first-child", script.eval("resource.getChildren()[0].name", data));
}
public void testListChildren() throws Exception {
Node firstChild = node.addNode("first-child");
node.addNode("second-child");
final ScriptEngineHelper.Data data = new ScriptEngineHelper.Data();
data.put("resource", new TestResource(node));
assertEquals(2.0, script.eval("resource.listChildren().length", data));
assertEquals(firstChild.getPath(), script.eval("resource.listChildren()[0].path", data));
}
public void testGetChild() throws Exception {
Node child = node.addNode("child");
final ScriptEngineHelper.Data data = new ScriptEngineHelper.Data();
data.put("resource", new TestResource(node));
assertEquals(child.getPath(), script.eval("resource.getChild('./child').path", data));
}
public void testGetParent() throws Exception {
Node child = node.addNode("child");
Node grandChild = child.addNode("grandchild");
final ScriptEngineHelper.Data data = new ScriptEngineHelper.Data();
data.put("resource", new TestResource(grandChild));
assertEquals(child.getPath(), script.eval("resource.getParent().getPath()", data));
}
public void testParent() throws Exception {
Node child = node.addNode("child");
Node grandChild = child.addNode("grandchild");
final ScriptEngineHelper.Data data = new ScriptEngineHelper.Data();
data.put("resource", new TestResource(grandChild));
assertEquals(child.getPath(), script.eval("resource.parent.path", data));
}
public void testIsResourceType() throws Exception {
final ScriptEngineHelper.Data data = new ScriptEngineHelper.Data();
data.put("resource", new TestResource(node));
assertEquals(Boolean.TRUE, script.eval("resource.isResourceType('" + RESOURCE_TYPE + "')", data));
}
public void testResourceSuperType() throws Exception {
// set resource and resource super type
node.setProperty(JcrResourceConstants.SLING_RESOURCE_TYPE_PROPERTY,
RESOURCE_TYPE);
node.setProperty(
JcrResourceConstants.SLING_RESOURCE_SUPER_TYPE_PROPERTY,
RESOURCE_SUPER_TYPE);
final ScriptEngineHelper.Data data = new ScriptEngineHelper.Data();
data.put("resource", new TestResource(node));
// the resourceType of the resource
assertEquals(RESOURCE_SUPER_TYPE, script.eval(
"resource.resourceSuperType", data));
assertEquals(RESOURCE_SUPER_TYPE, script.eval(
"resource.getResourceSuperType()", data));
}
public void testResourceMetadata() throws Exception {
final ScriptEngineHelper.Data data = new ScriptEngineHelper.Data();
data.put("resource", new TestResource(node));
// official API
assertResourceMetaData(script.eval("resource.resourceMetadata", data));
assertResourceMetaData(script.eval("resource.getResourceMetadata()",
data));
// deprecated mappings
assertResourceMetaData(script.eval("resource.meta", data));
assertResourceMetaData(script.eval("resource.getMetadata()", data));
}
public void testResourceResolver() throws Exception {
final ScriptEngineHelper.Data data = new ScriptEngineHelper.Data();
data.put("resource", new TestResource(node));
// official API
assertEquals(RESOURCE_RESOLVER, script.eval(
"resource.resourceResolver", data));
assertEquals(RESOURCE_RESOLVER, script.eval(
"resource.getResourceResolver()", data));
}
public void testAdaptToNode() throws Exception {
final ScriptEngineHelper.Data data = new ScriptEngineHelper.Data();
data.put("resource", new TestResource(node));
// the node to which the resource adapts
assertEquals(node, script.eval("resource.adaptTo('javax.jcr.Node')",
data));
assertEquals(node, script.eval(
"resource.adaptTo(Packages.javax.jcr.Node)", data));
}
public void testAdaptToNothing() throws Exception {
final ScriptEngineHelper.Data data = new ScriptEngineHelper.Data();
data.put("resource", new TestResource(node));
// the node to which the resource adapts
assertEquals(true, script.eval("resource.adaptTo() == undefined", data));
assertEquals(true, script.eval("resource.adaptTo(null) == undefined", data));
assertEquals(true, script.eval("resource.adaptTo(undefined) == undefined", data));
assertEquals(true, script.eval("resource.adaptTo(Packages.java.util.Date) == undefined", data));
}
public void testProperties() throws Exception {
final ScriptEngineHelper.Data data = new ScriptEngineHelper.Data();
Calendar date = new GregorianCalendar();
node.setProperty(JcrConstants.JCR_LASTMODIFIED, date);
node.setProperty("test", "testProperties");
node.getSession().save();
data.put("resource", new TestResource(node));
assertEquals(date.getTimeInMillis(), script.eval("(resource.properties['jcr:lastModified']).getTimeInMillis()", data));
assertEquals("testProperties", script.eval("resource.properties.test", data));
}
private void assertEquals(Node expected, Object actual) {
while (actual instanceof Wrapper) {
actual = ((Wrapper) actual).unwrap();
}
super.assertEquals(expected, actual);
}
private void assertResourceMetaData(Object metaData) throws Exception {
if (metaData instanceof ResourceMetadata) {
ResourceMetadata rm = (ResourceMetadata) metaData;
rm.getResolutionPath().equals(node.getPath());
} else {
fail("Expected ResourceMetadata, got " + metaData);
}
}
private static class TestResource implements Resource {
private final Node node;
private final String path;
private final ResourceMetadata metadata;
TestResource(Node node) throws RepositoryException {
this.node = node;
this.path = node.getPath();
this.metadata = new ResourceMetadata();
this.metadata.setResolutionPath(this.path);
}
public String getPath() {
return path;
}
public ResourceMetadata getResourceMetadata() {
return metadata;
}
public ResourceResolver getResourceResolver() {
return RESOURCE_RESOLVER;
}
@Override
public @NotNull ValueMap getValueMap() {
return adaptTo(ValueMap.class);
}
public String getResourceType() {
return RESOURCE_TYPE;
}
public String getResourceSuperType() {
return RESOURCE_SUPER_TYPE;
}
@Override
public boolean hasChildren() {
try {
return node.hasNodes();
} catch (RepositoryException e) {
// do nothing
}
return false;
}
@SuppressWarnings("unchecked")
public <AdapterType> AdapterType adaptTo(Class<AdapterType> type) {
if (type == Node.class || type == Item.class) {
return (AdapterType) node;
} else if (type == ValueMap.class) {
try {
PropertyIterator iterator = node.getProperties();
Map<String, Object> properties = new HashMap<String, Object>();
while (iterator.hasNext()) {
Property prop = iterator.nextProperty();
if (prop.isMultiple()) {
Value[] values = prop.getValues();
Object[] array = new Object[values.length];
int index = 0;
for (Value value : values) {
switch (value.getType()) {
case PropertyType.BINARY:
array[index++] = value.getBinary();
break;
case PropertyType.BOOLEAN:
array[index++] = value.getBoolean();
break;
case PropertyType.DATE:
array[index++] = value.getDate();
break;
case PropertyType.DECIMAL:
array[index++] = value.getDecimal();
break;
case PropertyType.DOUBLE:
array[index++] = value.getDouble();
break;
case PropertyType.LONG:
array[index++] = value.getLong();
break;
default:
array[index++] = value.getString();
break;
}
}
properties.put(prop.getName(), array);
} else {
Value value = prop.getValue();
switch (value.getType()) {
case PropertyType.BINARY:
properties.put(prop.getName(), value.getBinary());
break;
case PropertyType.BOOLEAN:
properties.put(prop.getName(), value.getBoolean());
break;
case PropertyType.DATE:
properties.put(prop.getName(), value.getDate());
break;
case PropertyType.DECIMAL:
properties.put(prop.getName(), value.getDecimal());
break;
case PropertyType.DOUBLE:
properties.put(prop.getName(), value.getDouble());
break;
case PropertyType.LONG:
properties.put(prop.getName(), value.getLong());
break;
default:
properties.put(prop.getName(), value.getString());
break;
}
}
}
return ((AdapterType) (new ValueMapDecorator(properties)));
} catch (RepositoryException e) {
LOGGER.error("Unable to adapt resource " + getPath() + " to a ValueMap.", e);
}
}
return null;
}
public String getName() {
return ResourceUtil.getName(getPath());
}
public Resource getChild(String relPath) {
try
{
Node childNode = node.getNode( relPath );
if ( childNode != null ) {
return new TestResource( childNode );
} else {
return null;
}
} catch ( RepositoryException re )
{
return null;
}
}
public Resource getParent() {
try
{
Node parentNode = node.getParent();
if ( parentNode != null ) {
return new TestResource( parentNode );
} else {
return null;
}
} catch ( RepositoryException re )
{
return null;
}
}
public boolean isResourceType(String resourceType) {
return getResourceType().equals( resourceType );
}
public Iterator<Resource> listChildren() {
return getChildren().iterator();
}
@Override
public @NotNull Iterable<Resource> getChildren() {
try
{
List<Resource> childList = new ArrayList<Resource>();
NodeIterator it = node.getNodes();
while ( it.hasNext() )
{
Node nextNode = it.nextNode();
childList.add( new TestResource( nextNode ) );
}
return childList;
} catch ( RepositoryException re )
{
return null;
}
}
}
}