/* * 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.resource.collection.impl; import java.text.MessageFormat; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import org.apache.commons.lang.ArrayUtils; import org.apache.sling.api.resource.ModifiableValueMap; 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.apache.sling.jcr.resource.JcrResourceConstants; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.apache.sling.resource.collection.ResourceCollection; /** * Implements <code>ResourceCollection</code> * */ public class ResourceCollectionImpl implements ResourceCollection { private static final Logger log = LoggerFactory.getLogger(ResourceCollectionImpl.class); /** * Defines the resource type property */ private static final String RESOURCE_TYPE = JcrResourceConstants.SLING_RESOURCE_TYPE_PROPERTY; /** * underlying resource */ private final Resource resource; /** * The resource resolver in use by the resource. */ private final ResourceResolver resolver; private final Resource membersResource; /** * Creates a new collection from the given resource * * @param resource the resource */ public ResourceCollectionImpl(Resource resource) { this.resource = resource; resolver = resource.getResourceResolver(); membersResource = resource.getChild(ResourceCollectionConstants.MEMBERS_NODE_NAME); } /** * {@inheritDoc} */ public String getName() { return resource.getName(); } /** * {@inheritDoc} */ public String getPath() { return resource.getPath(); } /** * {@inheritDoc} */ public boolean add(Resource res, Map<String, Object> properties) throws PersistenceException { if (res != null && !contains(res)) { ModifiableValueMap vm = membersResource.adaptTo(ModifiableValueMap.class); String[] order = vm.get(ResourceCollectionConstants.REFERENCES_PROP, new String[]{}); order = (String[]) ArrayUtils.add(order, res.getPath()); vm.put(ResourceCollectionConstants.REFERENCES_PROP, order); if (properties == null) { properties = new HashMap<String, Object>(); } properties.put(ResourceCollectionConstants.REF_PROPERTY, res.getPath()); resolver.create( membersResource, ResourceUtil.createUniqueChildName(membersResource, res.getName()), properties); log.debug("added member to resource {} to collection {}", new String[] { res.getPath(), resource.getPath() }); return true; } return false; } /** * {@inheritDoc} */ public boolean add(Resource res) throws PersistenceException { if (res != null && !contains(res)) { ModifiableValueMap vm = membersResource.adaptTo(ModifiableValueMap.class); String[] order = vm.get(ResourceCollectionConstants.REFERENCES_PROP, new String[]{}); order = (String[]) ArrayUtils.add(order, res.getPath()); vm.put(ResourceCollectionConstants.REFERENCES_PROP, order); Map<String, Object> properties = new HashMap<String, Object>(); properties.put(ResourceCollectionConstants.REF_PROPERTY, res.getPath()); resolver.create( membersResource, ResourceUtil.createUniqueChildName(membersResource, res.getName()), properties); log.debug("added member to resource {} to collection {}", new String[] { res.getPath(), resource.getPath() }); return true; } return false; } /** * {@inheritDoc} */ public Iterator<Resource> getResources() { ValueMap vm = membersResource.adaptTo(ValueMap.class); String[] references = vm.get(ResourceCollectionConstants.REFERENCES_PROP, new String[]{}); List<Resource> resources = new ArrayList<Resource>(); for (String path:references) { Resource resource = resolver.getResource(path); if (resource != null){ resources.add(resource); } } return resources.iterator(); } /** * Returns the sling resource type on content node of collection * * @param * @return <code>sling:resourceType</code> for the collection resource */ public String getType() { return resource.getResourceType(); } /** * {@inheritDoc} */ public boolean contains(Resource res) { if (res != null) { ValueMap vm = membersResource.adaptTo(ValueMap.class); String[] order = vm.get(ResourceCollectionConstants.REFERENCES_PROP, new String[]{}); int index = ArrayUtils.indexOf(order, res.getPath(), 0); return index >= 0 ? true: false; } return false; } /** * {@inheritDoc} */ public boolean remove(Resource res) throws PersistenceException { //remove the resource Resource tobeRemovedRes = findRes(res); if (tobeRemovedRes == null) { return false; } resolver.delete(tobeRemovedRes); //remove from order array ModifiableValueMap vm = membersResource.adaptTo(ModifiableValueMap.class); String[] order = vm.get(ResourceCollectionConstants.REFERENCES_PROP, new String[]{}); int index = ArrayUtils.indexOf(order, res.getPath(), 0); order = (String[]) ArrayUtils.remove(order, index); vm.put(ResourceCollectionConstants.REFERENCES_PROP, order); return true; } /** * Sets the sling resource type on content node of collection * * @param type <code>sling:resourceType</code> to be set on the content node * @return */ public void setType(String type) throws PersistenceException { ModifiableValueMap mvp = resource.adaptTo(ModifiableValueMap.class); mvp.put(RESOURCE_TYPE, type); } private Resource findRes(Resource res) { if (res != null) { String resName = res.getName(); if (membersResource.getChild(resName) != null && (res.getPath()).equals(ResourceUtil.getValueMap( membersResource.getChild(resName)).get(ResourceCollectionConstants.REF_PROPERTY, ""))) return membersResource.getChild(resName); // handle multiple res with same name but different paths Iterator<Resource> children = membersResource.listChildren(); while (children.hasNext()) { Resource r = children.next(); if (ResourceUtil.getValueMap(r).get(ResourceCollectionConstants.REF_PROPERTY, "").equals( res.getPath())) return r; } } return null; } public void orderBefore(Resource srcResource, Resource destResource) { if (srcResource == null) { throw new IllegalArgumentException("Source Resource can not be null"); } ModifiableValueMap vm = membersResource.adaptTo(ModifiableValueMap.class); String[] order = vm.get(ResourceCollectionConstants.REFERENCES_PROP, new String[]{}); String srcPath = srcResource.getPath(); int srcIndex = ArrayUtils.indexOf(order, srcPath); if (srcIndex < 0) { log.warn("Collection ordering failed, as there is no resource {} in collection {} for destResource", srcPath, getPath()); return ; } if (destResource == null) { //add it to the end. order = (String[]) ArrayUtils.remove(order, srcIndex); order = (String[]) ArrayUtils.add(order, srcPath); } else { String destPath = destResource.getPath(); if (destPath.equals(srcPath)) { String message = MessageFormat.format("Collection ordering failed, as source {0} and destination {1} can not be same", srcPath, destPath); log.error(message); throw new IllegalArgumentException(message); } int destIndex = ArrayUtils.indexOf(order, destPath); if (destIndex < 0) { log.warn("Collection ordering failed, as there is no resource {} in collection {} for destResource", destPath, getPath()); return; } order = (String[]) ArrayUtils.remove(order, srcIndex); if (srcIndex < destIndex) { //recalculate dest index destIndex = ArrayUtils.indexOf(order, destPath); } order = (String[]) ArrayUtils.add(order, destIndex, srcPath); } vm.put(ResourceCollectionConstants.REFERENCES_PROP, order); } public ModifiableValueMap getProperties(Resource resource) { Iterator<Resource> entries = membersResource.listChildren(); while (entries.hasNext()) { Resource entry = entries.next(); String path = ResourceUtil.getValueMap(entry).get( ResourceCollectionConstants.REF_PROPERTY, ""); if (resource.getPath().equals(path)) { return entry.adaptTo(ModifiableValueMap.class); } } return null; } }