blob: 45a5753a20666c840d9bcb3510adf9a4987a33e3 [file] [log] [blame]
/*
* 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.jcr.resource;
import java.io.InputStream;
import java.lang.reflect.Array;
import java.math.BigDecimal;
import java.util.Calendar;
import java.util.StringTokenizer;
import javax.jcr.Node;
import javax.jcr.Property;
import javax.jcr.PropertyType;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.Value;
import javax.jcr.ValueFactory;
import javax.jcr.query.Query;
import javax.jcr.query.QueryManager;
import javax.jcr.query.QueryResult;
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.jcr.resource.internal.helper.LazyInputStream;
import org.slf4j.LoggerFactory;
/**
* The <code>JcrResourceUtil</code> class provides helper methods used
* throughout this bundle.
*
* @deprecated Use the Resource API instead.
*/
@Deprecated
public class JcrResourceUtil {
private static volatile boolean LOG_DEPRECATED_QUERY = true;
private static volatile boolean LOG_DEPRECATED_TO_JAVA_OBJECT_1 = true;
private static volatile boolean LOG_DEPRECATED_TO_JAVA_OBJECT_2 = true;
private static volatile boolean LOG_DEPRECATED_CREATE_VALUE = true;
private static volatile boolean LOG_DEPRECATED_SET_PROPERTY = true;
private static volatile boolean LOG_DEPRECATED_CREATE_PATH_1 = true;
private static volatile boolean LOG_DEPRECATED_CREATE_PATH_2 = true;
private static volatile boolean LOG_DEPRECATED_GET_RST_1 = true;
private static volatile boolean LOG_DEPRECATED_GET_RST_2 = true;
private static volatile boolean LOG_DEPRECATED_RT_TO_PATH = true;
/**
* Helper method to execute a JCR query.
*
* @param session the session
* @param query the query
* @param language the language
* @return the query's result
* @throws RepositoryException if the {@link QueryManager} cannot be retrieved
*/
public static QueryResult query(Session session, String query,
String language) throws RepositoryException {
if ( LOG_DEPRECATED_QUERY ) {
LOG_DEPRECATED_QUERY = false;
LoggerFactory.getLogger(JcrResourceUtil.class).warn("DEPRECATION WARNING: JcrResourceUtil.query is deprecated. Please use the resource resolver.");
}
QueryManager qManager = session.getWorkspace().getQueryManager();
Query q = qManager.createQuery(query, language);
return q.execute();
}
/**
* Converts a JCR Value to a corresponding Java Object
*
* @param value the JCR Value to convert
* @return the Java Object
* @throws RepositoryException if the value cannot be converted
*/
public static Object toJavaObject(Value value) throws RepositoryException {
if ( LOG_DEPRECATED_TO_JAVA_OBJECT_1 ) {
LOG_DEPRECATED_TO_JAVA_OBJECT_1 = false;
LoggerFactory.getLogger(JcrResourceUtil.class).warn("DEPRECATION WARNING: JcrResourceUtil.toJavaObject(Value) is deprecated. Please use the resource resolver API.");
}
switch (value.getType()) {
case PropertyType.DECIMAL:
return value.getDecimal();
case PropertyType.BINARY:
return new LazyInputStream(value);
case PropertyType.BOOLEAN:
return value.getBoolean();
case PropertyType.DATE:
return value.getDate();
case PropertyType.DOUBLE:
return value.getDouble();
case PropertyType.LONG:
return value.getLong();
case PropertyType.NAME: // fall through
case PropertyType.PATH: // fall through
case PropertyType.REFERENCE: // fall through
case PropertyType.STRING: // fall through
case PropertyType.UNDEFINED: // not actually expected
default: // not actually expected
return value.getString();
}
}
/**
* Converts the value(s) of a JCR Property to a corresponding Java Object.
* If the property has multiple values the result is an array of Java
* Objects representing the converted values of the property.
*
* @param property the property to be converted to the corresponding Java Object
* @throws RepositoryException if the conversion cannot take place
* @return the Object resulting from the conversion
*/
public static Object toJavaObject(Property property)
throws RepositoryException {
if ( LOG_DEPRECATED_TO_JAVA_OBJECT_2 ) {
LOG_DEPRECATED_TO_JAVA_OBJECT_2 = false;
LoggerFactory.getLogger(JcrResourceUtil.class).warn("DEPRECATION WARNING: JcrResourceUtil.toJavaObject(Property) is deprecated. Please use the resource resolver API.");
}
// multi-value property: return an array of values
if (property.isMultiple()) {
Value[] values = property.getValues();
final Object firstValue = values.length > 0 ? toJavaObject(values[0]) : null;
final Object[] result;
if ( firstValue instanceof Boolean ) {
result = new Boolean[values.length];
} else if ( firstValue instanceof Calendar ) {
result = new Calendar[values.length];
} else if ( firstValue instanceof Double ) {
result = new Double[values.length];
} else if ( firstValue instanceof Long ) {
result = new Long[values.length];
} else if ( firstValue instanceof BigDecimal) {
result = new BigDecimal[values.length];
} else if ( firstValue instanceof InputStream) {
result = new Object[values.length];
} else {
result = new String[values.length];
}
for (int i = 0; i < values.length; i++) {
Value value = values[i];
if (value != null) {
result[i] = toJavaObject(value);
}
}
return result;
}
// single value property
return toJavaObject(property.getValue());
}
/**
* Creates a {@link javax.jcr.Value JCR Value} for the given object with
* the given Session.
* Selects the the {@link javax.jcr.PropertyType PropertyType} according
* the instance of the object's Class
*
* @param value object
* @param session to create value for
* @return the value or null if not convertible to a valid PropertyType
* @throws RepositoryException in case of error, accessing the Repository
*/
public static Value createValue(final Object value, final Session session)
throws RepositoryException {
if ( LOG_DEPRECATED_CREATE_VALUE ) {
LOG_DEPRECATED_CREATE_VALUE = false;
LoggerFactory.getLogger(JcrResourceUtil.class).warn("DEPRECATION WARNING: JcrResourceUtil.createValue is deprecated. Please use the resource resolver API.");
}
Value val;
ValueFactory fac = session.getValueFactory();
if(value instanceof Calendar) {
val = fac.createValue((Calendar)value);
} else if (value instanceof InputStream) {
val = fac.createValue(fac.createBinary((InputStream)value));
} else if (value instanceof Node) {
val = fac.createValue((Node)value);
} else if (value instanceof BigDecimal) {
val = fac.createValue((BigDecimal)value);
} else if (value instanceof Long) {
val = fac.createValue((Long)value);
} else if (value instanceof Short) {
val = fac.createValue((Short)value);
} else if (value instanceof Integer) {
val = fac.createValue((Integer)value);
} else if (value instanceof Number) {
val = fac.createValue(((Number)value).doubleValue());
} else if (value instanceof Boolean) {
val = fac.createValue((Boolean) value);
} else if ( value instanceof String ) {
val = fac.createValue((String)value);
} else {
val = null;
}
return val;
}
/**
* Sets the value of the property.
* Selects the {@link javax.jcr.PropertyType PropertyType} according
* to the instance of the object's class.
* @param node The node where the property will be set on.
* @param propertyName The name of the property.
* @param propertyValue The value for the property.
* @throws RepositoryException if the property cannot be set
*/
public static void setProperty(final Node node,
final String propertyName,
final Object propertyValue)
throws RepositoryException {
if ( LOG_DEPRECATED_SET_PROPERTY ) {
LOG_DEPRECATED_SET_PROPERTY = false;
LoggerFactory.getLogger(JcrResourceUtil.class).warn("DEPRECATION WARNING: JcrResourceUtil.setProperty is deprecated. Please use the resource resolver API.");
}
if ( propertyValue == null ) {
node.setProperty(propertyName, (String)null);
} else if ( propertyValue.getClass().isArray() ) {
final int length = Array.getLength(propertyValue);
final Value[] setValues = new Value[length];
for(int i=0; i<length; i++) {
final Object value = Array.get(propertyValue, i);
setValues[i] = createValue(value, node.getSession());
}
node.setProperty(propertyName, setValues);
} else {
node.setProperty(propertyName, createValue(propertyValue, node.getSession()));
}
}
/**
* Helper method, which returns the given resource type as returned from the
* {@link org.apache.sling.api.resource.Resource#getResourceType()} as a
* relative path.
*
* @param type The resource type to be converted into a path
* @return The resource type as a path.
* @deprecated Use {@link ResourceUtil#resourceTypeToPath(String)}
*/
@Deprecated
public static String resourceTypeToPath(String type) {
if ( LOG_DEPRECATED_RT_TO_PATH ) {
LOG_DEPRECATED_RT_TO_PATH = false;
LoggerFactory.getLogger(JcrResourceUtil.class).warn("DEPRECATION WARNING: JcrResourceUtil.resourceTypeToPath is deprecated. Please use the resource resolver API.");
}
return type.replaceAll("\\:", "/");
}
/**
* Returns the super type of the given resource type. This is the result of
* adapting the child resource
* {@link JcrResourceConstants#SLING_RESOURCE_SUPER_TYPE_PROPERTY} of the
* <code>Resource</code> addressed by the <code>resourceType</code> to a
* string. If no such child resource exists or if the resource does not
* adapt to a string, this method returns <code>null</code>.
*
* @param resourceResolver The <code>ResourceResolver</code> used to
* access the resource whose path (relative or absolute) is given
* by the <code>resourceType</code> parameter.
* @param resourceType The resource type whose super type is to be returned.
* This type is turned into a path by calling the
* {@link #resourceTypeToPath(String)} method before trying to
* get the resource through the <code>resourceResolver</code>.
* @return the super type of the <code>resourceType</code> or
* <code>null</code> if the resource type does not have a child
* resource
* {@link JcrResourceConstants#SLING_RESOURCE_SUPER_TYPE_PROPERTY}
* adapting to a string.
* @deprecated Use {@link ResourceUtil#getResourceSuperType(ResourceResolver, String)}
*/
@SuppressWarnings("deprecation")
@Deprecated
public static String getResourceSuperType(
ResourceResolver resourceResolver, String resourceType) {
if ( LOG_DEPRECATED_GET_RST_1) {
LOG_DEPRECATED_GET_RST_1 = false;
LoggerFactory.getLogger(JcrResourceUtil.class).warn("DEPRECATION WARNING: JcrResourceUtil.getResourceSuperType(String) is deprecated. Please use the resource resolver API.");
}
return ResourceUtil.getResourceSuperType(resourceResolver, resourceType);
}
/**
* Returns the resource super type of the given resource. This is either the
* child resource
* {@link JcrResourceConstants#SLING_RESOURCE_SUPER_TYPE_PROPERTY} if the
* given <code>resource</code> adapted to a string or the result of
* calling the {@link #getResourceSuperType(ResourceResolver, String)}
* method on the resource type of the <code>resource</code>.
* <p>
* This mechanism allows to specifically set the resource super type on a
* per-resource level overwriting any resource super type hierarchy
* pre-defined by the actual resource type of the resource.
*
* @param resource The <code>Resource</code> whose resource super type is
* requested.
* @return The resource super type or <code>null</code> if the algorithm
* described above does not yield a resource super type.
* @deprecated Call {@link ResourceUtil#findResourceSuperType(Resource)}
*/
@SuppressWarnings("deprecation")
@Deprecated
public static String getResourceSuperType(Resource resource) {
if ( LOG_DEPRECATED_GET_RST_2) {
LOG_DEPRECATED_GET_RST_2 = false;
LoggerFactory.getLogger(JcrResourceUtil.class).warn("DEPRECATION WARNING: JcrResourceUtil.getResourceSuperType(Resource) is deprecated. Please use the resource resolver API.");
}
String resourceSuperType = resource.getResourceSuperType();
if ( resourceSuperType == null ) {
final ResourceResolver resolver = resource.getResourceResolver();
// try explicit resourceSuperType resource
final String resourceType = resource.getResourceType();
resourceSuperType = ResourceUtil.getResourceSuperType(resolver, resourceType);
}
return resourceSuperType;
}
/**
* Creates or gets the {@link javax.jcr.Node Node} at the given Path.
* In case it has to create the Node all non-existent intermediate path-elements
* will be create with the given intermediate node type and the returned node
* will be created with the given nodeType
*
* @param path to create
* @param intermediateNodeType to use for creation of intermediate nodes (or null)
* @param nodeType to use for creation of the final node (or null)
* @param session to use
* @param autoSave Should save be called when a new node is created?
* @return the Node at path
* @throws RepositoryException in case of exception accessing the Repository
*/
public static Node createPath(String path,
String intermediateNodeType,
String nodeType,
Session session,
boolean autoSave)
throws RepositoryException {
if ( LOG_DEPRECATED_CREATE_PATH_1 ) {
LOG_DEPRECATED_CREATE_PATH_1 = false;
LoggerFactory.getLogger(JcrResourceUtil.class).warn("DEPRECATION WARNING: JcrResourceUtil.createPath(String, ...) is deprecated. Please use the resource resolver API.");
}
if (path == null || path.length() == 0 || "/".equals(path)) {
return session.getRootNode();
}
// sanitize path if it ends with a slash
if ( path.endsWith("/") ) {
path = path.substring(0, path.length() - 1);
}
if (!session.itemExists(path)) {
String existingPath = findExistingPath(path, session);
String relativePath = null;
Node parentNode = null;
if (existingPath != null) {
parentNode = session.getNode(existingPath);
relativePath = path.substring(existingPath.length() + 1);
} else {
relativePath = path.substring(1);
parentNode = session.getRootNode();
}
return createPath(parentNode,
relativePath,
intermediateNodeType,
nodeType,
autoSave);
} else {
return session.getNode(path);
}
}
/**
* Creates or gets the {@link javax.jcr.Node Node} at the given Path.
* In case it has to create the Node all non-existent intermediate path-elements
* will be create with the given intermediate node type and the returned node
* will be created with the given nodeType
*
* @param parentNode starting node
* @param relativePath to create
* @param intermediateNodeType to use for creation of intermediate nodes (or null)
* @param nodeType to use for creation of the final node (or null)
* @param autoSave Should save be called when a new node is created?
* @return the Node at path
* @throws RepositoryException in case of exception accessing the Repository
*/
public static Node createPath(Node parentNode,
String relativePath,
String intermediateNodeType,
String nodeType,
boolean autoSave)
throws RepositoryException {
if ( LOG_DEPRECATED_CREATE_PATH_2 ) {
LOG_DEPRECATED_CREATE_PATH_2 = false;
LoggerFactory.getLogger(JcrResourceUtil.class).warn("DEPRECATION WARNING: JcrResourceUtil.createPath(Node,...) is deprecated. Please use the resource resolver API.");
}
if (relativePath == null || relativePath.length() == 0 || "/".equals(relativePath)) {
return parentNode;
}
// sanitize path if it ends with a slash
if ( relativePath.endsWith("/") ) {
relativePath = relativePath.substring(0, relativePath.length() - 1);
}
if (!parentNode.hasNode(relativePath)) {
Session session = parentNode.getSession();
String path = parentNode.getPath() + "/" + relativePath;
String existingPath = findExistingPath(path, session);
if (existingPath != null) {
parentNode = session.getNode(existingPath);
relativePath = path.substring(existingPath.length() + 1);
}
Node node = parentNode;
int pos = relativePath.lastIndexOf('/');
if ( pos != -1 ) {
final StringTokenizer st = new StringTokenizer(relativePath.substring(0, pos), "/");
while ( st.hasMoreTokens() ) {
final String token = st.nextToken();
if ( !node.hasNode(token) ) {
try {
if ( intermediateNodeType != null ) {
node.addNode(token, intermediateNodeType);
} else {
node.addNode(token);
}
if ( autoSave ) session.save();
} catch (RepositoryException re) {
// we ignore this as this folder might be created from a different task
session.refresh(false);
}
}
node = node.getNode(token);
}
relativePath = relativePath.substring(pos + 1);
}
if ( !node.hasNode(relativePath) ) {
if ( nodeType != null ) {
node.addNode(relativePath, nodeType);
} else {
node.addNode(relativePath);
}
if ( autoSave ) session.save();
}
return node.getNode(relativePath);
} else {
return parentNode.getNode(relativePath);
}
}
private static String findExistingPath(String path, Session session)
throws RepositoryException {
//find the parent that exists
// we can start from the youngest child in tree
int currentIndex = path.lastIndexOf('/');
String temp = path;
String existingPath = null;
while (currentIndex > 0) {
temp = temp.substring(0, currentIndex);
//break when first existing parent is found
if (session.itemExists(temp)) {
existingPath = temp;
break;
}
currentIndex = temp.lastIndexOf("/");
}
return existingPath;
}
}