/* * 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.samples.pathbasedrtp; import java.util.Dictionary; import javax.jcr.Node; import javax.jcr.RepositoryException; import javax.servlet.http.HttpServletRequest; import org.apache.felix.scr.annotations.Component; import org.apache.felix.scr.annotations.Property; import org.apache.felix.scr.annotations.PropertyUnbounded; import org.apache.felix.scr.annotations.Service; import org.apache.sling.api.resource.Resource; import org.apache.sling.api.resource.ResourceDecorator; import org.apache.sling.api.resource.ResourceWrapper; import org.osgi.service.component.ComponentContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Default resource type provider that uses a component of the node path * to define the default resource type. * * A number of mappings can be configured, for example "/content:2" would * cause a node at /content/foo/bar to get the "foo" resource type if it * doesn't have a default one: "/content" is used to select nodes to which the * mapping applies, and "2" is the (1-based) index of the path component to * use as the resource type. * */ @Component(metatype=true, label="%defaultRtp.name", description="%defaultRtp.description") @Service @Property(name="service.description", value="Sling Sample Resource Decorator") public class PathBasedResourceDecorator implements ResourceDecorator { /** * Name of the configurable property name that defines mappings. The default values * specify the use of path component 2 for the /content path, and add a similar * definition for the /sling-test-pbrt path that is used in integration testing. * */ @Property(value={"/content:2", "/sling-test-pbrt:2"}, unbounded=PropertyUnbounded.ARRAY) private static final String PROP_PATH_MAPPING = "path.mapping"; private final Logger log = LoggerFactory.getLogger(getClass()); private Mapping [] mappings; /** * @see org.apache.sling.api.resource.ResourceDecorator#decorate(org.apache.sling.api.resource.Resource, javax.servlet.http.HttpServletRequest) */ public Resource decorate(Resource resource, HttpServletRequest request) { return this.decorate(resource); } /** Return a resource type for given node, if we have a mapping that applies */ public Resource decorate(Resource resource) { String result = null; if (mappings!=null) { // let's check when we should apply the mapping // 1. if the resource is a star resource boolean apply = false; String resourceType = null; if ( resource.getPath().endsWith("/*") ) { apply = true; resourceType = Mapping.DEFAULT_NODE_TYPE; } else { // 2. if the resource is adaptable to a node // and the primary node type equals the resource type try { final Node node = resource.adaptTo(Node.class); if ( node != null && node.getPrimaryNodeType().getName().equals(resource.getResourceType()) ) { apply = true; resourceType = resource.getResourceType(); } } catch (RepositoryException re) { // we ignore this } } if ( apply ) { final String path = resource.getPath(); for(Mapping m : mappings) { result = m.getResourceType(path, resourceType); if (result != null) { log.debug("Default resource type {} used for resource {}", result, path); break; } } } } if (result==null && log.isDebugEnabled()) { log.debug("No Mapping applies to node {}, no resource type provided", resource.getPath()); } if ( result != null ) { final String resourceType = result; return new ResourceWrapper(resource) { @Override public String getResourceType() { return resourceType; } }; } return resource; } /** Activates this component, called by SCR before registering as a service */ protected void activate(ComponentContext componentContext) { final Dictionary<?, ?> properties = componentContext.getProperties(); final String[] mappingList = (String[]) properties.get(PROP_PATH_MAPPING); if(mappingList== null || mappingList.length == 0) { mappings = null; } else { mappings = new Mapping[mappingList.length]; for(int i=0; i < mappingList.length; i++) { mappings[i] = new Mapping(mappingList[i]); log.debug("Added {}", mappings[i]); } } } }