]> git.argeo.org Git - gpl/argeo-slc.git/blob - AkbJcrUtils.java
b7d0ba7df6ebf49729538e32e165ab70837c8045
[gpl/argeo-slc.git] / AkbJcrUtils.java
1 package org.argeo.slc.akb.utils;
2
3 import java.util.ArrayList;
4 import java.util.List;
5 import java.util.Map;
6 import java.util.TreeMap;
7
8 import javax.jcr.Node;
9 import javax.jcr.NodeIterator;
10 import javax.jcr.Property;
11 import javax.jcr.PropertyIterator;
12 import javax.jcr.Repository;
13 import javax.jcr.RepositoryException;
14 import javax.jcr.Session;
15 import javax.jcr.Value;
16 import javax.jcr.query.Row;
17 import javax.jcr.query.RowIterator;
18
19 import org.argeo.jcr.JcrUtils;
20 import org.argeo.jcr.PropertyDiff;
21 import org.argeo.slc.akb.AkbException;
22 import org.argeo.slc.akb.AkbNames;
23 import org.argeo.slc.akb.AkbTypes;
24
25 /** Some static utils methods that might be factorized in a near future */
26 public class AkbJcrUtils {
27
28 // /////////////////////////
29 // SPECIFIC METHOS
30 /**
31 * Returns the list of environment templates that are visible for the
32 * current user.
33 */
34 public static List<Node> getDefinedTemplate(Session session) {
35 try {
36 if (session.nodeExists(AkbNames.AKB_TEMPLATES_BASE_PATH)) {
37 NodeIterator ni = session.getNode(
38 AkbNames.AKB_TEMPLATES_BASE_PATH).getNodes();
39 List<Node> templates = new ArrayList<Node>();
40 while (ni.hasNext()) {
41 Node currN = ni.nextNode();
42 if (currN.isNodeType(AkbTypes.AKB_ENV_TEMPLATE))
43 templates.add(currN);
44 }
45 return templates;
46 }
47 return null;
48 } catch (RepositoryException re) {
49 throw new AkbException("Unable to list templates", re);
50 }
51 }
52
53 /**
54 * Returns a template given it's name
55 */
56 public static Node getTemplateByName(Session session, String name) {
57 try {
58 if (name == null)
59 return null;
60 if (session.nodeExists(AkbNames.AKB_TEMPLATES_BASE_PATH)) {
61 NodeIterator ni = session.getNode(
62 AkbNames.AKB_TEMPLATES_BASE_PATH).getNodes();
63 while (ni.hasNext()) {
64 Node currN = ni.nextNode();
65 if (name.equals(AkbJcrUtils.get(currN, Property.JCR_TITLE)))
66 return currN;
67 }
68 }
69 return null;
70 } catch (RepositoryException re) {
71 throw new AkbException("Unable to list templates", re);
72 }
73 }
74
75 /**
76 * Return the type of alias that must be used given current item type
77 */
78 public static String getAliasTypeForNode(Node itemTemplate) {
79 try {
80 if (itemTemplate.isNodeType(AkbTypes.AKB_JDBC_QUERY))
81 return AkbTypes.AKB_JDBC_CONNECTOR;
82 else if (itemTemplate.isNodeType(AkbTypes.AKB_SSH_COMMAND)
83 || itemTemplate.isNodeType(AkbTypes.AKB_SSH_FILE))
84 return AkbTypes.AKB_SSH_CONNECTOR;
85 else
86 throw new AkbException("No connector type define for node "
87 + itemTemplate);
88 } catch (RepositoryException re) {
89 throw new AkbException("Unable to login", re);
90 }
91 }
92
93 /**
94 * Return current template depending on the passed node
95 */
96 public static Node getCurrentTemplate(Node akbNode) {
97 try {
98 if (akbNode.getDepth() == 0)
99 // no base path for root node
100 return null;
101 Node parNode = akbNode.getParent();
102
103 while (parNode != null)
104 if (akbNode.isNodeType(AkbTypes.AKB_ENV_TEMPLATE))
105 return akbNode;
106 else if (parNode.getDepth() == 0)
107 // we found not fitting node
108 return null;
109 else {
110 akbNode = parNode;
111 parNode = parNode.getParent();
112 }
113 return null;
114 } catch (RepositoryException re) {
115 throw new AkbException("Unable to find template for node "
116 + akbNode, re);
117 }
118 }
119
120 /**
121 * Return the current env base path
122 */
123 public static String getCurrentEnvBasePath(Node akbNode) {
124 try {
125 if (akbNode.getDepth() == 0)
126 // no base path for root node
127 return null;
128
129 Node parNode = akbNode.getParent();
130
131 while (parNode != null)
132 if (akbNode.isNodeType(AkbTypes.AKB_ENV)
133 || akbNode.isNodeType(AkbTypes.AKB_ENV_TEMPLATE))
134 return akbNode.getPath();
135 else if (parNode.getDepth() == 0)
136 // we found not fitting node
137 return null;
138 else {
139 akbNode = parNode;
140 parNode = parNode.getParent();
141 }
142 return null;
143 } catch (RepositoryException re) {
144 throw new AkbException("Unable to login", re);
145 }
146 }
147
148 // //////////////////////////////////
149 // METHODS THAT CAN BE FACTORIZED
150 /**
151 * Call {@link Repository#login()} without exceptions (useful in super
152 * constructors and dependency injection).
153 */
154 public static Session login(Repository repository) {
155 try {
156 return repository.login();
157 } catch (RepositoryException re) {
158 throw new AkbException("Unable to login", re);
159 }
160 }
161
162 /**
163 * Convert a {@link rowIterator} to a list of {@link Node} given a selector
164 * name. It relies on the <code>Row.getNode(String selectorName)</code>
165 * method.
166 */
167 public static List<Node> rowIteratorToList(RowIterator rowIterator,
168 String selectorName) throws RepositoryException {
169 List<Node> nodes = new ArrayList<Node>();
170 while (rowIterator.hasNext()) {
171 Row row = rowIterator.nextRow();
172 if (row.getNode(selectorName) != null)
173 nodes.add(row.getNode(selectorName));
174 }
175 return nodes;
176 }
177
178 /**
179 * Check if a string is null or an empty string (a string with only spaces
180 * is considered as empty
181 */
182 public static boolean isEmptyString(String stringToTest) {
183 return stringToTest == null || "".equals(stringToTest.trim());
184 }
185
186 /**
187 * Check if a string is null or an empty string (a string with only spaces
188 * is considered as empty
189 */
190 public static boolean checkNotEmptyString(String string) {
191 return string != null && !"".equals(string.trim());
192 }
193
194 /**
195 * Wraps the versionMananger.isCheckedOut(path) method to adapt it to the
196 * current check in / check out policy.
197 *
198 * TODO : add management of check out by others.
199 */
200 public static boolean isNodeCheckedOut(Node node) {
201 try {
202 return node.getSession().getWorkspace().getVersionManager()
203 .isCheckedOut(node.getPath());
204 } catch (RepositoryException re) {
205 throw new AkbException("Unable to get check out status for node",
206 re);
207 }
208 }
209
210 /**
211 * For the time being, same as isNodeCheckedOut(Node node).
212 *
213 * TODO : add management of check out by others.
214 */
215 public static boolean isNodeCheckedOutByMe(Node node) {
216 return isNodeCheckedOut(node);
217 }
218
219 /**
220 * Wraps the versionMananger.checkedOut(path) method to adapt it to the
221 * current check in / check out policy.
222 *
223 * TODO : add management of check out by others.
224 */
225 public static void checkout(Node node) {
226 try {
227 node.getSession().getWorkspace().getVersionManager()
228 .checkout(node.getPath());
229 } catch (RepositoryException re) {
230 throw new AkbException("Unable to check out Node", re);
231 }
232 }
233
234 /**
235 * Wraps the versionMananger.checkedIn(path) method to adapt it to the
236 * current check in / check out policy.
237 *
238 * It also checked if the current entity has to be moved or not. TODO : add
239 * management of check out by others.
240 */
241 public static void saveAndCheckin(Node node) {
242 try {
243 JcrUtils.updateLastModified(node);
244 node.getSession().save();
245 node.getSession().getWorkspace().getVersionManager()
246 .checkin(node.getPath());
247 } catch (RepositoryException re) {
248 throw new AkbException("Unable to save and chek in node", re);
249 }
250 }
251
252 /**
253 * Wraps the versionMananger.checkedIn(path) method to adapt it to the
254 * current check in / check out policy.
255 *
256 * TODO : add management of check out by others. TODO : manage usecase where
257 * a node that has never been checked in (draft node) is canceled and thus
258 * must be deleted
259 */
260 public static void cancelAndCheckin(Node node) {
261 try {
262 String path = node.getPath();
263 Session session = node.getSession();
264 JcrUtils.discardUnderlyingSessionQuietly(node);
265 // if the node has never been saved, it does not exist anymore.
266 if (session.nodeExists(path))
267 session.getWorkspace().getVersionManager().checkin(path);
268 } catch (RepositoryException re) {
269 throw new AkbException("Unable to save and chek in node", re);
270 }
271 }
272
273 /**
274 * Concisely get the string value of a property. It returns an empty String
275 * rather than null if this node doesn't have this property or if the
276 * corresponding property is an empty string.
277 */
278 public static String get(Node node, String propertyName) {
279 try {
280 if (!node.hasProperty(propertyName))
281 return "";
282 else
283 return node.getProperty(propertyName).getString();
284 } catch (RepositoryException e) {
285 throw new AkbException("Cannot get property " + propertyName
286 + " of " + node, e);
287 }
288 }
289
290 /**
291 * Concisely get the value of a property or null if this node doesn't have
292 * this property
293 */
294 public static Boolean getBooleanValue(Node node, String propertyName) {
295 try {
296 if (!node.hasProperty(propertyName))
297 return null;
298 else
299 return node.getProperty(propertyName).getBoolean();
300 } catch (RepositoryException e) {
301 throw new AkbException("Cannot get boolean property "
302 + propertyName + " of " + node, e);
303 }
304 }
305
306 /**
307 * Concisely get the identifier of a node in Ui listener for instance
308 * */
309 public static String getIdentifierQuietly(Node node) {
310 try {
311 return node.getIdentifier();
312 } catch (RepositoryException e) {
313 throw new AkbException("Cannot get identifier for node " + node, e);
314 }
315 }
316
317 public static Map<String, PropertyDiff> diffProperties(Node reference,
318 Node observed) {
319 Map<String, PropertyDiff> diffs = new TreeMap<String, PropertyDiff>();
320 diffPropertiesLevel(diffs, null, reference, observed);
321 return diffs;
322 }
323
324 /**
325 * Compare the properties of two nodes. Extends
326 * <code>JcrUtils.diffPropertiesLevel</code> to also track differences in
327 * multiple value properties and sub graph. No property is skipped (among
328 * other all technical jcr:... properties) to be able to track jcr:title and
329 * description properties, among other. Filtering must be applied afterwards
330 * to only keep relevant properties.
331 */
332 static void diffPropertiesLevel(Map<String, PropertyDiff> diffs,
333 String baseRelPath, Node reference, Node observed) {
334 try {
335 // check removed and modified
336 PropertyIterator pit = reference.getProperties();
337 while (pit.hasNext()) {
338 Property p = pit.nextProperty();
339 String name = p.getName();
340 // if (name.startsWith("jcr:"))
341 // continue props;
342
343 if (!observed.hasProperty(name)) {
344 String relPath = propertyRelPath(baseRelPath, name);
345 PropertyDiff pDiff = new PropertyDiff(PropertyDiff.REMOVED,
346 relPath, p.getValue(), null);
347 diffs.put(relPath, pDiff);
348 } else {
349 if (p.isMultiple()) {
350 int i = 0;
351
352 Value[] refValues = p.getValues();
353 Value[] newValues = observed.getProperty(name)
354 .getValues();
355 String relPath = propertyRelPath(baseRelPath, name);
356 refValues: for (Value refValue : refValues) {
357 for (Value newValue : newValues) {
358 if (refValue.equals(newValue))
359 continue refValues;
360 }
361 PropertyDiff pDiff = new PropertyDiff(
362 PropertyDiff.REMOVED, relPath, refValue,
363 null);
364 diffs.put(relPath + "_" + i++, pDiff);
365 }
366
367 newValues: for (Value newValue : newValues) {
368 for (Value refValue : refValues) {
369 if (refValue.equals(newValue))
370 continue newValues;
371 }
372 PropertyDiff pDiff = new PropertyDiff(
373 PropertyDiff.ADDED, relPath, null, newValue);
374 diffs.put(relPath + "_" + i++, pDiff);
375 }
376
377 } else {
378 Value referenceValue = p.getValue();
379 Value newValue = observed.getProperty(name).getValue();
380 if (!referenceValue.equals(newValue)) {
381 String relPath = propertyRelPath(baseRelPath, name);
382 PropertyDiff pDiff = new PropertyDiff(
383 PropertyDiff.MODIFIED, relPath,
384 referenceValue, newValue);
385 diffs.put(relPath, pDiff);
386 }
387 }
388 }
389 }
390 // check added
391 pit = observed.getProperties();
392 // props:
393 while (pit.hasNext()) {
394 Property p = pit.nextProperty();
395 String name = p.getName();
396 // if (name.startsWith("jcr:"))
397 // continue props;
398 if (!reference.hasProperty(name)) {
399 String relPath = propertyRelPath(baseRelPath, name);
400 if (p.isMultiple()) {
401 Value[] newValues = observed.getProperty(name)
402 .getValues();
403 int i = 0;
404 for (Value newValue : newValues) {
405 PropertyDiff pDiff = new PropertyDiff(
406 PropertyDiff.ADDED, relPath, null, newValue);
407 diffs.put(relPath + "_" + i++, pDiff);
408 }
409 } else {
410 PropertyDiff pDiff = new PropertyDiff(
411 PropertyDiff.ADDED, relPath, null, p.getValue());
412 diffs.put(relPath, pDiff);
413 }
414 }
415 }
416 } catch (RepositoryException e) {
417 throw new AkbException("Cannot diff " + reference + " and "
418 + observed, e);
419 }
420 }
421
422 /** Builds a property relPath to be used in the diff. */
423 private static String propertyRelPath(String baseRelPath,
424 String propertyName) {
425 if (baseRelPath == null)
426 return propertyName;
427 else
428 return baseRelPath + '/' + propertyName;
429 }
430
431 /** prevent instantiation by others */
432 private AkbJcrUtils() {
433 }
434
435 }