package org.etk.orm.plugins.jcr;
import java.lang.reflect.Method;
import java.util.Iterator;
import java.util.List;
import java.util.RandomAccess;
import javax.jcr.Item;
import javax.jcr.ItemNotFoundException;
import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.PathNotFoundException;
import javax.jcr.Property;
import javax.jcr.PropertyIterator;
import javax.jcr.PropertyType;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.nodetype.NodeType;
import javax.jcr.nodetype.NodeTypeManager;
import javax.jcr.query.Query;
import javax.jcr.query.QueryManager;
import javax.jcr.query.QueryResult;
import org.etk.common.logging.Logger;
public class SessionWrapperImpl implements SessionWrapper {
/** . */
private static final Logger log = Logger.getLogger(SessionWrapperImpl.class);
/** . */
private Session session;
/** . */
private AbstractLinkManager[] linkMgrs;
/** . */
private SessionLifeCycle sessionLifeCycle;
/** . */
private final boolean hasPropertyOptimized;
/** . */
private final boolean hasNodeOptimized;
public SessionWrapperImpl(
SessionLifeCycle sessionLifeCycle,
Session session,
boolean hasPropertyOptimized,
boolean hasNodeOptimized) {
//
this.hasPropertyOptimized = hasPropertyOptimized;
this.hasNodeOptimized = hasNodeOptimized;
this.sessionLifeCycle = sessionLifeCycle;
this.session = session;
this.linkMgrs = new AbstractLinkManager[] {
new ReferenceLinkManager(session),
new PathLinkManager(session)
};
}
public Iterator<Property> getProperties(Node node) throws RepositoryException {
@SuppressWarnings("unchecked")
Iterator<Property> properties = node.getProperties();
return properties;
}
public Property getProperty(Node node, String relPath) throws RepositoryException {
if (hasPropertyOptimized) {
try {
return node.getProperty(relPath);
}
catch (PathNotFoundException e) {
return null;
}
} else {
if (node.hasProperty(relPath)) {
return node.getProperty(relPath);
} else {
return null;
}
}
}
public Node getNode(String path) throws RepositoryException {
try {
Item item = session.getItem(path);
if (item instanceof Node) {
return (Node)item;
}
}
catch (PathNotFoundException ignore) {
}
return null;
}
public Node getNode(Node node, String relPath) throws RepositoryException {
if (hasNodeOptimized) {
try {
return node.getNode(relPath);
}
catch (PathNotFoundException e) {
return null;
}
} else {
if (node.hasNode(relPath)) {
return node.getNode(relPath);
} else {
return null;
}
}
}
public NodeType getNodeType(String nodeTypeName) throws RepositoryException {
NodeTypeManager mgr = session.getWorkspace().getNodeTypeManager();
return mgr.getNodeType(nodeTypeName);
}
public Node addNode(Node parentNode, String relPath, String primartyNodeTypeName, List<String> mixinNodeTypeNames) throws RepositoryException {
Node childNode = parentNode.addNode(relPath, primartyNodeTypeName);
if (mixinNodeTypeNames instanceof RandomAccess) {
int size = mixinNodeTypeNames.size();
for (int i = 0;i < size;i++) {
String mixinNodeTypeName = mixinNodeTypeNames.get(i);
childNode.addMixin(mixinNodeTypeName);
}
} else {
for (String mixinNodeTypeName : mixinNodeTypeNames) {
childNode.addMixin(mixinNodeTypeName);
}
}
return childNode;
}
public void move(Node srcNode, Node dstNode, String dstName) throws RepositoryException {
String dstPath = dstNode.getPath() + "/" + dstName;
session.move(srcNode.getPath(), dstPath);
}
public void orderBefore(Node parentNode, Node srcNode, Node dstNode) throws RepositoryException {
if (dstNode != null) {
parentNode.orderBefore(srcNode.getName(), dstNode.getName());
} else {
long size = parentNode.getNodes().getSize();
if (size > 1) {
parentNode.orderBefore(srcNode.getName(), null);
}
}
}
public Node getNodeByUUID(String uuid) throws RepositoryException {
try {
return session.getNodeByUUID(uuid);
}
catch (ItemNotFoundException e) {
return null;
}
}
public Node getParent(Node childNode) throws RepositoryException {
return childNode.getParent();
}
public Iterator<Node> getChildren(Node parentNode) throws RepositoryException {
return (Iterator<Node>)parentNode.getNodes();
}
public Node getChild(Node parentNode, String name) throws RepositoryException {
if (parentNode.hasNode(name)) {
return parentNode.getNode(name);
} else {
return null;
}
}
/**
* Remove a node recursively in order to have one remove event generated for every descendants of the node in order to
* keep the contexts state corrects. It also remove all existing references to that node.
*
* @param node the node to remove
* @throws RepositoryException any repository exception
*/
public void remove(Node node) throws RepositoryException {
//
cleanReferencesForRemoval(node);
//
node.remove();
}
public boolean canAddMixin(Node node, String mixinTypeName) throws RepositoryException {
return node.canAddMixin(mixinTypeName);
}
public void addMixin(Node node, String mixinTypeName) throws RepositoryException {
node.addMixin(mixinTypeName);
}
public boolean haxMixin(Node node, String mixinTypeName) throws RepositoryException {
for (NodeType mixinNodeType : node.getMixinNodeTypes()) {
if (mixinNodeType.getName().equals(mixinTypeName)) {
return true;
}
}
return false;
}
/**
* Need to find a way to optimized this method as it forces us to visit the entire children hierarchy.
*
* @param node the node to be removed
* @throws RepositoryException any repository exception
*/
public void cleanReferencesForRemoval(Node node) throws RepositoryException {
for (NodeIterator i = node.getNodes(); i.hasNext();) {
Node child = i.nextNode();
cleanReferencesForRemoval(child);
}
// Cleanup
for (PropertyIterator i = node.getReferences(); i.hasNext();) {
Property property = i.nextProperty();
property.setValue((Node)null);
}
// Update reference manager
for (PropertyIterator i = node.getProperties(); i.hasNext();) {
Property property = i.nextProperty();
if (property.getType() == PropertyType.REFERENCE) {
linkMgrs[LinkType.REFERENCE.index].setReferenced(node, property.getName(), null);
} else if (property.getType() == PropertyType.PATH) {
linkMgrs[LinkType.PATH.index].setReferenced(node, property.getName(), null);
}
}
}
public void save() throws RepositoryException {
sessionLifeCycle.save(session);
for (AbstractLinkManager mgr : linkMgrs) {
mgr.clear();
}
}
public Node getReferenced(Node referent, String propertyName, LinkType linkType) throws RepositoryException {
return linkMgrs[linkType.index].getReferenced(referent, propertyName);
}
public Node setReferenced(Node referent, String propertyName, Node referenced, LinkType linkType) throws RepositoryException {
return linkMgrs[linkType.index].setReferenced(referent, propertyName, referenced);
}
public Iterator<Node> getReferents(Node referenced, String propertyName, LinkType linkType) throws RepositoryException {
return linkMgrs[linkType.index].getReferents(referenced, propertyName);
}
@Override
public int hashCode() {
return session.hashCode();
}
@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (obj instanceof SessionWrapperImpl) {
SessionWrapperImpl that = (SessionWrapperImpl)obj;
return session == that.session;
}
return false;
}
public Session getSession() {
return session;
}
public boolean isClosed()
{
return session == null;
}
public void close() {
if (session != null)
{
for (AbstractLinkManager mgr : linkMgrs) {
mgr.clear();
}
sessionLifeCycle.close(session);
session = null;
}
}
public Query createQuery(String statement) throws RepositoryException {
QueryManager queryMgr = session.getWorkspace().getQueryManager();
return queryMgr.createQuery(statement, Query.SQL);
}
public QueryResult executeQuery(Query query, Long offset, Long limit) throws RepositoryException {
if (offset != null && offset > 0)
{
invokeLongSetter(query, "setOffset", offset);
}
if (limit != null && limit >= 0)
{
invokeLongSetter(query, "setLimit", limit);
}
return query.execute();
}
public int hits(QueryResult result) throws RepositoryException
{
int hits = invokeIntGetter(result, "getTotalSize");
if (hits < 0)
{
hits = (int)result.getNodes().getSize();
}
return hits;
}
private int invokeIntGetter(Object o, String methodName)
{
Class<?> clazz = o.getClass();
int hits = -1;
try {
Method getter = clazz.getMethod(methodName);
Class<?> ret = getter.getReturnType();
if (ret.equals(int.class))
{
hits = (Integer)getter.invoke(o);
}
}
catch (NoSuchMethodException ignore) {
log.trace("Could not find method " + methodName + " on " + clazz.getName(), ignore);
}
catch (Exception e) {
log.error("Could not invoke " + methodName + " of class " + clazz.getName() + " on " + o, e);
}
return hits;
}
private void invokeLongSetter(Object o, String methodName, Long value)
{
Class<?> clazz = o.getClass();
try {
Method setter = clazz.getMethod(methodName, long.class);
setter.invoke(o, value);
}
catch (NoSuchMethodException ignore) {
log.trace("Could not find method " + methodName + " on " + clazz.getName(), ignore);
}
catch (Exception e) {
log.error("Could not invoke " + methodName + " of class " + clazz.getName() + " on " + o + " with value " + value, e);
}
}
}