1 package org.argeo.connect.util;
2
3 import java.math.BigDecimal;
4 import java.security.AccessControlException;
5 import java.text.SimpleDateFormat;
6 import java.util.ArrayList;
7 import java.util.Calendar;
8 import java.util.GregorianCalendar;
9 import java.util.List;
10
11 import javax.jcr.InvalidItemStateException;
12 import javax.jcr.ItemNotFoundException;
13 import javax.jcr.Node;
14 import javax.jcr.NodeIterator;
15 import javax.jcr.Property;
16 import javax.jcr.PropertyType;
17 import javax.jcr.Repository;
18 import javax.jcr.RepositoryException;
19 import javax.jcr.Session;
20 import javax.jcr.Value;
21 import javax.jcr.ValueFactory;
22 import javax.jcr.nodetype.NodeType;
23 import javax.jcr.query.Query;
24 import javax.jcr.query.QueryManager;
25 import javax.jcr.query.QueryResult;
26 import javax.jcr.query.Row;
27 import javax.jcr.query.RowIterator;
28 import javax.jcr.query.qom.Constraint;
29 import javax.jcr.query.qom.QueryObjectModelFactory;
30 import javax.jcr.query.qom.Selector;
31 import javax.jcr.query.qom.StaticOperand;
32 import javax.jcr.version.VersionManager;
33
34 import org.apache.commons.logging.Log;
35 import org.apache.commons.logging.LogFactory;
36 import org.argeo.connect.ConnectConstants;
37 import org.argeo.connect.ConnectException;
38 import org.argeo.eclipse.ui.EclipseUiUtils;
39 import org.argeo.jcr.JcrUtils;
40
41
42
43
44
45 public class ConnectJcrUtils {
46 private final static Log log = LogFactory.getLog(ConnectJcrUtils.class);
47
48 private final static String NS_JCR = "http://www.jcp.org/jcr/1.0";
49 private final static String NS_NT = "http://www.jcp.org/jcr/nt/1.0";
50
51
52
53
54
55
56
57
58
59 public static String getLocalJcrItemName(String name) {
60 String jcr = "{" + NS_JCR + "}";
61 String nt = "{" + NS_NT + "}";
62 if (name.startsWith(jcr))
63 return "jcr:" + name.substring(jcr.length());
64 else if (name.startsWith(nt))
65 return "nt:" + name.substring(nt.length());
66 else
67 throw new ConnectException("Unknown prefix for " + name);
68 }
69
70 public static String checkAndLocalizeNamespaces(String name) {
71 String jcr = "{" + NS_JCR + "}";
72 String nt = "{" + NS_NT + "}";
73 if (name.startsWith(jcr))
74 return "jcr:" + name.substring(jcr.length());
75 else if (name.startsWith(nt))
76 return "nt:" + name.substring(nt.length());
77 else
78 return name;
79 }
80
81 public static String cleanNodeName(String name) {
82 String cleanName = name.trim().replaceAll("[^a-zA-Z0-9-. _]", "");
83 return cleanName;
84 }
85
86
87
88
89
90 public final static char[] INVALID_NAME_CHARACTERS = { '/', ':', '[', ']', '|', '*', '?',
91
92
93 '<', '>', '&' };
94
95
96
97
98
99
100
101 public static String replaceInvalidChars(String name) {
102 return replaceInvalidChars(name, '_');
103 }
104
105
106
107
108
109
110
111 public static String replaceInvalidChars(String name, char replacement) {
112 boolean modified = false;
113 char[] arr = name.toCharArray();
114 for (int i = 0; i < arr.length; i++) {
115 char c = arr[i];
116 invalid: for (char invalid : INVALID_NAME_CHARACTERS) {
117 if (c == invalid) {
118 arr[i] = replacement;
119 modified = true;
120 break invalid;
121 }
122 }
123 }
124 if (modified)
125 return new String(arr);
126 else
127
128 return name;
129 }
130
131
132
133 public static String parentRelPath(String relPath) {
134
135 if (relPath.charAt(relPath.length() - 1) == '/')
136 relPath = relPath.substring(0, relPath.length() - 2);
137
138 int index = relPath.lastIndexOf('/');
139 if (index < 0)
140 return "";
141 else
142 return relPath.substring(0, index);
143 }
144
145
146 public static String lastRelPathElement(String relPath) {
147
148 if (relPath.charAt(relPath.length() - 1) == '/')
149 relPath = relPath.substring(0, relPath.length() - 2);
150
151 int index = relPath.lastIndexOf('/');
152 if (index < 0)
153 return relPath;
154 return relPath.substring(index + 1);
155 }
156
157 public static boolean canEdit(Node entity) {
158 boolean canEdit = false;
159 try {
160 entity.getSession().checkPermission(entity.getPath(), "add_node");
161 canEdit = true;
162 } catch (AccessControlException ace) {
163
164 } catch (RepositoryException e) {
165 throw new ConnectException("Unable to check permission on " + entity, e);
166 }
167 return canEdit;
168 }
169
170
171
172
173
174
175
176 public static Node getNodeFromElement(Object element, String selectorName) {
177 Node currNode;
178 if (element instanceof Row) {
179 Row currRow = (Row) element;
180 try {
181 if (selectorName != null)
182 currNode = currRow.getNode(selectorName);
183 else
184 currNode = currRow.getNode();
185 } catch (RepositoryException re) {
186 throw new ConnectException(
187 "Unable to retrieve Node with selector name " + selectorName + " on " + currRow, re);
188 }
189 } else if (element instanceof Node)
190 currNode = (Node) element;
191 else
192 throw new ConnectException("unsupported element type: " + element.getClass().getName());
193 return currNode;
194 }
195
196
197
198
199
200 public static Node getVersionableAncestor(Node node) {
201 try {
202 if (node.isNodeType(NodeType.MIX_VERSIONABLE))
203 return node;
204 else if (node.getPath().equals("/"))
205 return null;
206 else
207 return getVersionableAncestor(node.getParent());
208 } catch (RepositoryException re) {
209 throw new ConnectException("Unable to get check out status for node " + node, re);
210 }
211 }
212
213
214
215
216
217
218
219
220 public static boolean nodeStillExists(Node node) {
221 try {
222 node.getPath();
223 } catch (InvalidItemStateException iise) {
224 return false;
225 } catch (RepositoryException re) {
226 throw new ConnectException("Error while testing node existence", re);
227 }
228 return true;
229 }
230
231
232
233
234
235
236
237 public static boolean isNodeCheckedOut(Node node) {
238 try {
239 if (!node.isNodeType(NodeType.MIX_VERSIONABLE))
240 return true;
241 else
242 return node.getSession().getWorkspace().getVersionManager().isCheckedOut(node.getPath());
243 } catch (RepositoryException re) {
244 throw new ConnectException("Unable to get check out status for node " + node, re);
245 }
246 }
247
248
249
250
251
252 public static NodeIterator getNodesOfType(Session session, String parentPath, String nodeType) {
253 try {
254 if (parentPath == null)
255 parentPath = "/";
256 StringBuilder builder = new StringBuilder();
257 builder.append(XPathUtils.descendantFrom(parentPath));
258 builder.append("//element(*, ").append(nodeType).append(")");
259 Query query = session.getWorkspace().getQueryManager().createQuery(builder.toString(),
260 ConnectConstants.QUERY_XPATH);
261 return query.execute().getNodes();
262 } catch (RepositoryException re) {
263 throw new ConnectException("Unable to retrieve node of type " + nodeType + " under " + parentPath, re);
264 }
265 }
266
267 public static Node getByPropertyValue(Session session, String parentPath, String nodeType, String propName,
268 String propValue) {
269 NodeIterator nit = getByPropertyValue(session, parentPath, nodeType, propName, propValue, false);
270 if (nit != null && nit.hasNext())
271 return nit.nextNode();
272 else
273 return null;
274 }
275
276 public static NodeIterator getByPropertyValue(Session session, String parentPath, String nodeType, String propName,
277 String propValue, boolean acceptMultipleResult) {
278 try {
279 QueryManager queryManager = session.getWorkspace().getQueryManager();
280 String xpathQueryStr = XPathUtils.descendantFrom(parentPath) + "//element(*, "
281 + checkAndLocalizeNamespaces(nodeType) + ")";
282
283 String attrQuery = XPathUtils.getPropertyEquals(checkAndLocalizeNamespaces(propName), propValue);
284
285 xpathQueryStr += "[" + attrQuery + "]";
286
287
288 Query xpathQuery = queryManager.createQuery(xpathQueryStr, ConnectConstants.QUERY_XPATH);
289 QueryResult result = xpathQuery.execute();
290 NodeIterator ni = result.getNodes();
291
292 long niSize = ni.getSize();
293 if (niSize == 0)
294 return null;
295 else if (niSize > 1) {
296 if (acceptMultipleResult)
297 return ni;
298 else
299 throw new ConnectException("Found " + niSize + " entities of type " + nodeType + "with " + propName
300 + " =[" + propValue + "] under " + parentPath);
301 } else
302 return ni;
303 } catch (RepositoryException e) {
304 throw new ConnectException("Unable to retrieve entities of type " + nodeType + " with " + propName + " = ["
305 + propValue + "] under " + parentPath, e);
306 }
307 }
308
309
310 public static String getPropertyTypeAsString(Property prop) {
311 try {
312 return PropertyType.nameFromValue(prop.getType());
313 } catch (RepositoryException e) {
314 throw new ConnectException("Cannot check type for " + prop, e);
315 }
316 }
317
318
319
320
321
322
323
324
325
326
327 public static void updateLastModified(Node node, String userId) {
328 try {
329 if (!node.isNodeType(NodeType.MIX_LAST_MODIFIED))
330 node.addMixin(NodeType.MIX_LAST_MODIFIED);
331 node.setProperty(Property.JCR_LAST_MODIFIED, new GregorianCalendar());
332 node.setProperty(Property.JCR_LAST_MODIFIED_BY, userId);
333 } catch (RepositoryException e) {
334 throw new ConnectException("Cannot update last modified on " + node, e);
335 }
336 }
337
338
339
340
341
342
343 public static boolean isNodeCheckedOutByMe(Node node) {
344 return isNodeCheckedOut(node);
345 }
346
347
348
349
350
351 public static boolean saveAndPublish(Node node, boolean publish) {
352 try {
353 boolean changed = false;
354 Session session = node.getSession();
355 if (session.hasPendingChanges()) {
356 JcrUtils.updateLastModified(node);
357 session.save();
358 changed = true;
359 }
360 if (isVersionable(node) && publish) {
361 VersionManager vm = session.getWorkspace().getVersionManager();
362 String path = node.getPath();
363 vm.checkpoint(path);
364 } else if (publish && !isVersionable(node)) {
365 log.warn("Cannot publish unversionnable node at " + node.getPath());
366 }
367 return changed;
368 } catch (RepositoryException re) {
369 throw new ConnectException("Unable to perform check point on " + node, re);
370 }
371 }
372
373
374
375
376
377 public static boolean saveIfNecessary(Node node) {
378 boolean changed = false;
379 try {
380 Session session = node.getSession();
381 if (session.hasPendingChanges()) {
382 session.save();
383 changed = true;
384 }
385 return changed;
386 } catch (RepositoryException re) {
387 throw new ConnectException("Cannot save with node " + node, re);
388 }
389 }
390
391
392
393
394
395
396
397
398
399
400 public static void checkPoint(Session session, List<String> pathes, boolean updateLastModified) {
401 try {
402 VersionManager vm = session.getWorkspace().getVersionManager();
403 loop: for (String currPath : pathes) {
404 if (!session.nodeExists(currPath))
405 continue loop;
406 try {
407 Node currNode = session.getNode(currPath);
408 if (!currNode.isNodeType(NodeType.MIX_VERSIONABLE))
409 continue loop;
410
411 if (updateLastModified) {
412 JcrUtils.updateLastModified(currNode);
413 session.save();
414 }
415 vm.checkpoint(currPath);
416 } catch (RepositoryException re) {
417 throw new ConnectException("Unable to perform check point on " + currPath, re);
418 }
419 }
420 } catch (RepositoryException re) {
421 throw new ConnectException("Unexpected error when performing batch check point ", re);
422 }
423 }
424
425
426
427
428
429 public static boolean checkCOStatusBeforeUpdate(Node node) {
430 boolean wasCheckedOut = isNodeCheckedOutByMe(node);
431 if (!wasCheckedOut)
432 checkout(node);
433 return wasCheckedOut;
434 }
435
436
437
438
439
440 public static Node getParentVersionableNode(Node node) throws RepositoryException {
441 Node curr = node;
442 while (true) {
443 if (curr.isNodeType(NodeType.MIX_VERSIONABLE))
444 return curr;
445 try {
446 curr = curr.getParent();
447 } catch (ItemNotFoundException infe) {
448
449 return null;
450 }
451 }
452 }
453
454
455
456
457
458
459
460 public static Session login(Repository repository) {
461 try {
462 return repository.login();
463 } catch (RepositoryException re) {
464 throw new ConnectException("Unable to login", re);
465 }
466 }
467
468
469 public static Session getSession(Node node) {
470 try {
471 return node.getSession();
472 } catch (RepositoryException re) {
473 throw new ConnectException("Unable to retrieve session for node " + node, re);
474 }
475 }
476
477
478
479
480
481 public static Repository getRepository(Node node) {
482 try {
483 return node.getSession().getRepository();
484 } catch (RepositoryException re) {
485 throw new ConnectException("Unable to retrieve repository for node " + node, re);
486 }
487 }
488
489
490 public static String getIdentifier(Node node) {
491 try {
492 return node.getIdentifier();
493 } catch (RepositoryException re) {
494 throw new ConnectException("Unable to retrieve identifier for node " + node, re);
495 }
496 }
497
498
499 public static String getName(Node node) {
500 try {
501 return node.getName();
502 } catch (RepositoryException re) {
503 throw new ConnectException("Unable to retrieve name for node " + node, re);
504 }
505
506 }
507
508
509 public static String getPath(Node node) {
510 try {
511 return node.getPath();
512 } catch (RepositoryException re) {
513 throw new ConnectException("Unable to retrieve path for node " + node, re);
514 }
515 }
516
517
518 public static String getAbsPath(String parPath, String nodeName) {
519 String absPath = null;
520 if ("/".equals(parPath))
521 absPath = "/" + nodeName;
522 else
523 absPath = parPath + "/" + nodeName;
524 return absPath;
525 }
526
527
528 public static boolean itemExists(Session session, String absPath) {
529 try {
530 return session.itemExists(absPath);
531 } catch (RepositoryException re) {
532 throw new ConnectException("Unable to check existence of item at " + absPath, re);
533 }
534 }
535
536
537
538
539
540 public static Node getNodeByIdentifier(Session session, String identifier) {
541 try {
542 return session.getNodeByIdentifier(identifier);
543 } catch (RepositoryException re) {
544 throw new ConnectException("Unable to retrieve node by identifier with " + identifier, re);
545 }
546 }
547
548
549 public static Node getParent(Node child) {
550 try {
551 return child.getParent();
552 } catch (RepositoryException re) {
553 throw new ConnectException("Unable to retrieve parent node for " + child, re);
554 }
555 }
556
557
558
559
560
561
562 public static Node getNodeByIdentifier(Node sessionNode, String identifier) {
563 return getNodeByIdentifier(getSession(sessionNode), identifier);
564 }
565
566
567
568
569 public static Node getNode(Session session, String absPath) {
570 try {
571 return session.getNode(absPath);
572 } catch (RepositoryException re) {
573 throw new ConnectException("Unable to retrieve Node at path " + absPath, re);
574 }
575 }
576
577
578
579
580
581
582
583
584 public static Node getNode(Session session, String absParentPath, String... childRelPath) {
585 try {
586 if (EclipseUiUtils.isEmpty(absParentPath))
587 absParentPath = "/";
588 if (!session.itemExists(absParentPath))
589 throw new ConnectException("Node at " + absParentPath + " does not exist or is not visible");
590 StringBuilder builder = new StringBuilder();
591 for (String rp : childRelPath)
592 builder.append(rp).append("/");
593 String relPath = builder.substring(0, builder.length() - 1);
594 Node parent = session.getNode(absParentPath);
595 if (parent.hasNode(relPath))
596 return parent.getNode(relPath);
597 else
598 return null;
599 } catch (RepositoryException re) {
600 throw new ConnectException(
601 "Unable to retrieve Node at path " + absParentPath + " with child rel path " + childRelPath, re);
602 }
603 }
604
605
606
607
608 public static Node getNode(Row row, String selectorName) {
609 try {
610 if (selectorName == null)
611 return row.getNode();
612 else
613 return row.getNode(selectorName);
614 } catch (RepositoryException re) {
615 throw new ConnectException("Unable to retrieve Node with selector name " + selectorName + " on " + row, re);
616 }
617 }
618
619
620 public static boolean isNodeType(Node node, String nodeTypeName) {
621 try {
622 return node.isNodeType(nodeTypeName);
623 } catch (RepositoryException re) {
624 throw new ConnectException("Unable to test NodeType " + nodeTypeName + " for " + node, re);
625 }
626 }
627
628
629 public static String getPrimaryNodeType(Node node) {
630 try {
631 return node.getPrimaryNodeType().getName();
632 } catch (RepositoryException re) {
633 throw new ConnectException("Unable to retrieve node type name for " + node, re);
634 }
635 }
636
637
638 private static void checkout(Node node) {
639 try {
640 node.getSession().getWorkspace().getVersionManager().checkout(node.getPath());
641 } catch (RepositoryException re) {
642 throw new ConnectException("Unable to check out node " + node, re);
643 }
644 }
645
646
647 public static boolean isVersionable(Node node) {
648 try {
649 return node.isNodeType(NodeType.MIX_VERSIONABLE);
650 } catch (RepositoryException re) {
651 throw new ConnectException("Unable to test versionability of " + node, re);
652 }
653 }
654
655
656
657
658
659
660
661 public static String get(Node node, String propertyName) {
662 try {
663 if (!node.hasProperty(propertyName))
664 return "";
665 else
666 return node.getProperty(propertyName).getString();
667 } catch (RepositoryException e) {
668 throw new ConnectException("Cannot get property " + propertyName + " of " + node, e);
669 }
670 }
671
672
673
674
675
676 public static Long getLongValue(Node node, String propRelPath) {
677 try {
678 if (!node.hasProperty(propRelPath))
679 return null;
680 else
681 return node.getProperty(propRelPath).getLong();
682 } catch (RepositoryException e) {
683 throw new ConnectException("Cannot get long property " + propRelPath + " of " + node, e);
684 }
685 }
686
687
688
689
690
691 public static Double getDoubleValue(Node node, String propRelPath) {
692 try {
693 if (!node.hasProperty(propRelPath))
694 return null;
695 else
696 return node.getProperty(propRelPath).getDouble();
697 } catch (RepositoryException e) {
698 throw new ConnectException("Cannot get double property " + propRelPath + " of " + node, e);
699 }
700 }
701
702
703
704
705
706 public static Calendar getDateValue(Node node, String propRelPath) {
707 try {
708 if (!node.hasProperty(propRelPath))
709 return null;
710 else
711 return node.getProperty(propRelPath).getDate();
712 } catch (RepositoryException e) {
713 throw new ConnectException("Cannot get date property " + propRelPath + " of " + node, e);
714 }
715 }
716
717
718
719
720
721 public static Boolean getBooleanValue(Node node, String propertyName) {
722 try {
723 if (!node.hasProperty(propertyName))
724 return null;
725 else
726 return node.getProperty(propertyName).getBoolean();
727 } catch (RepositoryException e) {
728 throw new ConnectException("Cannot get boolean property " + propertyName + " of " + node, e);
729 }
730 }
731
732
733
734
735
736 public static String getDateFormattedAsString(Node node, String propertyName, String dateFormatPattern) {
737 try {
738 if (!node.hasProperty(propertyName))
739 return null;
740 else {
741 Calendar cal = node.getProperty(propertyName).getDate();
742 return new SimpleDateFormat(dateFormatPattern).format(cal.getTime());
743 }
744 } catch (RepositoryException e) {
745 throw new ConnectException("Cannot get date property " + propertyName + " on " + node, e);
746 }
747 }
748
749
750
751
752
753 public static Node getReference(Node node, String propName) {
754 try {
755 Node ref = null;
756 if (node.hasProperty(propName)) {
757 Property prop = node.getProperty(propName);
758 if (prop.getType() == PropertyType.REFERENCE) {
759 ref = prop.getNode();
760 }
761 }
762 return ref;
763 } catch (RepositoryException re) {
764 throw new ConnectException("Unable to get reference " + propName + " for node " + node, re);
765 }
766 }
767
768
769
770
771
772
773
774
775 public static boolean setJcrProperty(Node node, String propName, int propertyType, Object value) {
776 try {
777
778 if (value == null)
779 if (node.hasProperty(propName)) {
780 node.getProperty(propName).remove();
781 return true;
782 } else
783 return false;
784
785 switch (propertyType) {
786 case PropertyType.STRING:
787 String strValue = (String) value;
788 if (node.hasProperty(propName) && node.getProperty(propName).getString().equals(strValue))
789 return false;
790 else {
791 node.setProperty(propName, strValue);
792 return true;
793 }
794 case PropertyType.REFERENCE:
795 case PropertyType.WEAKREFERENCE:
796 Node nodeValue = (Node) value;
797 if (node.hasProperty(propName)
798 && nodeValue.getIdentifier().equals(node.getProperty(propName).getNode().getIdentifier()))
799 return false;
800 else {
801 node.setProperty(propName, nodeValue);
802 return true;
803 }
804 case PropertyType.BOOLEAN:
805 if (node.hasProperty(propName) && node.getProperty(propName).getBoolean() == (Boolean) value)
806 return false;
807 else {
808 node.setProperty(propName, (Boolean) value);
809 return true;
810 }
811 case PropertyType.DATE:
812 if (node.hasProperty(propName) && node.getProperty(propName).getDate().equals((Calendar) value))
813 return false;
814 else {
815 node.setProperty(propName, (Calendar) value);
816 return true;
817 }
818 case PropertyType.LONG:
819 Long lgValue = (Long) value;
820 if (node.hasProperty(propName) && node.getProperty(propName).getLong() == lgValue)
821 return false;
822 else {
823 node.setProperty(propName, lgValue);
824 return true;
825 }
826 case PropertyType.DOUBLE:
827 Double dbValue;
828 if (value instanceof Double)
829 dbValue = (Double) value;
830 else {
831 try {
832 dbValue = Double.parseDouble(value.toString());
833 } catch (NumberFormatException e) {
834 return false;
835 }
836 }
837 if (node.hasProperty(propName) && node.getProperty(propName).getDouble() == dbValue)
838 return false;
839 else {
840 node.setProperty(propName, dbValue);
841 return true;
842 }
843 case PropertyType.DECIMAL:
844 BigDecimal bdValue = (BigDecimal) value;
845 if (node.hasProperty(propName) && node.getProperty(propName).getDecimal() == bdValue)
846 return false;
847 else {
848 node.setProperty(propName, bdValue);
849 return true;
850 }
851 default:
852 throw new ConnectException("Update unimplemented for property type " + propertyType
853 + ". Unable to update property " + propName + " on " + node);
854 }
855 } catch (RepositoryException re) {
856 throw new ConnectException("Unexpected error while setting property " + propName + " on " + node, re);
857 }
858 }
859
860
861
862
863
864
865 public static void removeMultiPropertyValue(Node node, String propName, String stringToRemove) {
866 try {
867 boolean foundValue = false;
868
869 List<String> strings = new ArrayList<String>();
870 Value[] values = node.getProperty(propName).getValues();
871 for (int i = 0; i < values.length; i++) {
872 String curr = values[i].getString();
873 if (stringToRemove.equals(curr))
874 foundValue = true;
875 else
876 strings.add(curr);
877 }
878 if (foundValue)
879 node.setProperty(propName, strings.toArray(new String[0]));
880 } catch (RepositoryException e) {
881 throw new ConnectException(
882 "Unable to remove value " + stringToRemove + " for property " + propName + " of " + node, e);
883 }
884 }
885
886
887
888
889
890 public static String addMultiPropertyValue(Node node, String propName, String value) {
891 try {
892 Value[] values;
893 String[] valuesStr;
894 String errMsg = null;
895 if (node.hasProperty(propName)) {
896 values = node.getProperty(propName).getValues();
897
898
899 for (Value currVal : values) {
900 String curTagUpperCase = currVal.getString().toUpperCase().trim();
901 if (value.toUpperCase().trim().equals(curTagUpperCase)) {
902 errMsg = value + " is already in the list and thus could not be added.";
903 return errMsg;
904 }
905 }
906 valuesStr = new String[values.length + 1];
907 int i;
908 for (i = 0; i < values.length; i++) {
909 valuesStr[i] = values[i].getString();
910 }
911 valuesStr[i] = value;
912 } else {
913 valuesStr = new String[1];
914 valuesStr[0] = value;
915 }
916 node.setProperty(propName, valuesStr);
917 return null;
918 } catch (RepositoryException re) {
919 throw new ConnectException("Unable to set tags", re);
920 }
921 }
922
923
924
925
926
927 public static void setMultiValueStringPropFromString(Node node, String propName, String values, String separator) {
928 try {
929 if (notEmpty(values)) {
930 String[] valArray = values.split(separator);
931
932 List<String> newValList = new ArrayList<String>();
933 for (String currValue : valArray) {
934 if (notEmpty(currValue))
935 newValList.add(currValue);
936 }
937 node.setProperty(propName, newValList.toArray(new String[0]));
938 }
939 } catch (RepositoryException re) {
940 throw new ConnectException("Unable to set multi value property " + propName + " of node " + node
941 + " with values [" + values + "]", re);
942 }
943 }
944
945
946
947
948
949
950
951
952
953 public static String getMultiAsString(Node node, String propertyName, String separator) {
954 try {
955 if (separator == null)
956 separator = "; ";
957 if (!node.hasProperty(propertyName))
958 return "";
959 else {
960 Value[] values = node.getProperty(propertyName).getValues();
961 StringBuilder builder = new StringBuilder();
962 for (Value val : values) {
963 String currStr = val.getString();
964 if (notEmpty(currStr))
965 builder.append(currStr).append(separator);
966 }
967 if (builder.lastIndexOf(separator) >= 0)
968 return builder.substring(0, builder.length() - separator.length());
969 else
970 return builder.toString();
971 }
972 } catch (RepositoryException e) {
973 throw new ConnectException("Cannot get multi valued property " + propertyName + " of " + node, e);
974 }
975 }
976
977
978
979
980
981 public static List<String> getMultiAsList(Node node, String propertyName) {
982 List<String> results = new ArrayList<String>();
983 try {
984 if (propertyName == null)
985 return results;
986 if (!node.hasProperty(propertyName))
987 return results;
988 else {
989 Value[] values = node.getProperty(propertyName).getValues();
990 for (Value val : values) {
991 results.add(val.getString());
992 }
993 }
994 } catch (RepositoryException e) {
995 throw new ConnectException("Cannot get multi valued property " + propertyName + " of " + node, e);
996 }
997 return results;
998 }
999
1000
1001
1002
1003
1004 public static void setMultipleReferences(Node node, String propertyName, List<Node> nodes)
1005 throws RepositoryException {
1006 ValueFactory vFactory = node.getSession().getValueFactory();
1007 int size = nodes.size();
1008 Value[] values = new Value[size];
1009 int i = 0;
1010 for (Node currNode : nodes) {
1011 Value val = vFactory.createValue(currNode.getIdentifier(), PropertyType.REFERENCE);
1012 values[i++] = val;
1013 }
1014 node.setProperty(propertyName, values);
1015 }
1016
1017
1018 public static void removeRefFromMultiValuedProp(Node node, String propName, String identifier) {
1019 try {
1020 Session session = node.getSession();
1021 List<Node> nodes = new ArrayList<Node>();
1022 Value[] values = node.getProperty(propName).getValues();
1023 for (int i = 0; i < values.length; i++) {
1024 String curr = values[i].getString();
1025 if (!identifier.equals(curr))
1026 nodes.add(session.getNodeByIdentifier(curr));
1027 }
1028 setMultipleReferences(node, propName, nodes);
1029 } catch (RepositoryException e) {
1030 throw new ConnectException("Unable to remove reference from property " + propName + " of Node " + node, e);
1031 }
1032 }
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043 public static String addRefToMultiValuedProp(Node node, String propName, Node nodeToReference) {
1044 try {
1045 Session session = node.getSession();
1046 Value[] values;
1047 List<Node> nodes = new ArrayList<Node>();
1048 String errMsg = null;
1049 if (node.hasProperty(propName)) {
1050 values = node.getProperty(propName).getValues();
1051
1052 for (Value currValue : values) {
1053 String jcrId = currValue.getString();
1054 if (nodeToReference.getIdentifier().equals(jcrId)) {
1055 errMsg = ConnectJcrUtils.get(nodeToReference, Property.JCR_TITLE)
1056 + " is already in the list and thus could not be added.";
1057 return errMsg;
1058 } else
1059 nodes.add(session.getNodeByIdentifier(jcrId));
1060 }
1061 }
1062 nodes.add(nodeToReference);
1063 setMultipleReferences(node, propName, nodes);
1064 return null;
1065 } catch (RepositoryException re) {
1066 throw new ConnectException("Unable to add reference ", re);
1067 }
1068 }
1069
1070
1071
1072
1073
1074
1075
1076
1077 public static void orderReferenceBefore(Node node, String propName, Node sourceNode, Node targetNode) {
1078 try {
1079 Session session = node.getSession();
1080 String sourceId = sourceNode.getIdentifier();
1081 String targetId = null;
1082 if (targetNode != null)
1083 targetId = targetNode.getIdentifier();
1084
1085 Value[] values;
1086 List<Node> nodes = new ArrayList<Node>();
1087 if (node.hasProperty(propName)) {
1088 values = node.getProperty(propName).getValues();
1089
1090 for (Value currValue : values) {
1091 String jcrId = currValue.getString();
1092 if (sourceId.equals(jcrId)) {
1093
1094 } else if (jcrId.equals(targetId)) {
1095 nodes.add(session.getNodeByIdentifier(sourceId));
1096 nodes.add(session.getNodeByIdentifier(targetId));
1097 } else
1098 nodes.add(session.getNodeByIdentifier(jcrId));
1099 }
1100 if (targetId == null)
1101 nodes.add(session.getNodeByIdentifier(sourceId));
1102 }
1103 setMultipleReferences(node, propName, nodes);
1104 } catch (RepositoryException re) {
1105 throw new ConnectException("Unable to update node " + node + " to order " + sourceNode + " before "
1106 + targetNode + " in multi value reference property " + propName, re);
1107 }
1108 }
1109
1110
1111
1112
1113
1114
1115 public static boolean valueExists(Node node, String propName, String value) {
1116 try {
1117 value = value.trim().toLowerCase();
1118 if (node.hasProperty(propName)) {
1119 Value[] values = node.getProperty(propName).getValues();
1120 for (Value currVal : values) {
1121 String currStr = currVal.getString().trim().toLowerCase();
1122 if (value.equals(currStr))
1123 return true;
1124 }
1125 }
1126 return false;
1127 } catch (RepositoryException re) {
1128 throw new ConnectException("Unable to set tags", re);
1129 }
1130 }
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141 public static String addStringToMultiValuedProp(Node node, String propName, String value) {
1142 try {
1143 Value[] values;
1144 String[] valuesStr;
1145 String errMsg = null;
1146 if (node.hasProperty(propName)) {
1147 values = node.getProperty(propName).getValues();
1148
1149
1150 for (Value currVal : values) {
1151 String currStr = currVal.getString();
1152 if (value.equals(currStr)) {
1153 errMsg = value + " is already in the list and thus " + "could not be added.";
1154 return errMsg;
1155 }
1156 }
1157
1158 valuesStr = new String[values.length + 1];
1159 int i;
1160 for (i = 0; i < values.length; i++) {
1161 valuesStr[i] = values[i].getString();
1162 }
1163 valuesStr[i] = value;
1164 } else {
1165 valuesStr = new String[1];
1166 valuesStr[0] = value;
1167 }
1168 node.setProperty(propName, valuesStr);
1169 return null;
1170 } catch (RepositoryException re) {
1171 throw new ConnectException("Unable to set tags", re);
1172 }
1173 }
1174
1175
1176 public static void removeStringFromMultiValuedProp(Node node, String propName, String value) {
1177 try {
1178 if (node.hasProperty(propName)) {
1179 List<Value> nodes = new ArrayList<Value>();
1180 Value[] values = node.getProperty(propName).getValues();
1181 for (int i = 0; i < values.length; i++) {
1182 String curr = values[i].getString();
1183 if (!value.equals(curr))
1184 nodes.add(values[i]);
1185 }
1186 Value[] results = nodes.toArray(new Value[0]);
1187 node.setProperty(propName, results);
1188 }
1189 } catch (RepositoryException e) {
1190 throw new ConnectException("Unable to remove reference from property " + propName + " of Node " + node, e);
1191 }
1192 }
1193
1194
1195
1196
1197
1198 public static Node[] nodeIteratorToArray(NodeIterator nit) {
1199 Node[] nodes = new Node[(int) nit.getSize()];
1200 int i = 0;
1201 while (nit.hasNext()) {
1202 nodes[i++] = nit.nextNode();
1203 }
1204 return nodes;
1205 }
1206
1207
1208 public static Row[] rowIteratorToArray(RowIterator rit) {
1209 List<Row> rows = new ArrayList<Row>();
1210 while (rit.hasNext()) {
1211 rows.add(rit.nextRow());
1212 }
1213 return rows.toArray(new Row[rows.size()]);
1214 }
1215
1216
1217
1218
1219
1220
1221 public static Row[] rowIteratorToDistinctArray(RowIterator rit, String distinctSelectorName)
1222 throws RepositoryException {
1223 List<Row> rows = new ArrayList<Row>();
1224 List<String> jcrIds = new ArrayList<String>();
1225 while (rit.hasNext()) {
1226 Row curr = rit.nextRow();
1227 String currId = curr.getNode(distinctSelectorName).getIdentifier();
1228 if (jcrIds.contains(currId))
1229 ;
1230 else {
1231 jcrIds.add(currId);
1232 rows.add(curr);
1233 }
1234 }
1235 return rows.toArray(new Row[rows.size()]);
1236 }
1237
1238
1239
1240
1241
1242
1243 public static List<Node> rowIteratorToNodeList(RowIterator rowIterator, String selectorName)
1244 throws RepositoryException {
1245 List<Node> nodes = new ArrayList<Node>();
1246 while (rowIterator.hasNext()) {
1247 Row row = rowIterator.nextRow();
1248 if (row.getNode(selectorName) != null)
1249 nodes.add(row.getNode(selectorName));
1250 }
1251 return nodes;
1252 }
1253
1254
1255 public static String[] parseAndClean(String string, String regExp, boolean clean) {
1256 String[] temp = string.split(regExp);
1257 if (clean) {
1258 String[] cleanRes = new String[temp.length];
1259 int i = 0;
1260 for (String tag : temp) {
1261 cleanRes[i] = tag.trim();
1262 i++;
1263 }
1264 return cleanRes;
1265 }
1266 return temp;
1267 }
1268
1269
1270 public static String concatIfNotEmpty(String str1, String str2, String separator) {
1271 StringBuilder builder = new StringBuilder();
1272 if (notEmpty(str1))
1273 builder.append(str1);
1274
1275 if (notEmpty(str1) && notEmpty(str2))
1276 builder.append(separator);
1277
1278 if (notEmpty(str2))
1279 builder.append(str2);
1280 return builder.toString();
1281 }
1282
1283
1284
1285
1286
1287
1288 public static Constraint localAnd(QueryObjectModelFactory factory, Constraint defaultC, Constraint newC)
1289 throws RepositoryException {
1290 if (defaultC == null)
1291 return newC;
1292 else
1293 return factory.and(defaultC, newC);
1294 }
1295
1296
1297 public static Constraint getFreeTextConstraint(Session session, QueryObjectModelFactory factory, Selector source,
1298 String filter) throws RepositoryException {
1299 Constraint defaultC = null;
1300 if (notEmpty(filter)) {
1301 String[] strs = filter.trim().split(" ");
1302 for (String token : strs) {
1303 StaticOperand so = factory.literal(session.getValueFactory().createValue("*" + token + "*"));
1304 Constraint currC = factory.fullTextSearch(source.getSelectorName(), null, so);
1305 defaultC = localAnd(factory, defaultC, currC);
1306 }
1307 }
1308 return defaultC;
1309 }
1310
1311
1312 static boolean notEmpty(String stringToTest) {
1313 return !(stringToTest == null || "".equals(stringToTest.trim()));
1314 }
1315
1316
1317 private ConnectJcrUtils() {
1318 }
1319 }