com.btmatthews.atlas.jcr.impl.JCRTemplate Maven / Gradle / Ivy
/*
* Copyright 2011-2012 Brian Thomas Matthews
*
* 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.btmatthews.atlas.jcr.impl;
import com.btmatthews.atlas.jcr.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;
import javax.jcr.*;
import javax.jcr.query.Query;
import javax.jcr.query.QueryManager;
import javax.jcr.query.QueryResult;
import java.math.BigDecimal;
import java.net.URI;
import java.net.URISyntaxException;
import java.text.MessageFormat;
import java.util.*;
import java.util.regex.Pattern;
/**
* @author Brian Thomas Matthews
* @since 1.0.0
*/
public class JCRTemplate implements JCRAccessor {
private final static String BORROW_SESSION_RETURNED_NULL = "SessionFactory#getSession(String) returned null";
private final static String GET_ROOT_NODE_RETURNED_NULL = "Session#getRootNode() returned null.";
private final static String GET_NODE_RETURNED_NULL = "Session#getNode(String) returned null";
private final static String GET_NODE_BY_IDENTIFIER_RETURNED_NULL = "Session#getNodeByIdentifier(String) returned null";
private final static String GET_WORKSPACE_RETURNED_NULL = "Session#getWorkspace() returned null";
private final static String GET_QUERY_MANAGER_RETURNED_NULL = "Workspace#getQueryManager() return null";
private final static String CREATE_QUERY_RETURNED_NULL = "QueryManager#createQuery(String, String) returned null";
private final static String EXECUTE_RETURNED_NULL = "Query#execute() returned null";
private final static String GET_NODES_RETURNED_NULL = "QueryResutlt#getNodes() returned null";
private final static String NEXT_NODE_RETURNED_NULL = "NodeIterator#nextNode() returned null";
private final static String GET_VALUE_FACTORY_RETURNED_NULL = "Session#getValueFactory() returned null";
private final static String UNSUPPORTED_PARAMETER_TYPE = "Parameter type not supported. name={0}, class={1}";
private final static String WORKSPACE_PATTERN = ".+";
private final static String ID_PATTERN = "[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}";
private final static String PATH_PATTERN = ".+";
private final static String QUERY_PATTERN = ".+";
private final static String LANGUAGE_PATTERN = "(JCR-SQL2)|(JCR-JQOM)";
private static final Logger LOGGER = LoggerFactory.getLogger(JCRTemplate.class);
private static final Map EMPTY_PARAMETERS = new HashMap();
private SessionFactory sessionFactory;
private CredentialsProvider credentialsProvider;
/**
* The default constructor.
*/
public JCRTemplate() {
}
/**
* Initialise the JCR template with a session factory.
*
* @param factory The session factory.
*/
public JCRTemplate(final SessionFactory factory) {
sessionFactory = factory;
}
/**
* Initialise the JCR template with a session factory and a credentials provider.
*
* @param factory The session factory.
* @param provider The credentials provider.
*/
public JCRTemplate(final SessionFactory factory, final CredentialsProvider provider) {
sessionFactory = factory;
credentialsProvider = provider;
}
/**
* Used to inject the session pool.
*
* @param pool The session pool.
*/
public void setSessionFactory(final SessionFactory pool) {
sessionFactory = pool;
}
/**
* Used to inject the credentials provider.
*
* @param provider The credentials provider.
*/
public void setCredentialsProvider(final CredentialsProvider provider) {
credentialsProvider = provider;
}
/**
* Determine if the node contains the named property.
*
* @param node The node.
* @param name The property name.
* @return {@code true} if the node contains the named property. {@code false} otherwise.
*/
public boolean hasProperty(final Node node, final String name) {
try {
return node.hasProperty(name);
} catch (final RepositoryException e) {
throw new RepositoryAccessException(e.getMessage(), e);
}
}
/**
* Determine if the node contains all the named properties.
*
* @param node The node.
* @param names The property names.
* @return {@code true} if the node contains the named property. {@code false} otherwise.
*/
public boolean hasProperties(final Node node, final String... names) {
for (final String name : names) {
if (!hasProperty(node, name)) {
return false;
}
}
return true;
}
public Binary getBinaryProperty(final Node node, final String name) {
return getBinaryProperty(node, name, null);
}
public Binary getBinaryProperty(final Node node, final String name, final Binary defaultValue) {
try {
return node.getProperty(name).getBinary();
} catch (final PathNotFoundException e) {
return defaultValue;
} catch (final RepositoryException e) {
throw new RepositoryAccessException(e.getMessage(), e);
}
}
public BigDecimal getBigDecimalProperty(final Node node, final String name) {
return getBigDecimalProperty(node, name, null);
}
public BigDecimal getBigDecimalProperty(final Node node, final String name, final BigDecimal defaultValue) {
try {
return node.getProperty(name).getDecimal();
} catch (final PathNotFoundException e) {
return defaultValue;
} catch (final RepositoryException e) {
throw new RepositoryAccessException(e.getMessage(), e);
}
}
public Boolean getBooleanProperty(final Node node, final String name) {
return getBooleanProperty(node, name, null);
}
public Boolean getBooleanProperty(final Node node, final String name, final Boolean defaultValue) {
try {
return node.getProperty(name).getBoolean();
} catch (final PathNotFoundException e) {
return defaultValue;
} catch (final RepositoryException e) {
throw new RepositoryAccessException(e.getMessage(), e);
}
}
public Calendar getCalendarProperty(final Node node, final String name) {
return getCalendarProperty(node, name, null);
}
public Calendar getCalendarProperty(final Node node, final String name, final Calendar defaultValue) {
try {
return node.getProperty(name).getDate();
} catch (final PathNotFoundException e) {
return defaultValue;
} catch (final RepositoryException e) {
throw new RepositoryAccessException(e.getMessage(), e);
}
}
public Double getDoubleProperty(final Node node, final String name) {
return getDoubleProperty(node, name, null);
}
public Double getDoubleProperty(final Node node, final String name, final Double defaultValue) {
try {
return node.getProperty(name).getDouble();
} catch (final PathNotFoundException e) {
return defaultValue;
} catch (final RepositoryException e) {
throw new RepositoryAccessException(e.getMessage(), e);
}
}
public Long getLongProperty(final Node node, final String name) {
return getLongProperty(node, name, null);
}
public Long getLongProperty(final Node node, final String name, final Long defaultValue) {
try {
return node.getProperty(name).getLong();
} catch (final PathNotFoundException e) {
return defaultValue;
} catch (final RepositoryException e) {
throw new RepositoryAccessException(e.getMessage(), e);
}
}
public String getPathProperty(final Node node, final String name) {
return getPathProperty(node, name, null);
}
public String getPathProperty(final Node node, final String name, final String defaultValue) {
try {
return node.getProperty(name).getString();
} catch (final PathNotFoundException e) {
return defaultValue;
} catch (final RepositoryException e) {
throw new RepositoryAccessException(e.getMessage(), e);
}
}
public Node getReferenceProperty(final Node node, final String name) {
return getReferenceProperty(node, name, null);
}
public Node getReferenceProperty(final Node node, final String name, final Node defaultValue) {
try {
return node.getProperty(name).getNode();
} catch (final PathNotFoundException e) {
return defaultValue;
} catch (final RepositoryException e) {
throw new RepositoryAccessException(e.getMessage(), e);
}
}
public String getStringProperty(final Node node, final String name) {
return getStringProperty(node, name, null);
}
public String getStringProperty(final Node node, final String name, final String defaultValue) {
try {
return node.getProperty(name).getString();
} catch (final PathNotFoundException e) {
return defaultValue;
} catch (final RepositoryException e) {
throw new RepositoryAccessException(e.getMessage(), e);
}
}
public URI getURIProperty(final Node node, final String name) {
return getURIProperty(node, name, null);
}
public URI getURIProperty(final Node node, final String name, final URI defaultValue) {
try {
return new URI(node.getProperty(name).getString());
} catch (final PathNotFoundException e) {
return defaultValue;
} catch (final RepositoryException e) {
throw new RepositoryAccessException(e.getMessage(), e);
} catch (final URISyntaxException e) {
throw new RepositoryAccessException(e.getMessage(), e);
}
}
public Node getOrCreateNode(final Node node,
final String leafType,
final String name) {
try {
if (node.hasNode(name)) {
return node.getNode(name);
} else {
return node.addNode(name, leafType);
}
} catch (RepositoryException e) {
throw new RepositoryAccessException(e.getMessage(), e);
}
}
public Node getOrCreateNode(final Node node,
final String intermediateType,
final String leafType,
final String path) {
return getOrCreateNode(node, intermediateType, leafType, StringUtils.split(path, "/"));
}
public Node getOrCreateNode(final Node node,
final String intermediateType,
final String leafType,
final String... names) {
Node parent = node;
int i = 0;
while (i < names.length - 1) {
parent = getOrCreateNode(parent, intermediateType, names[i++]);
}
return getOrCreateNode(parent, leafType, names[i]);
}
/**
* Execute a function on the root node of the named workspace.
*
* @param workspaceName The workspace name.
* @param callback The callback that implements the function to be executed.
* @param The type returned by the function.
* @return The result returned by the function.
*/
public T withRoot(final String workspaceName,
final NodeCallback callback) {
return withSession(workspaceName, session -> {
final Node node = session.getRootNode();
if (node == null) {
throw new RepositoryAccessException(GET_ROOT_NODE_RETURNED_NULL);
}
return callback.doInSessionWithNode(session, node);
});
}
/**
* Execute a function on a node at the specified path in the named workspace.
*
* @param workspaceName The named workspace.
* @param path The path to the node.
* @param callback The callback that implements the function to be executed.
* @param The type returned by the function.
* @return The result of the function.
*/
public T withNodePath(final String workspaceName,
final String path,
final NodeCallback callback) {
return withNodePath(
workspaceName,
path,
callback,
JCRTemplate::defaultNotFoundCallback,
JCRTemplate::defaultErrorCallback);
}
public T withNodePath(final String workspaceName,
final String path,
final NodeCallback found,
final ErrorCallback notFound) {
return withNodePath(
workspaceName,
path,
found,
notFound,
JCRTemplate::defaultErrorCallback);
}
public T withNodePath(final String workspaceName,
final String path,
final NodeCallback found,
final ErrorCallback notFound,
final ErrorCallback error) {
assert workspaceName != null && Pattern.matches(WORKSPACE_PATTERN, workspaceName);
assert path != null && Pattern.matches(PATH_PATTERN, path);
assert found != null;
assert notFound != null;
assert error != null;
return withSession(
workspaceName,
session -> {
try {
final Node node = session.getNode(path);
return found.doInSessionWithNode(session, node);
} catch (PathNotFoundException e) {
return notFound.doInSessionWithException(session, e);
} catch (final RepositoryException e) {
return error.doInSessionWithException(session, e);
}
}
);
}
/**
* Perform a callback operation on the node identified by {@code id} in the workspace named {@code workspaceName}
* and return the result of the callback operation to the caller.
*
* @param workspaceName The name of the workspace.
* @param id The identifier of the node.
* @param found The callback.
* @param The type returned by the callback operation.
* @return The result of the callback operation.
*/
public T withNodeId(final String workspaceName,
final String id,
final NodeCallback found) {
return withNodeId(
workspaceName,
id,
found,
JCRTemplate::defaultNotFoundCallback,
JCRTemplate::defaultErrorCallback);
}
public T withNodeId(final String workspaceName,
final String id,
final NodeCallback found,
final ErrorCallback notFound) {
return withNodeId(workspaceName,
id,
found,
notFound,
JCRTemplate::defaultErrorCallback);
}
public T withNodeId(final String workspaceName,
final String id,
final NodeCallback found,
final ErrorCallback notFound,
final ErrorCallback error) {
assert workspaceName != null && Pattern.matches(WORKSPACE_PATTERN, workspaceName);
assert id != null && Pattern.matches(ID_PATTERN, id);
assert found != null;
assert notFound != null;
assert error != null;
return withSession(workspaceName, session -> {
try {
final Node node = session.getNodeByIdentifier(id);
return found.doInSessionWithNode(session, node);
} catch (final PathNotFoundException e) {
return notFound.doInSessionWithException(session, e);
} catch (final RepositoryException e) {
return error.doInSessionWithException(session, e);
}
});
}
private static T defaultNotFoundCallback(final Session session,
final Exception e)
throws Exception {
throw new RepositoryAccessException(GET_NODE_RETURNED_NULL);
}
private static T defaultErrorCallback(final Session session,
final Exception e)
throws Exception {
throw e;
}
/**
* @param workspaceName The name of the workspace.
* @param callback The callback that implements the function to be executed.
* @param The type returned by the function.
* @return The result of the function.
*/
public T withSession(final String workspaceName,
final SessionCallback callback) {
assert workspaceName != null && Pattern.matches(WORKSPACE_PATTERN, workspaceName);
assert callback != null;
try {
final Session session = sessionFactory.getSession(workspaceName);
if (session == null) {
throw new RepositoryAccessException(BORROW_SESSION_RETURNED_NULL);
}
try {
if (credentialsProvider == null) {
return callback.doInSession(session);
} else {
final Credentials credentials = credentialsProvider.getUserCredentials();
if (credentials == null) {
return callback.doInSession(session);
} else {
final Session impersonatedSession = session.impersonate(credentials);
try {
return callback.doInSession(impersonatedSession);
} finally {
impersonatedSession.logout();
}
}
}
} finally {
sessionFactory.releaseSession(workspaceName, session);
}
} catch (final RepositoryAccessException e) {
LOGGER.debug(e.getMessage(), e);
throw e;
} catch (final Exception e) {
final String message = e.getMessage();
LOGGER.debug(message, e);
throw new RepositoryAccessException(message, e);
}
}
/**
* @param workspaceName The name of the workspace.
* @param statement The query statement.
* @param language The query language.
* @param callback The callback operation to be performed on each item in the query result.
* @param offset The offset in the query result to start processing.
* @param limit The maximum number of items to process.
* @param The type returned by the callback operation.
* @return A {@link List} containing the callback results.
* @throws RepositoryAccessException If there was an error executing the query or processing the results.
*/
public List withQueryResults(final String workspaceName,
final String statement,
final String language,
final NodeCallback callback,
final long offset,
final long limit) {
assert workspaceName != null && Pattern.matches(WORKSPACE_PATTERN, workspaceName);
assert statement != null && Pattern.matches(QUERY_PATTERN, statement);
assert language != null && Pattern.matches(LANGUAGE_PATTERN, language);
assert callback != null;
assert offset >= 0;
assert limit > 0;
return withSession(workspaceName,
session -> {
final NodeIterator iterator = getQueryResults(session, statement, language, EMPTY_PARAMETERS, offset, limit);
final List results = new ArrayList<>((int) iterator.getSize());
while (iterator.hasNext()) {
final Node node = iterator.nextNode();
if (node == null) {
throw new RepositoryAccessException(NEXT_NODE_RETURNED_NULL);
}
final T result = callback.doInSessionWithNode(session, node);
results.add(result);
}
return results;
}
);
}
/**
* Create and execute a query returning an iterator that can be used to iterate through a subset of the query results.
*
* @param session The JCR session.
* @param statement The query statement.
* @param language The query language.
* @param parameters Query parameters.
* @param offset The starting offset in the result set.
* @param limit The maximum number of records to return from the result set.
* @return A {@link NodeIterator} that can be used to iterate through the subset of the query results.
* @throws RepositoryException Thrown by the JCR API operations if there is an error.
* @throws RepositoryAccessException If there was an unexpected result from a JCR API operation.
*/
private NodeIterator getQueryResults(final Session session,
final String statement,
final String language,
final Map parameters,
final long offset,
final long limit) throws RepositoryException {
assert session != null;
assert statement != null && Pattern.matches(QUERY_PATTERN, statement);
assert language != null && Pattern.matches(LANGUAGE_PATTERN, language);
assert offset >= 0;
assert limit > 0;
final Workspace workspace = session.getWorkspace();
if (workspace == null) {
throw new RepositoryAccessException(GET_WORKSPACE_RETURNED_NULL);
}
final QueryManager queryManager = workspace.getQueryManager();
if (queryManager == null) {
throw new RepositoryAccessException(GET_QUERY_MANAGER_RETURNED_NULL);
}
final Query query = queryManager.createQuery(statement, language);
if (query == null) {
throw new RepositoryAccessException(CREATE_QUERY_RETURNED_NULL);
}
query.setOffset(offset);
query.setLimit(limit);
if (!parameters.isEmpty()) {
final ValueFactory valueFactory = session.getValueFactory();
if (valueFactory == null) {
throw new RepositoryAccessException(GET_VALUE_FACTORY_RETURNED_NULL);
}
for (final Map.Entry parameter : parameters.entrySet()) {
bindValue(query, valueFactory, parameter.getKey(), parameter.getValue());
}
}
final QueryResult queryResult = query.execute();
if (queryResult == null) {
throw new RepositoryAccessException(EXECUTE_RETURNED_NULL);
}
final NodeIterator iterator = queryResult.getNodes();
if (iterator == null) {
throw new RepositoryAccessException(GET_NODES_RETURNED_NULL);
}
return iterator;
}
private void bindValue(final Query query,
final ValueFactory valueFactory,
final String name,
final Object value)
throws RepositoryException {
if (value instanceof String) {
query.bindValue(name, valueFactory.createValue((String) value));
} else {
throw new RepositoryAccessException(MessageFormat.format(UNSUPPORTED_PARAMETER_TYPE, name, value.getClass().getSimpleName()));
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy