View Javadoc
1   package org.argeo.connect.util;
2   
3   import java.util.ArrayList;
4   import java.util.List;
5   
6   import javax.jcr.ItemNotFoundException;
7   import javax.jcr.Node;
8   import javax.jcr.NodeIterator;
9   import javax.jcr.Property;
10  import javax.jcr.PropertyIterator;
11  import javax.jcr.PropertyType;
12  import javax.jcr.Repository;
13  import javax.jcr.RepositoryException;
14  import javax.jcr.RepositoryFactory;
15  import javax.jcr.Session;
16  import javax.jcr.SimpleCredentials;
17  import javax.jcr.Value;
18  import javax.jcr.ValueFactory;
19  import javax.jcr.nodetype.NodeType;
20  
21  import org.apache.commons.logging.Log;
22  import org.apache.commons.logging.LogFactory;
23  import org.argeo.connect.ConnectException;
24  import org.argeo.jcr.JcrUtils;
25  import org.argeo.node.NodeUtils;
26  
27  /** Centralize convenience methods to manage a remote JCR repository */
28  public class RemoteJcrUtils {
29  	private final static Log log = LogFactory.getLog(RemoteJcrUtils.class);
30  
31  	/**
32  	 * Copy a node from the remote repository to the local repository, including
33  	 * all sub nodes. The target "toNode" must already exists in transient
34  	 * state.
35  	 * 
36  	 * @param fromNode
37  	 *            the node to be copied in the remote repository
38  	 * @param toNode
39  	 *            the target node in the local repository
40  	 */
41  	public static void copy(Node fromNode, Node toNode, boolean copyChildren) {
42  		try {
43  			if (toNode.getDefinition().isProtected())
44  				return;
45  
46  			// Mixins
47  			for (NodeType mixinType : fromNode.getMixinNodeTypes()) {
48  				toNode.addMixin(mixinType.getName());
49  			}
50  
51  			// Properties
52  			PropertyIterator pit = fromNode.getProperties();
53  			properties: while (pit.hasNext()) {
54  				Property fromProperty = pit.nextProperty();
55  				String propertyName = fromProperty.getName();
56  				if (toNode.hasProperty(propertyName) && toNode.getProperty(propertyName).getDefinition().isProtected())
57  					continue properties;
58  
59  				if (fromProperty.getDefinition().isProtected())
60  					continue properties;
61  
62  				if (propertyName.equals("jcr:created") || propertyName.equals("jcr:createdBy")
63  						|| propertyName.equals("jcr:lastModified") || propertyName.equals("jcr:lastModifiedBy"))
64  					continue properties;
65  
66  				if (PropertyType.REFERENCE == fromProperty.getType()
67  						|| PropertyType.WEAKREFERENCE == fromProperty.getType()) {
68  					copyReference(fromProperty, toNode);
69  				} else if (fromProperty.isMultiple())
70  					toNode.setProperty(propertyName, fromProperty.getValues());
71  				else
72  					toNode.setProperty(propertyName, fromProperty.getValue());
73  			}
74  
75  			// Child nodes
76  			if (copyChildren) {
77  				NodeIterator nit = fromNode.getNodes();
78  				while (nit.hasNext()) {
79  					Node fromChild = nit.nextNode();
80  					Integer index = fromChild.getIndex();
81  					String nodeRelPath = fromChild.getName() + "[" + index + "]";
82  					Node toChild;
83  					if (toNode.hasNode(nodeRelPath))
84  						toChild = toNode.getNode(nodeRelPath);
85  					else
86  						toChild = toNode.addNode(fromChild.getName(), fromChild.getPrimaryNodeType().getName());
87  					copy(fromChild, toChild, true);
88  				}
89  			}
90  			if (toNode.isNodeType(NodeType.MIX_LAST_MODIFIED))
91  				JcrUtils.updateLastModified(toNode);
92  			if (log.isTraceEnabled())
93  				log.trace("Copied " + toNode);
94  		} catch (RepositoryException e) {
95  			throw new ConnectException("Cannot copy " + fromNode + " to " + toNode, e);
96  		}
97  	}
98  
99  	public static void copyReference(Property fromProperty, Node toNode) throws RepositoryException {
100 		String propertyName = fromProperty.getName();
101 		if (fromProperty.isMultiple()) {
102 			Value[] vals = fromProperty.getValues();
103 			List<Node> toNodes = new ArrayList<Node>();
104 			values: for (Value val : vals) {
105 				String fromRefJcrId = val.getString();
106 				Node oldReferencedNode = null;
107 				try {
108 					oldReferencedNode = fromProperty.getSession().getNodeByIdentifier(fromRefJcrId);
109 				} catch (ItemNotFoundException e) {
110 					log.warn("Cannot resolve reference for multi-valued property " + fromProperty + " with ID "
111 							+ fromRefJcrId + ". Corresponding value has not been copied.");
112 					continue values;
113 				}
114 				String oldRefPath = oldReferencedNode.getPath();
115 				Session toSession = toNode.getSession();
116 				if (toSession.nodeExists(oldRefPath))
117 					toNodes.add(toSession.getNode(oldRefPath));
118 				else
119 					log.warn("Node with path: " + oldRefPath + " does not exist in target repository. "
120 							+ " Reference on this node while copying property " + fromProperty + " has been ignored.");
121 			}
122 			if (!toNodes.isEmpty())
123 				setMultipleReferences(toNode, propertyName, toNodes);
124 		} else {
125 			String oldRefPath = fromProperty.getNode().getPath();
126 			Session toSession = toNode.getSession();
127 			if (toSession.nodeExists(oldRefPath)) {
128 				Node newRef = toSession.getNode(oldRefPath);
129 				// log.warn("Skiping ref prop copy: " + fromProperty.getPath());
130 				toNode.setProperty(propertyName, newRef);
131 			} else
132 				log.warn("Cannot resolve reference for property " + fromProperty.getPath()
133 						+ ". It has not been copied.");
134 		}
135 	}
136 
137 	public static void setMultipleReferences(Node node, String propertyName, List<Node> nodes)
138 			throws RepositoryException {
139 		ValueFactory vFactory = node.getSession().getValueFactory();
140 		int size = nodes.size();
141 		Value[] values = new Value[size];
142 		int i = 0;
143 		for (Node currNode : nodes) {
144 			Value val = vFactory.createValue(currNode.getIdentifier(), PropertyType.REFERENCE);
145 			values[i++] = val;
146 		}
147 		node.setProperty(propertyName, values);
148 	}
149 
150 	/**
151 	 * Wraps session opening on a remote repository. The caller must close the
152 	 * session
153 	 */
154 	public static Session getSessionOnRemote(RepositoryFactory repositoryFactory, String repoUrl, String wkspName,
155 			String login, char[] pwd) throws RepositoryException {
156 		Repository remoteRepo = NodeUtils.getRepositoryByUri(repositoryFactory, repoUrl);
157 		SimpleCredentials sc = new SimpleCredentials(login, pwd);
158 		return remoteRepo.login(sc, wkspName);
159 	}
160 }