com.day.cq.commons.inherit.HierarchyNodeInheritanceValueMap Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of aem-sdk-api Show documentation
Show all versions of aem-sdk-api Show documentation
The Adobe Experience Manager SDK
/*
* Copyright 1997-2010 Day Management AG
* Barfuesserplatz 6, 4001 Basel, Switzerland
* All Rights Reserved.
*
* This software is the confidential and proprietary information of
* Day Management AG, ("Confidential Information"). You shall not
* disclose such Confidential Information and shall use it only in
* accordance with the terms of the license agreement you entered into
* with Day.
*/
package com.day.cq.commons.inherit;
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 com.day.cq.commons.ValueMapWrapper;
import com.day.cq.commons.jcr.JcrConstants;
/**
* An {@link InheritanceValueMap} for a given {@link Resource} that will inherit values from
* ancestral pages.
*
*
* For example, given: /content/parent/page/jcr:content/footer/image/@width
,
* the HierarchyNodeInheritanceValueMap
will search for a footer/image/@width
* property in:
*
* /content/parent/page/jcr:content/footer/image/@width
* /content/parent/jcr:content/footer/image/@width
* /content/jcr:content/footer/image/@width
*
* Having not found it in any of those locations, it will then return null
.
*
*
* Note that HierarchyNodeInheritanceValueMap
searches only the page
* hierarchy. It will not (for instance), look in:
*
* /content/parent/page/jcr:content/footer/@width
*
* See {@link ComponentInheritanceValueMap} for that functionality.
*/
public class HierarchyNodeInheritanceValueMap extends ValueMapWrapper implements InheritanceValueMap {
private Resource resource;
/**
* Will wrap the {@link ValueMap} returned by
* resource.adaptTo(ValueMap.class)
, or use an empty map if
* resource
is null or if it doesn't adapt to a ValueMap. The
* inheritance is internally resolved by fetching the parent resource and
* wrapping it into an {@link HierarchyNodeInheritanceValueMap} as well.
*
* @param resource
* the resource to start from
*/
public HierarchyNodeInheritanceValueMap(Resource resource) {
super(ResourceUtil.getValueMap(resource));
this.resource = resource;
}
/**
* Use this if the underlying {@link Resource} for a {@link ValueMap} is not
* available and no inheritance is needed. Using the inheritance-enabled
* {@link #getInherited(String, Class) getter}
* {@link #getInherited(String, Object) methods} will behave exactly like
* the normal ValueMap getters.
*
* @param map
* a ValueMap to wrap
*/
public HierarchyNodeInheritanceValueMap(ValueMap map) {
super(map);
this.resource = null;
}
@Override
@SuppressWarnings("unchecked")
public T get(String name, Class type) {
// overwritten to fix NPE
if (type == null) {
return (T) get(name);
}
return super.get(name, type);
}
public T getInherited(String name, Class type) {
T value = get(name, type);
if (value == null) {
value = getParentPageValue(getInnerPath(resource), name, type);
}
return value;
}
@SuppressWarnings("unchecked")
public T getInherited(String name, T defaultValue) {
Class type;
if (defaultValue == null) {
type = null;
} else {
// special handling in case the default value implements one
// of the interface types supported by the convertToType method
type = (Class) defaultValue.getClass();
}
T value = getInherited(name, type);
if (value == null) {
value = defaultValue;
}
return value;
}
// --------------------------------------------------< protected >---
protected T getParentPageValue(final String innerPath, final String name, final Class type) {
if (resource == null) {
return null;
}
// go up ancestors (allow empty paths)
Resource parent = ResourceUtil.getParent(resource);
boolean isContentNode = ResourceUtil.getName(resource).equals(JcrConstants.JCR_CONTENT);
if (parent == null) {
parent = getNextExistingParent(resource);
if (parent == null) {
// reached the root, but nothing was found
return null;
}
isContentNode = false;
}
// if we aren't the jcr:content child node ourself...
if (!isContentNode) {
// ...check jcr:content subnode of any hierarchy node
ResourceResolver resolver = parent.getResourceResolver();
Resource content = resolver.getResource(parent, JcrConstants.JCR_CONTENT);
if (content != null) {
// look up innerPath
Resource innerResource = resolver.getResource(content, innerPath);
// get from that value map
T value = ResourceUtil.getValueMap(innerResource).get(name, type);
if (value != null) {
return value;
}
}
}
// now check the parent
return new HierarchyNodeInheritanceValueMap(parent).getParentPageValue(innerPath, name, type);
}
/**
* Returns the page local path (aka localstruct). For example:
* /some/page/jcr:content/par/comp => par/comp
* @param resource resource whose page local path is returned
* @return page local path
*/
protected static String getInnerPath(Resource resource) {
if (resource == null) {
return ".";
}
final String resPath = resource.getPath();
int pos = resPath.indexOf(JcrConstants.JCR_CONTENT + "/");
if (pos <= 0) {
return ".";
}
return resPath.substring(pos + JcrConstants.JCR_CONTENT.length() + 1);
}
/**
* Returns the next existing ancestor. Normally this is the parent,
* but if the resource (and one or more of its parents) does not exist,
* this will walk up the path node by node to find the first existing
* ancestor. Returns null for the parent of the root "/".
* @param resource {@link Resource} whose next existing ancestor is to be found.
* @return next existing ancestor
*/
protected static Resource getNextExistingParent(Resource resource) {
ResourceResolver resolver = resource.getResourceResolver();
String path = resource.getPath();
do {
path = ResourceUtil.getParent(path);
// reached root => stop
if (path == null) {
return null;
}
resource = resolver.getResource(path);
} while (resource == null);
return resource;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy