1 package org.argeo.connect.resources.core;
2
3 import static org.argeo.connect.util.ConnectUtils.notEmpty;
4
5 import java.util.ArrayList;
6 import java.util.List;
7 import java.util.UUID;
8
9 import javax.jcr.Node;
10 import javax.jcr.NodeIterator;
11 import javax.jcr.Property;
12 import javax.jcr.PropertyType;
13 import javax.jcr.RepositoryException;
14 import javax.jcr.Session;
15 import javax.jcr.Value;
16 import javax.jcr.nodetype.NodeType;
17 import javax.jcr.query.Query;
18 import javax.jcr.query.QueryManager;
19 import javax.jcr.query.QueryResult;
20
21 import org.apache.commons.logging.Log;
22 import org.apache.commons.logging.LogFactory;
23 import org.argeo.cms.auth.CurrentUser;
24 import org.argeo.connect.ConnectConstants;
25 import org.argeo.connect.ConnectException;
26 import org.argeo.connect.ConnectNames;
27 import org.argeo.connect.ConnectTypes;
28 import org.argeo.connect.core.AbstractAppService;
29 import org.argeo.connect.resources.ResourcesConstants;
30 import org.argeo.connect.resources.ResourcesNames;
31 import org.argeo.connect.resources.ResourcesRole;
32 import org.argeo.connect.resources.ResourcesService;
33 import org.argeo.connect.resources.ResourcesTypes;
34 import org.argeo.connect.util.ConnectJcrUtils;
35 import org.argeo.connect.util.ConnectUtils;
36 import org.argeo.connect.util.XPathUtils;
37 import org.argeo.jcr.JcrUtils;
38
39
40 public class ResourcesServiceImpl extends AbstractAppService implements ResourcesService {
41 private final static Log log = LogFactory.getLog(ResourcesServiceImpl.class);
42
43
44 @Override
45 public Node publishEntity(Node parent, String nodeType, Node srcNode, boolean removeSrcNode)
46 throws RepositoryException {
47
48 return null;
49 }
50
51 @Override
52 public String getAppBaseName() {
53 return ResourcesNames.RESOURCES_BASE_NAME;
54 }
55
56 @Override
57 public String getDefaultRelPath(Node entity) throws RepositoryException {
58
59 return null;
60 }
61
62 @Override
63 public String getDefaultRelPath(Session session, String nodeType, String id) {
64 if (ResourcesTypes.RESOURCES_TAG.equals(nodeType) | ResourcesTypes.RESOURCES_ENCODED_TAG.equals(nodeType)) {
65
66 id = id.trim();
67 String cleanedTag = JcrUtils.replaceInvalidChars(id).trim();
68
69 if (cleanedTag.charAt(1) == ' ')
70 cleanedTag = cleanedTag.charAt(0) + ' ' + cleanedTag.substring(2);
71 String relPath = JcrUtils.firstCharsToPath(cleanedTag, 2);
72 return relPath + "/" + cleanedTag;
73 } else if (ResourcesTypes.RESOURCES_NODE_TEMPLATE.equals(nodeType))
74 return ResourcesNames.RESOURCES_TEMPLATES + "/" + id;
75 else if (ResourcesConstants.RESOURCE_TYPE_ID_TEMPLATE.equals(nodeType)) {
76 log.warn("Deprecated method argument : " + nodeType);
77 return ResourcesNames.RESOURCES_TEMPLATES + "/" + id;
78 } else if (ResourcesTypes.RESOURCES_TAG_PARENT.equals(nodeType))
79 return ResourcesNames.RESOURCES_TAG_LIKE + "/" + id;
80 else if (ResourcesConstants.RESOURCE_TYPE_ID_TAG_LIKE.equals(nodeType)) {
81 log.warn("Deprecated method argument : " + nodeType);
82 return ResourcesNames.RESOURCES_TAG_LIKE + "/" + id;
83 } else
84 return null;
85 }
86
87 @Override
88 public boolean isKnownType(Node entity) {
89 if (ConnectJcrUtils.isNodeType(entity, ResourcesTypes.RESOURCES_TAG_PARENT)
90 || ConnectJcrUtils.isNodeType(entity, ResourcesTypes.RESOURCES_NODE_TEMPLATE)
91 || ConnectJcrUtils.isNodeType(entity, ResourcesTypes.RESOURCES_ENCODED_TAG)
92 || ConnectJcrUtils.isNodeType(entity, ResourcesTypes.RESOURCES_TAG))
93 return true;
94 else
95 return false;
96 }
97
98 @Override
99 public boolean isKnownType(String nodeType) {
100 if (ResourcesTypes.RESOURCES_TAG_PARENT.equals(nodeType)
101 || ResourcesTypes.RESOURCES_NODE_TEMPLATE.equals(nodeType)
102 || ResourcesTypes.RESOURCES_ENCODED_TAG.equals(nodeType)
103 || ResourcesTypes.RESOURCES_TAG.equals(nodeType))
104 return true;
105 else
106 return false;
107 }
108
109
110
111 @Override
112 public String getItemDefaultEnLabel(String itemId) {
113 return itemId;
114 }
115
116 @Override
117 public String getItemLabel(String itemName, String langIso) {
118 log.warn("Item label retrieval is not yet internationnalized. " + "Returning english default label for "
119 + itemName + " instead.");
120 return getItemDefaultEnLabel(itemName);
121 }
122
123
124 @Override
125 public List<String> getTemplateCatalogue(Session session, String templateId, String propertyName, String filter) {
126 Node node = getNodeTemplate(session, templateId);
127 if (node != null)
128 return getTemplateCatalogue(node, propertyName, filter);
129 else
130
131 return new ArrayList<String>();
132 }
133
134 @Override
135 public List<String> getTemplateCatalogue(Node node, String propertyName, String filter) {
136 List<String> result = new ArrayList<String>();
137 try {
138 if (node.hasProperty(propertyName)) {
139 Value[] values = node.getProperty(propertyName).getValues();
140 for (Value value : values) {
141 String curr = value.getString();
142 if (ConnectUtils.isEmpty(filter)
143 || notEmpty(curr) && curr.toLowerCase().contains(filter.toLowerCase()))
144 result.add(curr);
145 }
146 }
147 } catch (RepositoryException re) {
148 throw new ConnectException("Unable to get " + propertyName + " values for template " + node, re);
149 }
150 return result;
151 }
152
153 @Override
154 public Node getNodeTemplate(Session session, String templateId) {
155 String path = "/" + getAppBaseName() + "/"
156 + getDefaultRelPath(null, ResourcesTypes.RESOURCES_NODE_TEMPLATE, templateId);
157 try {
158 if (session.nodeExists(path)) {
159 return session.getNode(path);
160 }
161 } catch (RepositoryException e) {
162 throw new ConnectException(
163 "Unable to retrieve template instance " + "at path " + path + " for templateId " + templateId, e);
164 }
165 return null;
166 }
167
168 @Override
169 public Node createTemplateForType(Session session, String nodeType, String templateId) {
170 String currId = templateId == null ? nodeType : templateId;
171 Node node = getNodeTemplate(session, currId);
172 if (node != null)
173 return node;
174 else {
175 String path = "/" + getAppBaseName() + "/"
176 + getDefaultRelPath(null, ResourcesTypes.RESOURCES_NODE_TEMPLATE, currId);
177 String parPath = JcrUtils.parentPath(path);
178 try {
179 if (!session.nodeExists(parPath))
180 throw new ConnectException(
181 "Default tree structure " + "for template resources must have been created. "
182 + "Please fix this before trying to create template " + currId);
183 Node parent = session.getNode(parPath);
184 Node template = parent.addNode(currId, ResourcesTypes.RESOURCES_NODE_TEMPLATE);
185 template.setProperty(ResourcesNames.RESOURCES_TEMPLATE_ID, currId);
186 return template;
187 } catch (RepositoryException e) {
188 throw new ConnectException("Unable to create new temaple " + currId + " at path " + path, e);
189 }
190 }
191 }
192
193 @Override
194 public NodeIterator getCatalogueValueInstances(Session session, String entityType, String propName, String value) {
195 try {
196 QueryManager qm = session.getWorkspace().getQueryManager();
197 Query query = qm.createQuery(
198 "select * from [" + entityType + "] as nodes where [" + propName + "]='" + value + "'" + " ",
199 Query.JCR_SQL2);
200 return query.execute().getNodes();
201 } catch (RepositoryException ee) {
202 throw new ConnectException("Unable to retrieve catalogue value instances for type " + entityType
203 + " and property " + propName + " for value " + value, ee);
204 }
205 }
206
207 @Override
208 public void updateCatalogueValue(Node templateNode, String taggableType, String propertyName, String oldValue,
209 String newValue) {
210 try {
211
212 if (ConnectUtils.isEmpty(oldValue))
213 throw new ConnectException("Old value cannot be empty");
214
215 Value[] values = templateNode.getProperty(propertyName).getValues();
216 List<String> newValues = new ArrayList<String>();
217
218 for (Value value : values) {
219 String currValStr = value.getString();
220 if (oldValue.equals(currValStr)) {
221 if (notEmpty(newValue))
222 newValues.add(newValue);
223 } else
224 newValues.add(currValStr);
225 }
226 templateNode.setProperty(propertyName, newValues.toArray(new String[0]));
227
228
229
230 NodeIterator nit = getCatalogueValueInstances(ConnectJcrUtils.getSession(templateNode), taggableType,
231 propertyName, oldValue);
232 while (nit.hasNext())
233 updateOneTag(nit.nextNode(), propertyName, oldValue, newValue);
234 } catch (RepositoryException e) {
235 throw new ConnectException(
236 "Unable to update " + templateNode + " with values on " + taggableType + " for property "
237 + propertyName + " with old value '" + oldValue + "' and new value '" + newValue + "'.",
238 e);
239 }
240 }
241
242
243 @Override
244 public Node createTagLikeResourceParent(Session session, String tagId, String tagInstanceType, String codePropName,
245 String taggableParentPath, String taggableNodeType, String taggablePropName) {
246 List<String> names = new ArrayList<String>();
247 names.add(taggablePropName);
248 return createTagLikeResourceParent(session, tagId, tagInstanceType, codePropName, taggableParentPath,
249 taggableNodeType, names);
250 }
251
252 public Node createTagLikeResourceParent(Session session, String tagId, String tagInstanceType, String codePropName,
253 String taggableParentPath, String taggableNodeType, List<String> taggablePropNames) {
254 String currId = tagId == null ? tagInstanceType : tagId;
255 Node node = getTagLikeResourceParent(session, currId);
256 if (node != null)
257 return node;
258 else {
259 String path = "/" + getAppBaseName() + "/"
260 + getDefaultRelPath(null, ResourcesTypes.RESOURCES_TAG_PARENT, currId);
261 String parPath = JcrUtils.parentPath(path);
262 try {
263 if (!session.nodeExists(parPath))
264 throw new ConnectException("Default tree structure "
265 + "for tag like resources must have been created. "
266 + "Please fix this before trying to create " + "tag like resource parent " + currId);
267 Node parent = session.getNode(parPath);
268 Node tagLikeParent = parent.addNode(currId, ResourcesTypes.RESOURCES_TAG_PARENT);
269 tagLikeParent.setProperty(ResourcesNames.RESOURCES_TAG_ID, currId);
270 tagLikeParent.setProperty(ResourcesNames.RESOURCES_TAG_INSTANCE_TYPE, tagInstanceType);
271
272
273 if (notEmpty(codePropName))
274 tagLikeParent.setProperty(ResourcesNames.RESOURCES_TAG_CODE_PROP_NAME, codePropName);
275 tagLikeParent.setProperty(ResourcesNames.RESOURCES_TAGGABLE_PARENT_PATH, taggableParentPath);
276 tagLikeParent.setProperty(ResourcesNames.RESOURCES_TAGGABLE_NODE_TYPE, taggableNodeType);
277 tagLikeParent.setProperty(ResourcesNames.RESOURCES_TAGGABLE_PROP_NAME,
278 taggablePropNames.toArray(new String[0]));
279 return tagLikeParent;
280 } catch (RepositoryException e) {
281 throw new ConnectException("Unable to create new temaple " + currId + " at path " + path, e);
282 }
283 }
284 }
285
286 @Override
287 public Node getTagLikeResourceParent(Session session, String tagId) {
288 String path = "/" + getAppBaseName() + "/"
289 + getDefaultRelPath(null, ResourcesTypes.RESOURCES_TAG_PARENT, tagId);
290 try {
291 if (session.nodeExists(path)) {
292 return session.getNode(path);
293 }
294 } catch (RepositoryException e) {
295 throw new ConnectException("Unable to retrieve tag like parent at path " + path + " for tagId " + tagId, e);
296 }
297 return null;
298 }
299
300 @Override
301 public Node registerTag(Session session, String tagId, String tagValue) throws RepositoryException {
302 Node tagInstance = getRegisteredTag(session, tagId, tagValue);
303 if (tagInstance != null) {
304
305 if (log.isTraceEnabled()) {
306 String registeredKey = ConnectJcrUtils.get(tagInstance,
307 getTagKeyPropName(getTagLikeResourceParent(session, tagId)));
308 log.debug("Tag [" + tagId + "] with key " + tagValue + " already exists (registered key is ["
309 + registeredKey + "]), nothing has been done.");
310 }
311 return tagInstance;
312 } else {
313 Node newTag = createTagInstanceInternal(getExistingTagLikeParent(session, tagId), tagValue);
314 return newTag;
315 }
316 }
317
318 @Override
319 public Node registerTag(Session session, String tagId, String tagCode, String tagValue) throws RepositoryException {
320
321 Node tagInstance = getRegisteredTag(session, tagId, tagCode);
322 if (tagInstance != null) {
323
324 if (log.isTraceEnabled()) {
325 String registeredKey = ConnectJcrUtils.get(tagInstance,
326 getTagKeyPropName(getTagLikeResourceParent(session, tagId)));
327 log.debug("Tag [" + tagId + "] with key " + tagCode + " already exists (registered key is ["
328 + registeredKey + "]), nothing has been done.");
329 }
330 return tagInstance;
331 } else {
332 Node newTag = createTagInstanceInternal(getExistingTagLikeParent(session, tagId), tagCode);
333
334 tagValue = tagValue.trim();
335 ConnectJcrUtils.setJcrProperty(newTag, Property.JCR_TITLE, PropertyType.STRING, tagValue);
336 return newTag;
337 }
338 }
339
340 @Override
341 public Node getRegisteredTag(Session session, String tagId, String instanceKey) {
342 return getRegisteredTag(getExistingTagLikeParent(session, tagId), instanceKey);
343 }
344
345 @Override
346 public Node getRegisteredTag(Node tagParent, String instanceKey) {
347 try {
348 String relPath = getDefaultRelPath(null, ResourcesTypes.RESOURCES_TAG, instanceKey);
349 if (tagParent.hasNode(relPath)) {
350 Node existing = tagParent.getNode(relPath);
351 String existingValue = ConnectJcrUtils.get(existing, getTagKeyPropName(tagParent));
352 if (instanceKey.equalsIgnoreCase(existingValue)) {
353 return existing;
354 }
355 }
356 return null;
357 } catch (RepositoryException e) {
358 throw new ConnectException("Unable to retrieve existing tag " + tagParent + " for key " + instanceKey, e);
359 }
360 }
361
362 @Override
363 public String getEncodedTagValue(Session session, String tagId, String code) {
364 try {
365 Node tag = getRegisteredTag(session, tagId, code);
366 if (tag != null && tag.hasProperty(Property.JCR_TITLE))
367 return tag.getProperty(Property.JCR_TITLE).getString();
368 } catch (RepositoryException e) {
369 throw new ConnectException("Unable to retrieve tag " + tagId + " value with key " + code, e);
370 }
371 return code;
372 }
373
374 @Override
375 public String getEncodedTagCodeFromValue(Session session, String tagId, String value) {
376 try {
377 Node tagParent = getExistingTagLikeParent(session, tagId);
378 String tagNodeType = tagParent.getProperty(ResourcesNames.RESOURCES_TAG_INSTANCE_TYPE).getString();
379 String tagCodePropName = tagParent.getProperty(ResourcesNames.RESOURCES_TAG_CODE_PROP_NAME).getString();
380
381 StringBuilder builder = new StringBuilder();
382 builder.append(XPathUtils.descendantFrom(tagParent.getPath()));
383 builder.append("//element(*, ").append(tagNodeType).append(")");
384 builder.append("[");
385 builder.append(XPathUtils.getPropertyEquals(Property.JCR_TITLE, value));
386 builder.append("]");
387
388 Query query = XPathUtils.createQuery(session, builder.toString());
389 QueryResult queryResult = query.execute();
390 NodeIterator ni = queryResult.getNodes();
391 if (ni.hasNext())
392 return ni.nextNode().getProperty(tagCodePropName).getString();
393 else {
394 return null;
395 }
396 } catch (RepositoryException e) {
397 throw new ConnectException("Unable to get code for encodedTag " + tagId + " with value " + value, e);
398 }
399 }
400
401 @Override
402 public String getEncodedTagValuesAsString(String tagId, Node node, String propertyName, String separator) {
403 try {
404 Session session = node.getSession();
405
406 if (!node.hasProperty(propertyName))
407 return "";
408 else {
409 Value[] codes = node.getProperty(propertyName).getValues();
410 StringBuilder builder = new StringBuilder();
411 for (Value val : codes) {
412 String currCode = val.getString();
413 if (notEmpty(currCode)) {
414 builder.append(getEncodedTagValue(session, tagId, currCode)).append(separator);
415 }
416 }
417 if (builder.lastIndexOf(separator) >= 0)
418 return builder.substring(0, builder.length() - separator.length());
419 else
420 return builder.toString();
421 }
422 } catch (RepositoryException e) {
423 throw new ConnectException(
424 "Cannot get values of " + tagId + " for property " + propertyName + " of " + node, e);
425 }
426 }
427
428 @Override
429 public NodeIterator getTaggedEntities(Session session, String tagId, String key) {
430 Node tagParent = getExistingTagLikeParent(session, tagId);
431 return getTaggedEntities(tagParent, key);
432 }
433
434 @Override
435 public NodeIterator getTaggedEntities(Node tagParent, String key) {
436 try {
437 String nodeType = tagParent.getProperty(ResourcesNames.RESOURCES_TAGGABLE_NODE_TYPE).getString();
438 String parentPath = tagParent.getProperty(ResourcesNames.RESOURCES_TAGGABLE_PARENT_PATH).getString();
439 List<String> propNames = ConnectJcrUtils.getMultiAsList(tagParent,
440 ResourcesNames.RESOURCES_TAGGABLE_PROP_NAME);
441
442
443 StringBuilder builder = new StringBuilder();
444
445 for (String propName : propNames) {
446 builder.append(XPathUtils.getPropertyEquals(propName, key));
447 builder.append(" OR ");
448 }
449 String condition = builder.toString();
450
451
452 condition = condition.substring(0, condition.length() - 4);
453
454 String xpathQueryStr = XPathUtils.descendantFrom(parentPath) + "//element(*, " + nodeType + ")";
455
456 xpathQueryStr += "[" + condition + "]";
457 QueryManager queryManager = tagParent.getSession().getWorkspace().getQueryManager();
458 Query query = queryManager.createQuery(xpathQueryStr, ConnectConstants.QUERY_XPATH);
459 NodeIterator nit = query.execute().getNodes();
460 return nit;
461 } catch (RepositoryException ee) {
462 throw new ConnectException("Unable to retrieve tagged entities for key " + key + " on parent " + tagParent,
463 ee);
464 }
465 }
466
467 @Override
468 public void refreshKnownTags(Session session, String tagId) {
469 refreshKnownTags(getExistingTagLikeParent(session, tagId));
470 }
471
472 @Override
473 public void refreshKnownTags(Node tagParent) {
474 try {
475
476 List<String> newExistingValues = new ArrayList<String>();
477 List<String> registeredTags = new ArrayList<String>();
478 Session session = tagParent.getSession();
479 if (log.isDebugEnabled())
480 log.debug("Starting known tag refresh for " + tagParent);
481 String keyPropName = getTagKeyPropName(tagParent);
482 String taggableNodeType = tagParent.getProperty(ResourcesNames.RESOURCES_TAGGABLE_NODE_TYPE).getString();
483 String taggableParentPath = tagParent.getProperty(ResourcesNames.RESOURCES_TAGGABLE_PARENT_PATH)
484 .getString();
485 String codeProp = ConnectJcrUtils.get(tagParent, ResourcesNames.RESOURCES_TAG_CODE);
486 List<String> propNames = ConnectJcrUtils.getMultiAsList(tagParent,
487 ResourcesNames.RESOURCES_TAGGABLE_PROP_NAME);
488
489 if (log.isTraceEnabled())
490 log.trace("Getting already registered tags");
491 NodeIterator nit = getRegisteredTags(tagParent, null);
492 while (nit.hasNext()) {
493 Node currNode = nit.nextNode();
494 String currKey = ConnectJcrUtils.get(currNode, keyPropName);
495 if (notEmpty(currKey) && !registeredTags.contains(currKey))
496 registeredTags.add(currKey);
497 }
498 if (log.isTraceEnabled())
499 log.trace("Found already " + registeredTags.size() + " registered tags");
500
501
502
503
504
505
506
507
508
509
510
511 String xpathQueryStr = XPathUtils.descendantFrom(taggableParentPath) + "//element(*, " + taggableNodeType
512 + ")";
513 QueryManager queryManager = session.getWorkspace().getQueryManager();
514 Query query = queryManager.createQuery(xpathQueryStr, ConnectConstants.QUERY_XPATH);
515 nit = query.execute().getNodes();
516 if (log.isDebugEnabled())
517 log.debug("Searching new tags on " + nit.getSize() + " elements of type " + taggableNodeType);
518 while (nit.hasNext()) {
519 Node currNode = nit.nextNode();
520 for (String propName : propNames) {
521 if (currNode.hasProperty(propName)) {
522 Value[] tags = currNode.getProperty(propName).getValues();
523 for (Value tagV : tags) {
524 String currTag = tagV.getString().trim();
525
526 if (notEmpty(currTag) && !registeredTags.contains(currTag)) {
527 if (currTag.length() < 2) {
528 log.warn("Unable to cache tag [" + currTag + "] for "
529 + ConnectJcrUtils.get(currNode, Property.JCR_TITLE) + " - " + currNode);
530 } else if (!newExistingValues.contains(currTag))
531 newExistingValues.add(currTag);
532 }
533 }
534 }
535 }
536 }
537
538 if (log.isTraceEnabled())
539 log.trace("Start processing the " + newExistingValues.size() + " new used tags found.");
540
541
542 if (ConnectUtils.isEmpty(codeProp))
543 for (String tag : newExistingValues) {
544 createTagInstanceInternal(tagParent, tag);
545 session.save();
546 }
547 else {
548 for (String tag : newExistingValues) {
549 Node curr = createTagInstanceInternal(tagParent, tag);
550 ConnectJcrUtils.setJcrProperty(curr, Property.JCR_TITLE, PropertyType.STRING, tag);
551 session.save();
552 }
553 log.warn("We refreshed an encoded tag like subtree, for " + tagParent
554 + ". All tag values have been set " + "with the same value as the code because we "
555 + "have no information on the corresponding label.");
556 }
557 if (log.isDebugEnabled())
558 log.debug("Tag refresh for " + tagParent + " has been done, creating " + newExistingValues.size()
559 + " new tag instances.");
560 } catch (RepositoryException ee) {
561 throw new ConnectException("Unable to refresh cache of known tags", ee);
562 }
563 }
564
565 @Override
566 public boolean updateTag(Node tagInstance, String newValue) throws RepositoryException {
567 Node tagParent = TagUtils.retrieveTagParentFromTag(tagInstance);
568 Value[] values = tagParent.getProperty(ResourcesNames.RESOURCES_TAGGABLE_PROP_NAME).getValues();
569 if (values.length > 1)
570
571 return false;
572 String propName = values[0].getString();
573 String oldValue = tagInstance.getProperty(Property.JCR_TITLE).getString();
574
575
576 ConnectJcrUtils.checkCOStatusBeforeUpdate(tagInstance);
577 Session session = tagInstance.getSession();
578
579 NodeIterator nit = getTaggedEntities(tagParent, oldValue);
580 while (nit.hasNext())
581 updateOneTag(nit.nextNode(), propName, oldValue, newValue);
582
583 String newRelPath = "/" + getDefaultRelPath(null, ResourcesTypes.RESOURCES_TAG, newValue);
584
585
586
587 Node newIntancePar = JcrUtils.mkdirs(tagParent, JcrUtils.parentPath(newRelPath), NodeType.NT_UNSTRUCTURED);
588 session.move(tagInstance.getPath(), newIntancePar.getPath() + "/" + JcrUtils.lastPathElement(newRelPath));
589 tagInstance.setProperty(Property.JCR_TITLE, newValue);
590 tagInstance.getSession().save();
591 return true;
592 }
593
594
595
596
597
598
599
600
601
602
603 private void updateOneTag(Node taggable, String tagPropName, String oldValue, String newValue) {
604 try {
605 Node versionable = ConnectJcrUtils.getParentVersionableNode(taggable);
606 if (versionable != null && !ConnectJcrUtils.checkCOStatusBeforeUpdate(versionable))
607 log.warn(versionable + " was checked-in as we want to update " + tagPropName + " of " + taggable
608 + " form " + oldValue + " to " + newValue);
609 Property property = taggable.getProperty(tagPropName);
610 if (property.isMultiple()) {
611 List<String> oldValues = ConnectJcrUtils.getMultiAsList(taggable, tagPropName);
612 List<String> newValues = new ArrayList<String>();
613 for (String val : oldValues) {
614 if (oldValue.equals(val) && newValue != null)
615 newValues.add(newValue);
616 else
617 newValues.add(val);
618 }
619 taggable.setProperty(tagPropName, newValues.toArray(new String[0]));
620 } else
621 taggable.setProperty(tagPropName, newValue);
622 taggable.getSession().save();
623 } catch (RepositoryException ee) {
624 throw new ConnectException("Unable to update tag like multiple value property " + tagPropName + " removing "
625 + oldValue + " and adding " + newValue + " on " + taggable, ee);
626 }
627 }
628
629 @Override
630 public void unregisterTag(Session session, String tagId, String tag) {
631 throw new ConnectException("Unimplemented method " + "ResourceService.unregisterTag("
632 + "Session session, String tagId, String tag) ");
633 }
634
635 @Override
636 public long countMembers(Node tag) {
637 Node parent = TagUtils.retrieveTagParentFromTag(tag);
638 String keyPropName = getTagKeyPropName(parent);
639 NodeIterator nit = getTaggedEntities(parent, ConnectJcrUtils.get(tag, keyPropName));
640 return nit.getSize();
641 }
642
643 @Override
644 public List<String> getRegisteredTagValueList(Session session, String tagId, String filter) {
645 Node tagParent = getTagLikeResourceParent(session, tagId);
646 List<String> values = new ArrayList<String>();
647 if (tagParent == null)
648 return values;
649 try {
650 NodeIterator nit = getRegisteredTags(tagParent, filter);
651 while (nit.hasNext()) {
652 Node curr = nit.nextNode();
653 if (curr.hasProperty(Property.JCR_TITLE))
654 values.add(curr.getProperty(Property.JCR_TITLE).getString());
655 }
656 return values;
657 } catch (RepositoryException re) {
658 throw new ConnectException("Unable to get values for tag of ID " + tagId, re);
659 }
660 }
661
662
663
664 private Node createTagInstanceInternal(Node tagParent, String tagKey) {
665 try {
666
667 String relPath = getDefaultRelPath(null, ResourcesTypes.RESOURCES_TAG, tagKey);
668 String instanceType = tagParent.getProperty(ResourcesNames.RESOURCES_TAG_INSTANCE_TYPE).getString();
669
670 Node newTag = JcrUtils.mkdirs(tagParent, relPath, instanceType);
671 newTag.setProperty(getTagKeyPropName(tagParent), tagKey);
672 if (newTag.isNodeType(ConnectTypes.CONNECT_ENTITY)) {
673 String uuid = UUID.randomUUID().toString();
674 newTag.setProperty(ConnectNames.CONNECT_UID, uuid);
675 }
676 return newTag;
677 } catch (RepositoryException e) {
678 throw new ConnectException("Unable to create tag instance " + tagKey + " for tag " + tagParent, e);
679 }
680 }
681
682 protected String getTagKeyPropName(Node tagParent) {
683 try {
684 if (tagParent.hasProperty(ResourcesNames.RESOURCES_TAG_CODE_PROP_NAME))
685 return tagParent.getProperty(ResourcesNames.RESOURCES_TAG_CODE_PROP_NAME).getString();
686 else
687 return ConnectJcrUtils.getLocalJcrItemName(Property.JCR_TITLE);
688 } catch (RepositoryException e) {
689 throw new ConnectException("unable to retrieve key property name for " + tagParent);
690 }
691 }
692
693
694 private Node getExistingTagLikeParent(Session session, String tagId) {
695 Node tagInstanceParent = getTagLikeResourceParent(session, tagId);
696 if (tagInstanceParent == null)
697 throw new ConnectException(
698 "Tag like resource with ID " + tagId + " does not exist. Cannot process current action.");
699 else
700 return tagInstanceParent;
701 }
702
703 private NodeIterator getRegisteredTags(Node tagParent, String filter) {
704 try {
705 String nodeType = tagParent.getProperty(ResourcesNames.RESOURCES_TAG_INSTANCE_TYPE).getString();
706 String queryStr = "select * from [" + nodeType + "] as nodes where ISDESCENDANTNODE('" + tagParent.getPath()
707 + "')";
708 if (notEmpty(filter))
709 queryStr += " AND LOWER(nodes.[" + Property.JCR_TITLE + "]) like \"%" + filter.toLowerCase() + "%\"";
710 queryStr += " ORDER BY nodes.[" + Property.JCR_TITLE + "]";
711
712 Query query = tagParent.getSession().getWorkspace().getQueryManager().createQuery(queryStr, Query.JCR_SQL2);
713 return query.execute().getNodes();
714 } catch (RepositoryException re) {
715 throw new ConnectException("Unable to get values for " + tagParent + " with filter " + filter, re);
716 }
717 }
718
719 @Override
720 public boolean canCreateTag(Session session) {
721
722 String prop = System.getProperty(ConnectConstants.SYS_PROP_ID_PREVENT_TAG_ADDITION);
723 return !"true".equals(prop) || CurrentUser.isInRole(ResourcesRole.editor.dn());
724 }
725 }