ResourceType.java
/*
* #%L
* wcm.io
* %%
* Copyright (C) 2014 wcm.io
* %%
* 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.
* #L%
*/
package io.wcm.sling.commons.resource;
import java.util.HashSet;
import java.util.Set;
import org.apache.commons.lang3.StringUtils;
import org.apache.sling.api.SlingException;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import com.day.cq.wcm.api.components.Component;
import com.day.cq.wcm.api.components.ComponentManager;
/**
* Helper methods for resource type path handling.
*/
public final class ResourceType {
private ResourceType() {
// utility methods only
}
/**
* /apps prefix for resource types
* @deprecated Search paths are confurable and should not be hard-coded.
*/
@Deprecated(since = "1.1.0")
public static final String APPS_PREFIX = "/apps/";
/**
* /libs prefix for resource types
* @deprecated Search paths are confurable and should not be hard-coded.
*/
@Deprecated(since = "1.1.0")
public static final String LIBS_PREFIX = "/libs/";
/**
* Converts the resource type to an absolute path. If it does not start with "/" the resource is resolved
* via search paths using resource resolver. If not matching resource is found it is returned unchanged.
* @param resourceType Resource type
* @param resourceResolver Resource resolver
* @return Absolute resource type
*/
public static @NotNull String makeAbsolute(@NotNull String resourceType, @NotNull ResourceResolver resourceResolver) {
if (StringUtils.isEmpty(resourceType) || StringUtils.startsWith(resourceType, "/")) {
return resourceType;
}
// first try to resolve path via component manager - because on publish instance the original resource may not accessible
ComponentManager componentManager = resourceResolver.adaptTo(ComponentManager.class);
if (componentManager != null) {
Component component = componentManager.getComponent(resourceType);
if (component != null) {
return component.getPath();
}
else {
return resourceType;
}
}
// otherwise use resource resolver directly
Resource resource = resourceResolver.getResource(resourceType);
if (resource != null) {
return resource.getPath();
}
else {
return resourceType;
}
}
/**
* Makes the given resource type relative by stripping off any search path prefix.
* In case the given resource type does not start with any of these prefixes it is returned unmodified.
* @param resourceType The resource type to make relative.
* @param resourceResolver Resource resolver
* @return Relative resource type
*/
public static @NotNull String makeRelative(@NotNull String resourceType, @NotNull ResourceResolver resourceResolver) {
String[] searchPaths = resourceResolver.getSearchPath();
for (String prefix : searchPaths) {
if (StringUtils.startsWith(resourceType, prefix)) {
return resourceType.substring(prefix.length());
}
}
return resourceType;
}
/**
* Makes the given resource type relative by stripping off an /apps/ or /libs/ prefix.
* In case the given resource type does not start with any of these prefixes it is returned unmodified.
* This method does not take the real configured search paths into account, but in case of AEM usually only /apps/ and
* /libs/ are used.
* @param resourceType The resource type to make relative.
* @return Relative resource type
* @deprecated Please use {@link #makeRelative(String, ResourceResolver)} instead.
*/
@Deprecated(since = "1.1.0")
public static @NotNull String makeRelative(@NotNull String resourceType) {
if (StringUtils.startsWith(resourceType, APPS_PREFIX)) {
return resourceType.substring(APPS_PREFIX.length());
}
else if (StringUtils.startsWith(resourceType, LIBS_PREFIX)) {
return resourceType.substring(LIBS_PREFIX.length());
}
return resourceType;
}
/**
* Returns <code>true</code> if the given resource type are equal.
* In case the value of any of the given resource types starts with /apps/ or /libs/ prefix this is removed before
* doing the comparison.
* @param resourceType A resource type
* @param anotherResourceType Another resource type to compare with
* @param resourceResolver Resource resolver
* @return <code>true</code> if the resource type equals the given resource type.
*/
public static boolean equals(@NotNull String resourceType, @NotNull String anotherResourceType,
@NotNull ResourceResolver resourceResolver) {
return StringUtils.equals(makeRelative(resourceType, resourceResolver), makeRelative(anotherResourceType, resourceResolver));
}
/**
* Returns <code>true</code> if the given resource type are equal.
* In case the value of any of the given resource types starts with /apps/ or /libs/ prefix this is removed before
* doing the comparison.
* @param resourceType A resource type
* @param anotherResourceType Another resource type to compare with
* @return <code>true</code> if the resource type equals the given resource type.
* @deprecated Please use {@link #equals(String, String, ResourceResolver)} instead.
*/
@Deprecated(since = "1.1.0")
public static boolean equals(@NotNull String resourceType, @NotNull String anotherResourceType) {
return StringUtils.equals(makeRelative(resourceType), makeRelative(anotherResourceType));
}
/**
* Returns <code>true</code> if the resource type or any of the resource's super type(s) equals the given resource
* type.
* This implementation is equal to {@link ResourceResolver#isResourceType(Resource, String)} - but in earlier sling
* version the comparison check did not take potentieal mixtures of relative and absolute resource types into account.
* This method respects this.
* @param resource The resource to check
* @param resourceType The resource type to check this resource against.
* @return <code>true</code> if the resource type or any of the resource's super type(s) equals the given resource
* type. <code>false</code> is also returned if <code>resource</code> or<code>resourceType</code> are
* <code>null</code>.
*/
public static boolean is(@Nullable Resource resource, @Nullable String resourceType) {
if (resource == null || resourceType == null) {
return false;
}
ResourceResolver resolver = resource.getResourceResolver();
// Check if the resource is of the given type. This method first checks the
// resource type of the resource, then its super resource type and continues
// to go up the resource super type hierarchy.
boolean result = false;
if (ResourceType.equals(resourceType, resource.getResourceType(), resource.getResourceResolver())) {
result = true;
}
else {
Set<String> superTypesChecked = new HashSet<>();
String superType = resolver.getParentResourceType(resource);
while (!result && superType != null) {
if (ResourceType.equals(resourceType, superType, resource.getResourceResolver())) {
result = true;
}
else {
superTypesChecked.add(superType);
superType = resolver.getParentResourceType(superType);
if (superType != null && superTypesChecked.contains(superType)) {
throw new SlingException("Cyclic dependency for resourceSuperType hierarchy detected on resource " + resource.getPath(), null);
}
}
}
}
return result;
}
}