/* * Copyright 2012 david gonzalez. * * Licensed 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 com.activecq.samples.slingresourceprovider.impl; import com.day.cq.commons.jcr.JcrConstants; import org.apache.commons.lang.StringUtils; import org.apache.felix.scr.annotations.Activate; import org.apache.felix.scr.annotations.Component; import org.apache.felix.scr.annotations.Deactivate; import org.apache.felix.scr.annotations.Properties; import org.apache.felix.scr.annotations.Property; import org.apache.felix.scr.annotations.Service; import org.apache.sling.api.resource.Resource; import org.apache.sling.api.resource.ResourceMetadata; import org.apache.sling.api.resource.ResourceProvider; import org.apache.sling.api.resource.ResourceResolver; import org.apache.sling.api.resource.SyntheticResource; import org.apache.sling.commons.osgi.PropertiesUtil; import org.osgi.framework.Constants; import org.osgi.service.component.ComponentContext; import javax.servlet.http.HttpServletRequest; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; /** * @author david */ @Component( label = "Samples - Sling Resource Provider", description = "Sample Sling Resource Provider", metatype = false, immediate = false ) @Properties({ @Property( label = "Vendor", name = Constants.SERVICE_VENDOR, value = "ActiveCQ", propertyPrivate = true ), @Property( label = "Root paths", description = "Root paths this Sling Resource Provider will respond to", name = ResourceProvider.ROOTS, value = {"/content/mount/thirdparty"}) }) @Service public class SampleSlingResourceProvider implements ResourceProvider { private List<String> roots; @Override public Resource getResource(ResourceResolver resourceResolver, HttpServletRequest request, String path) { // For this example the Request is not taken into consideration when evaluating // the Resource request, so we just call getResource(rr, path) // Remember, since this is a Synthetic resource there are no ACLs applied to this // resource. If you would like to restrict access, it must be done programmatically by checking // the ResourceResolver's user. return getResource(resourceResolver, path); } @Override public Resource getResource(ResourceResolver resourceResolver, String path) { // Make getResource() return as fast as possible! // Return null early if getResource() cannot/should not process the resource request // Check the user/group issuing the resource resolution request if (!accepts(resourceResolver)) { return null; } // Reject any paths that do not match the roots if (!accepts(path)) { return null; } // If path is a root, return a Sythentic Folder // This could be any "type" of SyntheticResource if (isRoot(path)) { return new SyntheticResource(resourceResolver, path, JcrConstants.NT_FOLDER); } // Do other checks on the path to make sure it meets your specific requirements // Make a call to some other sytem using the path/request and resolve the data to return // as the provided resource Map<String, String> thirdPartyData = new HashMap<String, String>(); // Mocking some data from a third party that represents this resource thirdPartyData.put("resourceTypeKey", "samples/components/content/title"); thirdPartyData.put("sample-data", "This is sample data"); ResourceMetadata resourceMetaData = new ResourceMetadata(); // Set the resolution path resourceMetaData.setResolutionPath(path); // This resourceType can of course be set/derived from anywhere // Often it is set in the OSGi Properties if the value is fixed for all // Resources this provider returns final String resourceType = thirdPartyData.get("resourceTypeKey"); // Populate "custom" data resourceMetaData.put("sample-data", thirdPartyData.get("sample-data")); // Create the resource to return Resource resource = new SyntheticResource(resourceResolver, resourceMetaData, resourceType); return resource; } @Override public Iterator<Resource> listChildren(Resource parent) { final String path = parent.getPath(); // Check the user/group issuing the resource resolution request if (!accepts(parent.getResourceResolver())) { return null; } // Reject any paths that do not match the roots if (!accepts(path)) { return null; } // If path is not the root, return null // This only allows listChildren to be called on a "Root" path // This restriction is implementation specific if (!isRoot(path)) { return null; } List<Resource> resources = new ArrayList<Resource>(); // Call third party, get and create a list of resources in a similar fashion as in getResource for (int i = 0; i < 10; i++) { ResourceMetadata resourceMetaData = new ResourceMetadata(); // Create the "path" for this resource; this pathing scheme should // be compatible with getResource(..) resourceMetaData.setResolutionPath(path + "_" + i); resourceMetaData.put("index", String.valueOf(i)); final String resourceType = "samples/components/content/title"; Resource resource = new SyntheticResource(parent.getResourceResolver(), resourceMetaData, resourceType); resources.add(resource); } return resources.iterator(); } /** * Checks if the provided path is a defined Root path * * @param path * @return */ protected boolean isRoot(String path) { for (String root : this.roots) { if (StringUtils.equals(path, root)) { return true; } } return false; } /** * Checks if this Resource Provider is willing to handle the resource path * * @param path * @return */ protected boolean accepts(String path) { for (String root : this.roots) { if (StringUtils.startsWith(path, root.concat("/"))) { return true; } } return false; } /** * Checks if this Resource Provider is willing to handle the resolution request * * @param resourceResolver * @return */ protected boolean accepts(ResourceResolver resourceResolver) { if (resourceResolver == null) { return false; } if (StringUtils.equals("anonymous", resourceResolver.getUserID())) { // Terrible "anonymous" check, this is just for an example return false; } return true; } /** * OSGi Component Methods * */ @Activate protected void activate(final ComponentContext componentContext) throws Exception { configure(componentContext); } @Deactivate protected void deactivate(ComponentContext ctx) { } private void configure(final ComponentContext componentContext) { final Map<String, String> properties = (Map<String, String>) componentContext.getProperties(); // Get Roots from Service properties this.roots = new ArrayList<String>(); String[] rootsArray = PropertiesUtil.toStringArray(properties.get(ResourceProvider.ROOTS), new String[]{}); for (String root : rootsArray) { root = StringUtils.strip(root); if (StringUtils.isBlank(root)) { continue; } else if (StringUtils.equals(root, "/")) { // Cowardly refusing to mount the root continue; } this.roots.add(StringUtils.removeEnd(root, "/")); } } }