View Javadoc

1   /**
2    * 2010, Digitalis Informatica. All rights reserved. Distribuicao e Gestao de Informatica, Lda. Estrada de Paco de Arcos
3    * num.9 - Piso -1 2780-666 Paco de Arcos Telefone: (351) 21 4408990 Fax: (351) 21 4408999 http://www.digitalis.pt
4    */
5   
6   package pt.digitalis.dif.utils.extensions.cms;
7   
8   import java.util.ArrayList;
9   import java.util.HashSet;
10  import java.util.List;
11  import java.util.Set;
12  
13  import pt.digitalis.dif.controller.security.objects.IDIFUser;
14  import pt.digitalis.dif.exception.security.IdentityManagerException;
15  import pt.digitalis.dif.utils.extensions.cms.exception.ContentItemNotFoundException;
16  import pt.digitalis.dif.utils.extensions.cms.exception.ContentItemWithDuplicateNameAndParentNodeException;
17  import pt.digitalis.dif.utils.extensions.cms.exception.ContentManagerException;
18  import pt.digitalis.dif.utils.extensions.cms.exception.InvalidParentNodeException;
19  import pt.digitalis.dif.utils.extensions.cms.exception.InvalidPathException;
20  import pt.digitalis.dif.utils.extensions.cms.exception.NoAccessException;
21  import pt.digitalis.dif.utils.extensions.cms.exception.NodeNotFoundException;
22  import pt.digitalis.dif.utils.extensions.cms.exception.NodeWithDuplicatePathException;
23  import pt.digitalis.dif.utils.extensions.cms.exception.NodeWithNodesException;
24  
25  /**
26   * Base implementation of a {@link IContentManager}
27   * 
28   * @author Pedro Viegas <a href="mailto:pviegas@digitalis.pt">pviegas@digitalis.pt</a><br/>
29   * @created 2010/10/25
30   */
31  public abstract class AbstractContentManager implements IContentManager {
32  
33      /** */
34      protected static char SEPARATOR = '\\';
35  
36      /**
37       * @see pt.digitalis.dif.utils.extensions.cms.IContentManager#addContent(pt.digitalis.dif.utils.extensions.cms.ContentItem)
38       */
39      public ContentItem addContent(ContentItem content) throws ContentManagerException
40      {
41  
42          if (content.getUser() == null)
43          {
44              throw new NoAccessException("The Content User attribute must be filled to complete the insert");
45          }
46  
47          if (content.getParentNodeId() != null)
48          {
49              try
50              {
51                  if (!nodeExists(content.getParentNodeId(), content.getUser()))
52                      throw new InvalidParentNodeException();
53              }
54              catch (Exception e)
55              {
56                  throw new InvalidParentNodeException(e);
57              }
58  
59              if (!hasNodeAccessUser(content.getParentNodeId(), content.getUser()))
60                  throw new NoAccessException("User doesn't have access to the parent node");
61          }
62  
63          return persistContentInRepository(content, content.getUser());
64      }
65  
66      /**
67       * @see pt.digitalis.dif.utils.extensions.cms.IContentManager#addNode(pt.digitalis.dif.utils.extensions.cms.Node)
68       */
69      public Node addNode(Node node) throws ContentManagerException
70      {
71          if (node == null)
72              throw new NodeNotFoundException();
73  
74          if (node.getUser() == null)
75          {
76              throw new NoAccessException("The Node User attribute must be filled to complete the insert");
77          }
78  
79          String fullPath = determineFullPath(node);
80  
81          if (!validadeNameAndPath(fullPath, true))
82              throw new InvalidPathException("Invalid path: " + fullPath);
83  
84          node.setFullPathName(fullPath);
85  
86          if (node.getParentNodeId() != null)
87              if (!hasNodeAccessUser(node.getParentNodeId(), node.getUser()))
88                  throw new NoAccessException("User doesn't have access to the parent node");
89  
90          return persistNodeInRepository(node, node.getUser());
91      }
92  
93      /**
94       * Check the access in a list of content items
95       * 
96       * @param listToCheck
97       *            the content list to check
98       * @param user
99       *            the user who's searching
100      * @return the list with the contents with access
101      */
102     protected List<ContentItem> checkContentAccessInList(List<ContentItem> listToCheck, IDIFUser user)
103     {
104         List<ContentItem> reviewedList = new ArrayList<ContentItem>();
105 
106         for (ContentItem content: listToCheck)
107         {
108             try
109             {
110                 if (hasContentAccessUser(content, user))
111                     reviewedList.add(content);
112             }
113             catch (ContentManagerException e)
114             {
115                 // never should occur
116             }
117         }
118 
119         return reviewedList;
120     }
121 
122     /**
123      * Check the access in a list of nodes
124      * 
125      * @param listToCheck
126      *            the node list to check
127      * @param user
128      *            the user who's searching
129      * @return the list with the contents with access
130      */
131     protected List<Node> checkNodeAccessInList(List<Node> listToCheck, IDIFUser user)
132     {
133         List<Node> reviewedList = new ArrayList<Node>();
134 
135         for (Node node: listToCheck)
136         {
137             try
138             {
139                 if (hasNodeAccessUser(node, user))
140                     reviewedList.add(node);
141             }
142             catch (ContentManagerException e)
143             {
144                 // never should occur
145             }
146         }
147 
148         return reviewedList;
149     }
150 
151     /**
152      * @see pt.digitalis.dif.utils.extensions.cms.IContentManager#deleteContent(java.lang.String,
153      *      pt.digitalis.dif.controller.security.objects.IDIFUser)
154      */
155     public boolean deleteContent(String id, IDIFUser user) throws ContentManagerException
156     {
157         if (!hasContentAccessUser(id, user))
158             throw new NoAccessException("User doesn't have access to content");
159 
160         return deleteContentInRepository(id, user);
161     }
162 
163     /**
164      * Deletes an existing content from the repository
165      * 
166      * @param id
167      *            the id of the content to delete
168      * @param user
169      *            the user id that is deleting the content
170      * @return T if all went well
171      * @throws ContentManagerException
172      */
173     protected abstract boolean deleteContentInRepository(String id, IDIFUser user) throws ContentManagerException;
174 
175     /**
176      * @see pt.digitalis.dif.utils.extensions.cms.IContentManager#deleteNode(java.lang.Long,
177      *      pt.digitalis.dif.controller.security.objects.IDIFUser)
178      */
179     public boolean deleteNode(Long id, IDIFUser user) throws ContentManagerException
180     {
181         return deleteNode(id, user, false);
182     }
183 
184     /**
185      * @see pt.digitalis.dif.utils.extensions.cms.IContentManager#deleteNode(java.lang.Long,
186      *      pt.digitalis.dif.controller.security.objects.IDIFUser, boolean)
187      */
188     public boolean deleteNode(Long id, IDIFUser user, boolean cascadeDelete) throws ContentManagerException
189     {
190         if (!hasNodeAccessUser(id, user))
191             throw new NoAccessException("User doesn't have access to node");
192 
193         return deleteNodeInRepository(id, user, cascadeDelete);
194     }
195 
196     /**
197      * Deletes an existing node from the repository. <br>
198      * Will launch an exception if the node is not empty
199      * 
200      * @param nodeId
201      *            the node to delete
202      * @param user
203      *            the user that's deleting the node
204      * @param cascadeDelete
205      *            if T will delete all inner nodes and content, if F will launch an exception if the node is not empty
206      * @return T if all went well
207      * @throws NodeNotFoundException
208      * @throws NodeWithNodesException
209      * @throws ContentManagerException
210      */
211     protected abstract boolean deleteNodeInRepository(Long nodeId, IDIFUser user, boolean cascadeDelete)
212             throws NodeNotFoundException, NodeWithNodesException, ContentManagerException;
213 
214     /**
215      * Determines the full path String base in the Node chain
216      * 
217      * @param node
218      *            node to convert
219      * @return the node converted
220      * @throws ContentManagerException
221      */
222     protected String determineFullPath(Node node) throws ContentManagerException
223     {
224         if (node.getParentNodeId() == null)
225             return SEPARATOR + node.getName();
226         else
227         {
228             String fullPathFromRep = getParentFullPathInRepository(node);
229 
230             if (!validadeNameAndPath(fullPathFromRep, true))
231                 throw new InvalidPathException("Invalid path: " + fullPathFromRep);
232 
233             return fullPathFromRep + SEPARATOR + node.getName();
234         }
235     }
236 
237     /**
238      * @see pt.digitalis.dif.utils.extensions.cms.IContentManager#getContentByDescription(java.lang.String,
239      *      pt.digitalis.dif.controller.security.objects.IDIFUser)
240      */
241     public List<ContentItem> getContentByDescription(String description, IDIFUser user) throws ContentManagerException
242     {
243         return checkContentAccessInList(getContentByDescriptionInRepository(description, user), user);
244     }
245 
246     /**
247      * Searches content items by description
248      * 
249      * @param description
250      *            the content id
251      * @param user
252      *            the user who's searching
253      * @return the content list
254      * @throws ContentManagerException
255      */
256     protected abstract List<ContentItem> getContentByDescriptionInRepository(String description, IDIFUser user)
257             throws ContentManagerException;
258 
259     /**
260      * @see pt.digitalis.dif.utils.extensions.cms.IContentManager#getContentById(java.lang.String,
261      *      pt.digitalis.dif.controller.security.objects.IDIFUser)
262      */
263     public ContentItem getContentById(String id, IDIFUser user) throws ContentManagerException
264     {
265         ContentItem contentItem = getContentByIdInRepository(id, user);
266         if (!hasContentAccessUser(contentItem, user))
267             throw new NoAccessException("User has no access to content item");
268 
269         return contentItem;
270     }
271 
272     /**
273      * Searches an existing content by it's unique identifier
274      * 
275      * @param id
276      *            the content id
277      * @param user
278      *            the user who's searching
279      * @return the content
280      * @throws ContentItemNotFoundException
281      * @throws NoAccessException
282      * @throws NodeNotFoundException
283      * @throws ContentManagerException
284      */
285     protected abstract ContentItem getContentByIdInRepository(String id, IDIFUser user)
286             throws ContentItemNotFoundException, NoAccessException, NodeNotFoundException, ContentManagerException;
287 
288     /**
289      * Searches an existing content by it's unique identifier, without access validation
290      * 
291      * @param id
292      *            the content id
293      * @param user
294      *            current user
295      * @return the content
296      * @throws ContentManagerException
297      */
298     protected ContentItem getContentByIdNoPermissions(String id, IDIFUser user) throws ContentManagerException
299     {
300         return getContentByIdNoPermissionsInRepository(id, user);
301     }
302 
303     /**
304      * Searches an existing content by it's unique identifier, without access validation
305      * 
306      * @param id
307      *            the content id
308      * @param user
309      *            current user
310      * @return the content
311      * @throws ContentItemNotFoundException
312      * @throws ContentManagerException
313      */
314     protected abstract ContentItem getContentByIdNoPermissionsInRepository(String id, IDIFUser user)
315             throws ContentItemNotFoundException, ContentManagerException;
316 
317     /**
318      * @see pt.digitalis.dif.utils.extensions.cms.IContentManager#getContentByName(java.lang.String,
319      *      pt.digitalis.dif.controller.security.objects.IDIFUser)
320      */
321     public List<ContentItem> getContentByName(String name, IDIFUser user) throws ContentManagerException
322     {
323         return checkContentAccessInList(getContentByNameInRepository(name, user), user);
324     }
325 
326     /**
327      * Searches content items by name
328      * 
329      * @param name
330      *            the content id
331      * @param user
332      *            the user who's searching
333      * @return the content list
334      * @throws ContentManagerException
335      */
336     protected abstract List<ContentItem> getContentByNameInRepository(String name, IDIFUser user)
337             throws ContentManagerException;
338 
339     /**
340      * @see pt.digitalis.dif.utils.extensions.cms.IContentManager#getContentByParentNode(java.lang.Long,
341      *      pt.digitalis.dif.controller.security.objects.IDIFUser)
342      */
343     public List<ContentItem> getContentByParentNode(Long nodeId, IDIFUser user) throws ContentManagerException
344     {
345         // just checks if exists
346         getNodeByIdNoPermissions(nodeId, user);
347 
348         return checkContentAccessInList(getContentByParentNodeInRepository(nodeId, user), user);
349     }
350 
351     /**
352      * Searches content items by parent node
353      * 
354      * @param nodeId
355      *            the parent id
356      * @param user
357      *            the user who's searching
358      * @return the content list
359      * @throws ContentManagerException
360      */
361     protected abstract List<ContentItem> getContentByParentNodeInRepository(Long nodeId, IDIFUser user)
362             throws ContentManagerException;
363 
364     /**
365      * @see pt.digitalis.dif.utils.extensions.cms.IContentManager#getContentFromNodePathByName(java.lang.String,
366      *      java.lang.String, pt.digitalis.dif.controller.security.objects.IDIFUser)
367      */
368     public ContentItem getContentFromNodePathByName(String nodeFullPath, String name, IDIFUser user)
369             throws ContentManagerException
370     {
371         ContentItem contentItem = getContentFromNodePathByNameRepository(nodeFullPath, name, user);
372         if (!hasContentAccessUser(contentItem, user))
373             throw new NoAccessException("User has no access to content item");
374 
375         return contentItem;
376     }
377 
378     /**
379      * Searches content items by name and node path on the repository
380      * 
381      * @param nodeFullPath
382      *            the node fullPath from the content will be retrieve
383      * @param name
384      *            the content id
385      * @param user
386      *            the user who's searching
387      * @return the content object
388      * @throws ContentManagerException
389      */
390     protected abstract ContentItem getContentFromNodePathByNameRepository(String nodeFullPath, String name,
391             IDIFUser user) throws ContentManagerException;
392 
393     /**
394      * @see pt.digitalis.dif.utils.extensions.cms.IContentManager#getContentItemACL(java.lang.String)
395      */
396     public List<ACLEntry> getContentItemACL(String id) throws ContentManagerException
397     {
398         return getContentItemACLInRepository(id);
399     }
400 
401     /**
402      * get node ACL
403      * 
404      * @param id
405      *            the content item ID
406      * @return the ACL
407      * @throws ContentManagerException
408      */
409     protected abstract List<ACLEntry> getContentItemACLInRepository(String id) throws ContentManagerException;
410 
411     /**
412      * @see pt.digitalis.dif.utils.extensions.cms.IContentManager#getNodeACL(java.lang.Long)
413      */
414     public List<ACLEntry> getNodeACL(Long id) throws ContentManagerException
415     {
416         return getNodeACLInRepository(id);
417     }
418 
419     /**
420      * get node ACL
421      * 
422      * @param id
423      *            the node ID
424      * @return the ACL
425      * @throws ContentManagerException
426      */
427     protected abstract List<ACLEntry> getNodeACLInRepository(Long id) throws ContentManagerException;
428 
429     /**
430      * @see pt.digitalis.dif.utils.extensions.cms.IContentManager#getNodeById(java.lang.Long,
431      *      pt.digitalis.dif.controller.security.objects.IDIFUser)
432      */
433     public Node getNodeById(Long id, IDIFUser user) throws ContentManagerException
434     {
435         Node node = getNodeByIdInRepository(id, user);
436         if (!hasNodeAccessUser(node, user))
437             throw new NoAccessException("User does not have access to the Node");
438 
439         return node;
440     }
441 
442     /**
443      * Searches a node by unique identifier
444      * 
445      * @param id
446      *            the node ID
447      * @param user
448      *            the user who's searching
449      * @return a list of all existing root nodes
450      * @throws ContentManagerException
451      */
452     protected abstract Node getNodeByIdInRepository(Long id, IDIFUser user) throws ContentManagerException;
453 
454     /**
455      * Searches a node by unique identifier. Permission checks are ignored
456      * 
457      * @param nodeID
458      *            the node ID
459      * @param user
460      *            the currentUser
461      * @return a list of all existing root nodes
462      * @throws ContentManagerException
463      */
464     protected Node getNodeByIdNoPermissions(Long nodeID, IDIFUser user) throws ContentManagerException
465     {
466         Node node = getNodeByIdNoPermissionsInRepository(nodeID, user);
467 
468         if (node == null)
469             throw new NodeNotFoundException(nodeID);
470 
471         return node;
472     }
473 
474     /**
475      * Searches for a given node. Permissions are not checked
476      * 
477      * @param id
478      *            the node ID
479      * @param user
480      *            current user
481      * @return a list of all existing root nodes
482      * @throws NodeNotFoundException
483      * @throws ContentManagerException
484      */
485     protected abstract Node getNodeByIdNoPermissionsInRepository(Long id, IDIFUser user) throws NodeNotFoundException,
486             ContentManagerException;
487 
488     /**
489      * @see pt.digitalis.dif.utils.extensions.cms.IContentManager#getNodeByPath(java.lang.String,
490      *      pt.digitalis.dif.controller.security.objects.IDIFUser)
491      */
492     public Node getNodeByPath(String fullPath, IDIFUser user) throws ContentManagerException
493     {
494         Node node = getNodeByPathInRespository(fullPath, user);
495         if (user != null)
496             if (!hasNodeAccessUser(node, user))
497                 throw new NoAccessException("User doesn't have access to the Node");
498 
499         return node;
500     }
501 
502     /**
503      * Searches a node by path
504      * 
505      * @param fullPath
506      *            the full path of the node the node ID
507      * @param user
508      *            the user who's searching
509      * @return a list of all existing root nodes
510      * @throws NodeNotFoundException
511      * @throws NoAccessException
512      * @throws ContentManagerException
513      */
514     protected abstract Node getNodeByPathInRespository(String fullPath, IDIFUser user) throws NodeNotFoundException,
515             NoAccessException, ContentManagerException;
516 
517     /**
518      * Searches a node by path. Permission checks are ignored
519      * 
520      * @param nodePath
521      *            the node path
522      * @param user
523      *            the currentUser
524      * @return a list of all existing root nodes
525      * @throws ContentManagerException
526      */
527     protected Node getNodeByPathNoPermissions(String nodePath, IDIFUser user) throws ContentManagerException
528     {
529         return getNodeByPathInRespository(nodePath, user);
530     }
531 
532     /**
533      * @see pt.digitalis.dif.utils.extensions.cms.IContentManager#getNodesByDescription(java.lang.String,
534      *      pt.digitalis.dif.controller.security.objects.IDIFUser)
535      */
536     public List<Node> getNodesByDescription(String description, IDIFUser user) throws ContentManagerException
537     {
538         return checkNodeAccessInList(getNodesByDescriptionInRepository(description, user), user);
539     }
540 
541     /**
542      * @see pt.digitalis.dif.utils.extensions.cms.IContentManager#getNodesByDescription(java.lang.String,
543      *      java.lang.String, pt.digitalis.dif.controller.security.objects.IDIFUser)
544      */
545     public List<Node> getNodesByDescription(String basePathToSearch, String description, IDIFUser user)
546             throws ContentManagerException
547     {
548         return checkNodeAccessInList(getNodesByDescriptionInRepository(basePathToSearch, description, user), user);
549     }
550 
551     /**
552      * Searches nodes by description
553      * 
554      * @param description
555      *            the description of the node to search
556      * @param user
557      *            the user who's searching
558      * @return a list of all existing nodes with the description
559      * @throws ContentManagerException
560      */
561     protected abstract List<Node> getNodesByDescriptionInRepository(String description, IDIFUser user)
562             throws ContentManagerException;
563 
564     /**
565      * Searches nodes by description
566      * 
567      * @param basePathToSearch
568      *            the path to search from
569      * @param description
570      *            the name of the node to search
571      * @param user
572      *            the user who's searching
573      * @return a list of all existing nodes with the description
574      * @throws ContentManagerException
575      */
576     protected abstract List<Node> getNodesByDescriptionInRepository(String basePathToSearch, String description,
577             IDIFUser user) throws ContentManagerException;
578 
579     /**
580      * @see pt.digitalis.dif.utils.extensions.cms.IContentManager#getNodesByName(java.lang.String,
581      *      pt.digitalis.dif.controller.security.objects.IDIFUser)
582      */
583     public List<Node> getNodesByName(String name, IDIFUser user) throws ContentManagerException
584     {
585         return checkNodeAccessInList(getNodesByNameInRepository(name, user), user);
586     }
587 
588     /**
589      * @see pt.digitalis.dif.utils.extensions.cms.IContentManager#getNodesByName(java.lang.String, java.lang.String,
590      *      pt.digitalis.dif.controller.security.objects.IDIFUser)
591      */
592     public List<Node> getNodesByName(String basePathToSearch, String name, IDIFUser user)
593             throws ContentManagerException
594     {
595         return checkNodeAccessInList(getNodesByNameInRepository(basePathToSearch, name, user), user);
596     }
597 
598     /**
599      * Searches nodes by name
600      * 
601      * @param name
602      *            the name of the node to search
603      * @param user
604      *            the user who's searching
605      * @return a list of nodes with the same name. May exist with same name in different parent nodes
606      * @throws ContentManagerException
607      */
608     protected abstract List<Node> getNodesByNameInRepository(String name, IDIFUser user) throws ContentManagerException;
609 
610     /**
611      * Searches nodes by name
612      * 
613      * @param basePathToSearch
614      *            the path to search from
615      * @param name
616      *            the name of the node to search
617      * @param user
618      *            the user who's searching
619      * @return a list of all existing root nodes. May exist with same name in different parent nodes
620      * @throws ContentManagerException
621      */
622     protected abstract List<Node> getNodesByNameInRepository(String basePathToSearch, String name, IDIFUser user)
623             throws ContentManagerException;
624 
625     /**
626      * @see pt.digitalis.dif.utils.extensions.cms.IContentManager#getNodesByParentNode(java.lang.Long,
627      *      pt.digitalis.dif.controller.security.objects.IDIFUser)
628      */
629     public List<Node> getNodesByParentNode(Long nodeId, IDIFUser user) throws ContentManagerException
630     {
631         return checkNodeAccessInList(getNodesByParentNodeInRepository(nodeId, user), user);
632     }
633 
634     /**
635      * Searches nodes by parent node
636      * 
637      * @param nodeId
638      *            the parent node id
639      * @param user
640      *            the user who's searching
641      * @return the content list
642      * @throws ContentManagerException
643      */
644     protected abstract List<Node> getNodesByParentNodeInRepository(Long nodeId, IDIFUser user)
645             throws ContentManagerException;
646 
647     /**
648      * Searches nodes by parent node. Permission checks are ignored.
649      * 
650      * @param nodeId
651      *            the parent node id
652      * @param user
653      *            current user
654      * @return the content list
655      * @throws ContentManagerException
656      */
657     protected List<Node> getNodesByParentNodeNoPermissions(Long nodeId, IDIFUser user) throws ContentManagerException
658     {
659         getNodeByIdNoPermissions(nodeId, user);
660 
661         return getNodesByParentNodeNoPermissionsInRepository(nodeId, user);
662     }
663 
664     /**
665      * Searches nodes by parent node. Permission checks are ignored.
666      * 
667      * @param nodeId
668      *            the parent node id
669      * @param user
670      *            current user
671      * @return the content list
672      * @throws ContentManagerException
673      */
674     protected abstract List<Node> getNodesByParentNodeNoPermissionsInRepository(Long nodeId, IDIFUser user)
675             throws ContentManagerException;
676 
677     /**
678      * Gets the parent full path
679      * 
680      * @param node
681      *            node to determine full path
682      * @return the node converted
683      * @throws InvalidParentNodeException
684      * @throws ContentManagerException
685      */
686     protected abstract String getParentFullPathInRepository(Node node) throws InvalidParentNodeException,
687             ContentManagerException;
688 
689     /**
690      * @see pt.digitalis.dif.utils.extensions.cms.IContentManager#getRootNodes(pt.digitalis.dif.controller.security.objects.IDIFUser)
691      */
692     public List<Node> getRootNodes(IDIFUser user) throws ContentManagerException
693     {
694         return checkNodeAccessInList(getRootNodesInRepository(user), user);
695     }
696 
697     /**
698      * Searches root nodes
699      * 
700      * @param user
701      *            the user who's searching
702      * @return a list of all existing root nodes
703      * @throws ContentManagerException
704      */
705     protected abstract List<Node> getRootNodesInRepository(IDIFUser user) throws ContentManagerException;
706 
707     /**
708      * Grants group access to content item
709      * 
710      * @param contentId
711      *            the id of the content to grant access
712      * @param groupId
713      *            the group to grant access
714      * @return T if access was granted, F otherwise.
715      * @throws ContentManagerException
716      */
717     public boolean grantContentAccessToGroup(String contentId, String groupId) throws ContentManagerException
718     {
719         ContentItem contentItem = this.getContentByIdNoPermissions(contentId, null);
720 
721         if (contentItem == null)
722             throw new ContentItemNotFoundException(contentId);
723 
724         return grantContentAccessToGroupInRepository(contentItem, groupId);
725     }
726 
727     /**
728      * Grants group access to content item
729      * 
730      * @param contentItemParam
731      *            the content to grant access
732      * @param groupId
733      *            the group to grant access
734      * @return T if access was granted, F otherwise.
735      * @throws ContentManagerException
736      */
737     protected abstract boolean grantContentAccessToGroupInRepository(ContentItem contentItemParam, String groupId)
738             throws ContentManagerException;
739 
740     /**
741      * @see pt.digitalis.dif.utils.extensions.cms.IContentManager#grantContentAccessToUser(java.lang.String,
742      *      pt.digitalis.dif.controller.security.objects.IDIFUser)
743      */
744     public boolean grantContentAccessToUser(String contentId, IDIFUser user) throws ContentManagerException
745     {
746         ContentItem contentItem = getContentByIdNoPermissions(contentId, user);
747 
748         if (contentItem == null)
749             throw new ContentItemNotFoundException(contentId);
750 
751         return grantContentAccessToUserInRepository(contentItem, user);
752     }
753 
754     /**
755      * Grants user access to content item
756      * 
757      * @param contentItemParam
758      *            the content to grant access
759      * @param user
760      *            the group to grant access
761      * @return T if access was granted, F otherwise.
762      * @throws ContentManagerException
763      */
764     protected abstract boolean grantContentAccessToUserInRepository(ContentItem contentItemParam, IDIFUser user)
765             throws ContentManagerException;
766 
767     /**
768      * @see pt.digitalis.dif.utils.extensions.cms.IContentManager#grantNodeAccessToGroup(java.lang.Long,
769      *      java.lang.String)
770      */
771     public boolean grantNodeAccessToGroup(Long nodeId, String groupId) throws ContentManagerException
772     {
773         Node node = getNodeByIdNoPermissions(nodeId, null);
774 
775         return grantNodeAccessToGroupInRepository(node, groupId);
776     }
777 
778     /**
779      * Grants group access to node
780      * 
781      * @param nodeParam
782      *            the node to grant access
783      * @param groupId
784      *            the group to grant access
785      * @return T if access was granted, F otherwise.
786      * @throws ContentManagerException
787      */
788     protected abstract boolean grantNodeAccessToGroupInRepository(Node nodeParam, String groupId)
789             throws ContentManagerException;
790 
791     /**
792      * @see pt.digitalis.dif.utils.extensions.cms.IContentManager#grantNodeAccessToUser(java.lang.Long,
793      *      pt.digitalis.dif.controller.security.objects.IDIFUser)
794      */
795     public boolean grantNodeAccessToUser(Long nodeId, IDIFUser user) throws ContentManagerException
796     {
797         Node node = this.getNodeByIdNoPermissions(nodeId, user);
798 
799         return grantNodeAccessToUserInRepository(node, user);
800     }
801 
802     /**
803      * @see pt.digitalis.dif.utils.extensions.cms.IContentManager#grantNodeAccessToUser(java.lang.String,
804      *      pt.digitalis.dif.controller.security.objects.IDIFUser)
805      */
806     public boolean grantNodeAccessToUser(String nodePath, IDIFUser user) throws ContentManagerException
807     {
808         Node node = getNodeByPathNoPermissions(nodePath, user);
809         return grantNodeAccessToUser(node.getId(), user);
810     }
811 
812     /**
813      * Grants user access to node
814      * 
815      * @param nodeParam
816      *            the node to grant access
817      * @param user
818      *            the group to grant access
819      * @return T if access was granted, F otherwise.
820      * @throws ContentManagerException
821      */
822     protected abstract boolean grantNodeAccessToUserInRepository(Node nodeParam, IDIFUser user)
823             throws ContentManagerException;
824 
825     /**
826      * Checks if group has access to the content
827      * 
828      * @param contentItem
829      *            the content to check access
830      * @param groupId
831      *            the group to check access
832      * @return T if group has access, F otherwise.
833      * @throws ContentManagerException
834      */
835     public boolean hasContentAccessGroup(ContentItem contentItem, String groupId) throws ContentManagerException
836     {
837         Node node = getNodeByIdNoPermissions(contentItem.getParentNodeId(), null);
838 
839         if (node.isPublic())
840             return true;
841 
842         Set<String> groups = new HashSet<String>();
843         groups.add(groupId);
844 
845         if (hasContentAccessGroupsInRepository(contentItem.getId(), groups))
846             return true;
847         else
848             return hasNodeAccessGroups(contentItem.getParentNodeId(), groups);
849     }
850 
851     /**
852      * @see pt.digitalis.dif.utils.extensions.cms.IContentManager#hasContentAccessGroup(java.lang.String,
853      *      java.lang.String)
854      */
855     public boolean hasContentAccessGroup(String contentId, String groupId) throws ContentManagerException
856     {
857         ContentItem contentItem = getContentByIdNoPermissions(contentId, null);
858 
859         return hasContentAccessGroup(contentItem, groupId);
860     }
861 
862     /**
863      * Checks if one of the group in the list has access to the content
864      * 
865      * @param contentItem
866      *            the content to check access
867      * @param groups
868      *            the group to check access
869      * @return T if group has access, F otherwise.
870      * @throws ContentManagerException
871      */
872     public boolean hasContentAccessGroups(ContentItem contentItem, Set<String> groups) throws ContentManagerException
873     {
874         Node node = getNodeByIdNoPermissions(contentItem.getParentNodeId(), null);
875 
876         if (node.isPublic())
877             return true;
878 
879         if (hasContentAccessGroupsInRepository(contentItem.getId(), groups))
880             return true;
881         else
882             return hasNodeAccessGroups(contentItem.getParentNodeId(), groups);
883     }
884 
885     /**
886      * Checks if one of the groups has access to the content
887      * 
888      * @param contentId
889      *            the id of the content to check access
890      * @param groups
891      *            the group list to check access
892      * @return T if group has access, F otherwise.
893      * @throws ContentManagerException
894      */
895     protected abstract boolean hasContentAccessGroupsInRepository(String contentId, Set<String> groups)
896             throws ContentManagerException;
897 
898     /**
899      * @see pt.digitalis.dif.utils.extensions.cms.IContentManager#hasContentAccessUser(pt.digitalis.dif.utils.extensions.cms.ContentItem,
900      *      pt.digitalis.dif.controller.security.objects.IDIFUser)
901      */
902     public boolean hasContentAccessUser(ContentItem contentItem, IDIFUser user) throws ContentManagerException
903     {
904         boolean result = false;
905         if (hasNodeAccessUser(contentItem.getParentNodeId(), user))
906         {
907             result = true;
908         }
909 
910         if (!result && hasContentAccessUserInRepository(contentItem.getId(), user))
911             result = true;
912 
913         try
914         {
915             if (!result && hasContentAccessGroups(contentItem, user.getGroupIDs()))
916                 result = true;
917         }
918         catch (IdentityManagerException e)
919         {
920             throw new ContentItemNotFoundException(e);
921         }
922 
923         return result;
924 
925     }
926 
927     /**
928      * @see pt.digitalis.dif.utils.extensions.cms.IContentManager#hasContentAccessUser(java.lang.String,
929      *      pt.digitalis.dif.controller.security.objects.IDIFUser)
930      */
931     public boolean hasContentAccessUser(String contentId, IDIFUser user) throws ContentManagerException
932     {
933         ContentItem contentItem = getContentByIdNoPermissions(contentId, user);
934 
935         if (contentItem == null)
936             throw new ContentItemNotFoundException(contentId);
937 
938         return hasContentAccessUser(contentItem, user);
939 
940     }
941 
942     /**
943      * Checks if group has access to thentent
944      * 
945      * @param contentId
946      *            the id of the content to check access
947      * @param user
948      *            the group to check access
949      * @return T if user has access, F otherwise.
950      * @throws ContentManagerException
951      */
952     protected abstract boolean hasContentAccessUserInRepository(String contentId, IDIFUser user)
953             throws ContentManagerException;
954 
955     /**
956      * @see pt.digitalis.dif.utils.extensions.cms.IContentManager#hasNodeAccessGroups(java.lang.Long, java.util.Set)
957      */
958     public boolean hasNodeAccessGroups(Long nodeId, Set<String> groups) throws ContentManagerException
959     {
960         Node node = getNodeByIdNoPermissions(nodeId, null);
961 
962         if (node.isPublic())
963             return true;
964 
965         if (hasNodeAccessGroupsInRepository(nodeId, groups))
966             return true;
967 
968         if (node.getParentNodeId() != null)
969             return hasNodeAccessGroups(node.getParentNodeId(), groups);
970 
971         return false;
972     }
973 
974     /**
975      * Checks if one of the groups has access to the node
976      * 
977      * @param nodeId
978      *            the id of the node to check access
979      * @param groups
980      *            the group list to check access
981      * @return T if group has access, F otherwise.
982      * @throws ContentManagerException
983      */
984     protected abstract boolean hasNodeAccessGroupsInRepository(Long nodeId, Set<String> groups)
985             throws ContentManagerException;
986 
987     /**
988      * @see pt.digitalis.dif.utils.extensions.cms.IContentManager#hasNodeAccessUser(java.lang.Long,
989      *      pt.digitalis.dif.controller.security.objects.IDIFUser)
990      */
991     public boolean hasNodeAccessUser(Long nodeId, IDIFUser user) throws ContentManagerException
992     {
993         Node node = getNodeByIdNoPermissions(nodeId, user);
994 
995         return hasNodeAccessUser(node, user);
996     }
997 
998     /**
999      * Checks if user has access to the node
1000      * 
1001      * @param node
1002      *            the node to check access
1003      * @param user
1004      *            the user to check access
1005      * @return T if user has access, F otherwise.
1006      * @throws ContentManagerException
1007      */
1008     public boolean hasNodeAccessUser(Node node, IDIFUser user) throws ContentManagerException
1009     {
1010         boolean result = false;
1011         if (node.isPublic())
1012             result = true;
1013 
1014         if (!result && hasNodeAccessUserInRespository(node.getId(), user))
1015             result = true;
1016 
1017         if (!result)
1018         {
1019             try
1020             {
1021                 result = hasNodeAccessGroups(node.getId(), user.getGroupIDs());
1022             }
1023             catch (IdentityManagerException e)
1024             {
1025                 new ContentManagerException(e);
1026             }
1027         }
1028 
1029         if (!result && node.getParentNodeId() != null)
1030         {
1031             Node parentNode = getNodeByIdNoPermissions(node.getParentNodeId(), null);
1032             result = hasNodeAccessUser(parentNode, user);
1033         }
1034 
1035         return result;
1036     }
1037 
1038     /**
1039      * Checks if user has access to the node
1040      * 
1041      * @param nodeId
1042      *            the id of the node to check access
1043      * @param user
1044      *            the group to check access
1045      * @return T if user has access, F otherwise.
1046      * @throws ContentManagerException
1047      */
1048     protected abstract boolean hasNodeAccessUserInRespository(Long nodeId, IDIFUser user)
1049             throws ContentManagerException;
1050 
1051     /**
1052      * Updates a content item
1053      * 
1054      * @param contentParam
1055      *            the content to update in the repository
1056      * @param user
1057      *            current user
1058      * @return the updated content
1059      * @throws ContentItemNotFoundException
1060      * @throws ContentItemWithDuplicateNameAndParentNodeException
1061      * @throws ContentManagerException
1062      */
1063     protected abstract ContentItem mergeContentInRepository(ContentItem contentParam, IDIFUser user)
1064             throws ContentItemNotFoundException, ContentItemWithDuplicateNameAndParentNodeException,
1065             ContentManagerException;
1066 
1067     /**
1068      * Updates a node
1069      * 
1070      * @param nodeParam
1071      *            the node to update in the repository
1072      * @param user
1073      *            current user
1074      * @return the updated content
1075      */
1076     protected abstract Node mergeNodeInRepository(Node nodeParam, IDIFUser user);
1077 
1078     /**
1079      * @see pt.digitalis.dif.utils.extensions.cms.IContentManager#moveContent(java.lang.String, java.lang.Long,
1080      *      pt.digitalis.dif.controller.security.objects.IDIFUser)
1081      */
1082     public boolean moveContent(String contentID, Long destinationNodeId, IDIFUser user) throws ContentManagerException
1083     {
1084         ContentItem contentItem = getContentById(contentID, user);
1085 
1086         if (contentItem == null)
1087             throw new ContentItemNotFoundException(contentID);
1088 
1089         Node node = getNodeByIdNoPermissions(destinationNodeId, user);
1090 
1091         if (!hasContentAccessUser(contentItem, user))
1092         {
1093             throw new NoAccessException("User has no access to the content");
1094         }
1095 
1096         if (!hasNodeAccessUser(node, user))
1097         {
1098             throw new NoAccessException("User has no access to the destination node");
1099         }
1100 
1101         moveContentInRepository(contentItem, node, user);
1102 
1103         return true;
1104     }
1105 
1106     /**
1107      * Moves content to another node
1108      * 
1109      * @param contentParam
1110      *            the content to update in the repository
1111      * @param nodeParam
1112      *            the node to move to
1113      * @param user
1114      *            the current user
1115      * @return the updated content
1116      * @throws ContentItemNotFoundException
1117      * @throws ContentManagerException
1118      */
1119     protected abstract ContentItem moveContentInRepository(ContentItem contentParam, Node nodeParam, IDIFUser user)
1120             throws ContentItemNotFoundException, ContentManagerException;
1121 
1122     /**
1123      * @see pt.digitalis.dif.utils.extensions.cms.IContentManager#moveNode(java.lang.Long, java.lang.Long,
1124      *      pt.digitalis.dif.controller.security.objects.IDIFUser)
1125      */
1126     public boolean moveNode(Long nodeID, Long destinationNodeId, IDIFUser user) throws ContentManagerException
1127     {
1128         Node node = getNodeByIdNoPermissions(nodeID, user);
1129 
1130         Node newParentNode = getNodeByIdNoPermissions(destinationNodeId, user);
1131 
1132         if (!hasNodeAccessUser(nodeID, user))
1133         {
1134             throw new NoAccessException("User has no access to the node");
1135         }
1136 
1137         if (!hasNodeAccessUser(destinationNodeId, user))
1138         {
1139             throw new NoAccessException("User has no access to the destination node");
1140         }
1141 
1142         node.setParentNodeId(newParentNode.getId());
1143 
1144         try
1145         {
1146             node.setFullPathName(determineFullPath(node));
1147         }
1148         catch (ContentManagerException e)
1149         {
1150             throw new NodeNotFoundException("Error determining full path");
1151         }
1152 
1153         moveNodeInRepository(node, user);
1154 
1155         return true;
1156     }
1157 
1158     /**
1159      * Moves node to another parent node
1160      * 
1161      * @param node
1162      *            the node to update in the repository
1163      * @param user
1164      *            the current user
1165      * @return the updated content
1166      */
1167     protected abstract Node moveNodeInRepository(Node node, IDIFUser user);
1168 
1169     /**
1170      * Searches a node by unique identifier.
1171      * 
1172      * @param id
1173      *            the node ID
1174      * @param user
1175      *            the current User
1176      * @return a list of all existing root nodes
1177      * @throws ContentManagerException
1178      */
1179     protected boolean nodeExists(Long id, IDIFUser user) throws ContentManagerException
1180     {
1181         return nodeExistsInRepository(id, user);
1182     }
1183 
1184     /**
1185      * Searches a node by unique identifier in the repository.
1186      * 
1187      * @param id
1188      *            the node ID
1189      * @param user
1190      *            the currentUser
1191      * @return a list of all existing root nodes
1192      * @throws ContentManagerException
1193      */
1194     protected abstract boolean nodeExistsInRepository(Long id, IDIFUser user) throws ContentManagerException;
1195 
1196     /**
1197      * Adds a new content to repository.<br>
1198      * Will assign the ID internally
1199      * 
1200      * @param content
1201      *            the content to update in the repository
1202      * @param user
1203      * @return the updated content
1204      * @throws ContentItemWithDuplicateNameAndParentNodeException
1205      * @throws ContentManagerException
1206      */
1207     protected abstract ContentItem persistContentInRepository(ContentItem content, IDIFUser user)
1208             throws ContentItemWithDuplicateNameAndParentNodeException, ContentManagerException;
1209 
1210     /**
1211      * Adds a new content to repository.<br>
1212      * Will assign the ID internally
1213      * 
1214      * @param node
1215      *            node to update in the repository
1216      * @param user
1217      *            the user persisting the node
1218      * @return the updated content
1219      * @throws NodeWithDuplicatePathException
1220      * @throws ContentManagerException
1221      */
1222     protected abstract Node persistNodeInRepository(Node node, IDIFUser user) throws NodeWithDuplicatePathException,
1223             ContentManagerException;
1224 
1225     /**
1226      * @see pt.digitalis.dif.utils.extensions.cms.IContentManager#revokeContentAccessToGroup(java.lang.String,
1227      *      java.lang.String)
1228      */
1229     public boolean revokeContentAccessToGroup(String contentId, String groupId) throws ContentManagerException
1230     {
1231         if (getContentByIdNoPermissions(contentId, null) == null)
1232             throw new ContentItemNotFoundException(contentId);
1233 
1234         return revokeContentAccessToGroupInRepository(contentId, groupId);
1235     }
1236 
1237     /**
1238      * Revokes group access to content item
1239      * 
1240      * @param contentId
1241      *            the id of the content to revoke access
1242      * @param groupId
1243      *            the group to revoke access
1244      * @return T if access was revoked, F otherwise.
1245      */
1246     protected abstract boolean revokeContentAccessToGroupInRepository(String contentId, String groupId);
1247 
1248     /**
1249      * @see pt.digitalis.dif.utils.extensions.cms.IContentManager#revokeContentAccessToUser(java.lang.String,
1250      *      pt.digitalis.dif.controller.security.objects.IDIFUser)
1251      */
1252     public boolean revokeContentAccessToUser(String contentId, IDIFUser user) throws ContentManagerException
1253     {
1254         if (getContentByIdNoPermissions(contentId, user) == null)
1255             throw new ContentItemNotFoundException(contentId);
1256 
1257         return revokeContentAccessToUserInRepository(contentId, user);
1258     }
1259 
1260     /**
1261      * Revokes user access to content item
1262      * 
1263      * @param contentId
1264      *            the id of the content to revoke access
1265      * @param user
1266      *            the group to revoke access
1267      * @return T if access was revoked, F otherwise.
1268      */
1269     protected abstract boolean revokeContentAccessToUserInRepository(String contentId, IDIFUser user);
1270 
1271     /**
1272      * @see pt.digitalis.dif.utils.extensions.cms.IContentManager#revokeNodeAccessToGroup(java.lang.Long,
1273      *      java.lang.String)
1274      */
1275     public boolean revokeNodeAccessToGroup(Long nodeId, String groupId) throws ContentManagerException
1276     {
1277         getNodeByIdNoPermissions(nodeId, null);
1278 
1279         return revokeNodeAccessToGroupInRepository(nodeId, groupId);
1280     }
1281 
1282     /**
1283      * Revokes group access to node
1284      * 
1285      * @param nodeId
1286      *            the id of the node to revoke access
1287      * @param groupId
1288      *            the group to revoke access
1289      * @return T if access was revoked, F otherwise.
1290      * @throws ContentManagerException
1291      */
1292     protected abstract boolean revokeNodeAccessToGroupInRepository(Long nodeId, String groupId)
1293             throws ContentManagerException;
1294 
1295     /**
1296      * @see pt.digitalis.dif.utils.extensions.cms.IContentManager#revokeNodeAccessToUser(java.lang.Long,
1297      *      pt.digitalis.dif.controller.security.objects.IDIFUser)
1298      */
1299     public boolean revokeNodeAccessToUser(Long nodeId, IDIFUser user) throws ContentManagerException
1300     {
1301         getNodeByIdNoPermissions(nodeId, user);
1302 
1303         return revokeNodeAccessToUserInRepository(nodeId, user);
1304     }
1305 
1306     /**
1307      * Revokes user access to node
1308      * 
1309      * @param nodeId
1310      *            the id of the node to revoke access
1311      * @param user
1312      *            the group to revoke access
1313      * @return T if access was revoked, F otherwise.
1314      * @throws ContentManagerException
1315      */
1316     protected abstract boolean revokeNodeAccessToUserInRepository(Long nodeId, IDIFUser user)
1317             throws ContentManagerException;
1318 
1319     /**
1320      * @see pt.digitalis.dif.utils.extensions.cms.IContentManager#updateContent(pt.digitalis.dif.utils.extensions.cms.ContentItem)
1321      */
1322     public ContentItem updateContent(ContentItem content) throws ContentManagerException
1323     {
1324         if (content == null)
1325             throw new ContentItemNotFoundException();
1326 
1327         if (content.getUser() == null)
1328         {
1329             throw new NoAccessException("The Content User attribute must be filled to complete the insert");
1330         }
1331 
1332         if (!hasContentAccessUser(content, content.getUser()))
1333             throw new NoAccessException("User doesn't have access to the parent node");
1334 
1335         ContentItem currentContent = getContentById(content.getId(), content.getUser());
1336 
1337         if (currentContent == null)
1338             throw new ContentItemNotFoundException();
1339 
1340         currentContent.setName(content.getName());
1341         currentContent.setDescription(content.getDescription());
1342         currentContent.setContent(content.getContent());
1343 
1344         return mergeContentInRepository(currentContent, content.getUser());
1345     }
1346 
1347     /**
1348      * @see pt.digitalis.dif.utils.extensions.cms.IContentManager#updateNode(pt.digitalis.dif.utils.extensions.cms.Node)
1349      */
1350     public Node updateNode(Node node) throws ContentManagerException
1351     {
1352         if (node == null)
1353             throw new NodeNotFoundException();
1354 
1355         if (node.getUser() == null)
1356         {
1357             throw new NoAccessException("The Node User attribute must be filled to complete the insert");
1358         }
1359 
1360         if (!hasNodeAccessUser(node, node.getUser()))
1361             throw new NoAccessException("User doesn't have access to the node");
1362 
1363         Node currentNode = getNodeByIdNoPermissions(node.getId(), node.getUser());
1364 
1365         currentNode.setDescription(node.getDescription());
1366         currentNode.setPublic(node.isPublic());
1367 
1368         if (!currentNode.getName().equals(node.getName()))
1369         {
1370 
1371             try
1372             {
1373                 node.setFullPathName(determineFullPath(node));
1374             }
1375             catch (ContentManagerException e)
1376             {
1377                 throw new NodeNotFoundException("Error determining full path");
1378             }
1379             currentNode.setName(node.getName());
1380             currentNode.setFullPathName(node.getFullPathName());
1381         }
1382 
1383         return mergeNodeInRepository(currentNode, node.getUser());
1384     }
1385 
1386     /**
1387      * Validates name and path
1388      * 
1389      * @param name
1390      *            full path
1391      * @param isPath
1392      *            check if it is a path
1393      * @return the validation result
1394      */
1395     private boolean validadeNameAndPath(String name, boolean isPath)
1396     {
1397         char ch;
1398         for (int i = 0; i < name.length(); i++)
1399         {
1400             ch = name.charAt(i);
1401 
1402             if (ch >= 'A' && ch <= 'Z')
1403                 continue;
1404             if (ch >= 'a' && ch <= 'z')
1405                 continue;
1406             if (ch >= '0' && ch <= '9')
1407                 continue;
1408             if (ch == '-' || ch == '_')
1409                 continue;
1410             if (isPath && ch == SEPARATOR)
1411                 continue;
1412 
1413             return false;
1414         }
1415 
1416         return true;
1417     }
1418 
1419 }