KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > slide > security > SecurityImpl


1 /*
2  * $Header: /home/cvs/jakarta-slide/src/share/org/apache/slide/security/SecurityImpl.java,v 1.53.2.5 2004/11/24 11:40:00 ozeigermann Exp $
3  * $Revision: 1.53.2.5 $
4  * $Date: 2004/11/24 11:40:00 $
5  *
6  * ====================================================================
7  *
8  * Copyright 1999-2002 The Apache Software Foundation
9  *
10  * Licensed under the Apache License, Version 2.0 (the "License");
11  * you may not use this file except in compliance with the License.
12  * You may obtain a copy of the License at
13  *
14  * http://www.apache.org/licenses/LICENSE-2.0
15  *
16  * Unless required by applicable law or agreed to in writing, software
17  * distributed under the License is distributed on an "AS IS" BASIS,
18  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19  * See the License for the specific language governing permissions and
20  * limitations under the License.
21  *
22  */

23
24 package org.apache.slide.security;
25
26 import java.lang.reflect.Constructor;
27 import java.lang.reflect.InvocationTargetException;
28 import java.util.ArrayList;
29 import java.util.Collections;
30 import java.util.Enumeration;
31 import java.util.HashMap;
32 import java.util.HashSet;
33 import java.util.Hashtable;
34 import java.util.Iterator;
35 import java.util.List;
36 import java.util.Map;
37 import java.util.Set;
38 import java.util.Vector;
39 import org.apache.slide.common.Namespace;
40 import org.apache.slide.common.NamespaceConfig;
41 import org.apache.slide.common.ServiceAccessException;
42 import org.apache.slide.common.SlideException;
43 import org.apache.slide.common.SlideToken;
44 import org.apache.slide.common.Uri;
45 import org.apache.slide.content.NodeProperty;
46 import org.apache.slide.content.NodeRevisionDescriptor;
47 import org.apache.slide.content.NodeRevisionDescriptors;
48 import org.apache.slide.content.NodeRevisionNumber;
49 import org.apache.slide.content.RevisionDescriptorNotFoundException;
50 import org.apache.slide.store.Store;
51 import org.apache.slide.structure.ActionNode;
52 import org.apache.slide.structure.LinkNode;
53 import org.apache.slide.structure.ObjectAlreadyExistsException;
54 import org.apache.slide.structure.ObjectNode;
55 import org.apache.slide.structure.ObjectNotFoundException;
56 import org.apache.slide.structure.SubjectNode;
57 import org.apache.slide.util.Configuration;
58 import org.apache.slide.util.XMLValue;
59 import org.apache.slide.util.logger.Logger;
60 import org.apache.slide.event.VetoException;
61 import org.apache.slide.event.EventDispatcher;
62 import org.apache.slide.event.SecurityEvent;
63 import org.jdom.JDOMException;
64
65 /**
66  * Security helper.
67  *
68  * @version $Revision: 1.53.2.5 $
69  */

70 public class SecurityImpl implements Security {
71     
72     private static final String LOG_CHANNEL = SecurityImpl.class.getName();
73     private static final String PRIVILEGE_MEMBER_SET = "privilege-member-set";
74     private static final String PRIVILEGE_NAMESPACE = "privilege-namespace";
75     protected Logger logger;
76     
77     
78     /**
79      * Constructor.
80      */

81     public SecurityImpl() {}
82     
83     /**
84      * Constructor.
85      *
86      * @param namespace Namespace
87      * @param namespaceConfig Namespace configuration
88      */

89     public SecurityImpl(Namespace namespace, NamespaceConfig namespaceConfig) {
90         init(namespace, namespaceConfig);
91     }
92     
93     public void init(Namespace namespace, NamespaceConfig namespaceConfig) {
94         this.namespace = namespace;
95         this.namespaceConfig = namespaceConfig;
96         this.rolesCache = new Hashtable();
97         aclInheritanceType = namespaceConfig.getAclInheritanceType();
98         logger = namespace.getLogger();
99     }
100     
101     // ----------------------------------------------------- Instance Variables
102

103     
104     /**
105      * Namespace.
106      */

107     protected Namespace namespace;
108     
109     
110     /**
111      * Namespace configuration.
112      */

113     protected NamespaceConfig namespaceConfig;
114     
115     
116     /**
117      * Roles cache.
118      * Role name -> Role interface.
119      */

120     protected Hashtable rolesCache;
121     
122     protected int aclInheritanceType;
123     
124     /**
125      * The actions that can modify objects in the repository. These are used
126      * to determine actions cache invalidation.
127      */

128     private Set modificationActions;
129     
130     // ------------------------------------------------------- Security Methods
131

132     
133     /**
134      * Set a new set of permissions on an object.
135      *
136      * @param token Credentials token
137      * @param object Object on which permission is granted
138      * @exception ServiceAccessException DataSource access error
139      * @exception ObjectNotFoundException Specified object was not found
140      * in the DataSource
141      * @exception AccessDeniedException Insufficent credentials
142      */

143     public void setPermissions(SlideToken token, String object,
144                                Enumeration permissions)
145         throws ServiceAccessException, ObjectNotFoundException,
146         AccessDeniedException {
147         
148         Uri objectUri = namespace.getUri(token, object);
149         ObjectNode objectNode = objectUri.getStore().retrieveObject(objectUri);
150         
151         checkCredentials(token, objectNode,
152                          namespaceConfig.getGrantPermissionAction());
153         checkCredentials(token, objectNode,
154                          namespaceConfig.getRevokePermissionAction());
155         
156         objectUri.getStore().revokePermissions(objectUri);
157         
158         while (permissions.hasMoreElements()) {
159             NodePermission permission =
160                 (NodePermission) permissions.nextElement();
161             objectUri.getStore().grantPermission(objectUri, permission);
162         }
163         
164     }
165     
166     
167     /**
168      * Grants a new permission.
169      *
170      * @param token Credentials token
171      * @param object Object on which permission is granted
172      * @param subject The subject to whom the permission is granted.
173      * @param action The action which the subject can perform
174      * @exception ServiceAccessException DataSource access error
175      * @exception ObjectNotFoundException Specified object was not found
176      * in the DataSource
177      * @exception AccessDeniedException Insufficent credentials
178      */

179     public void grantPermission(SlideToken token, ObjectNode object,
180                                 SubjectNode subject, ActionNode action)
181         throws ServiceAccessException, ObjectNotFoundException,
182         AccessDeniedException, VetoException {
183         grantPermission(token, object, subject, action, true);
184     }
185     
186     
187     /**
188      * Grants a new permission.
189      *
190      * @param token Credentials token
191      * @param object Object on which permission is granted
192      * @param subject Subject who can perform the action
193      * @param action Action which can be performed
194      * @param inheritable Create an inheritable permission
195      * @exception ServiceAccessException DataSource access error
196      * @exception ObjectNotFoundException Specified object was not found
197      * in the DataSource
198      * @exception AccessDeniedException Insufficent credentials
199      */

200     public void grantPermission(SlideToken token, ObjectNode object,
201                                 SubjectNode subject, ActionNode action,
202                                 boolean inheritable)
203         throws ServiceAccessException, ObjectNotFoundException,
204         AccessDeniedException, VetoException {
205         NodePermission permission = new NodePermission(object, subject, action,
206                                                        inheritable);
207         grantPermission(token, permission);
208     }
209     
210     
211     /**
212      * Grants a new permission.
213      *
214      * @param token Credentials token
215      * @param permission New permission
216      * @exception ServiceAccessException DataSource access error
217      * @exception ObjectNotFoundException Specified object was not found
218      * in the DataSource
219      * @exception AccessDeniedException Insufficent credentials
220      */

221     public void grantPermission(SlideToken token,
222                                 NodePermission permission)
223         throws ServiceAccessException, ObjectNotFoundException,
224         AccessDeniedException, VetoException {
225         Uri objectUri = namespace.getUri(token, permission.getObjectUri());
226         ObjectNode object = objectUri.getStore()
227             .retrieveObject(objectUri);
228         
229         // Checking if the permission is already present
230
Enumeration permissions = enumeratePermissions(token, object);
231         boolean alreadyPresent = false;
232         while (permissions.hasMoreElements() && !alreadyPresent) {
233             if (permission.equals(permissions.nextElement())) {
234                 alreadyPresent = true;
235             }
236         }
237         
238         if (!alreadyPresent) {
239             checkCredentials(token, object,
240                              namespaceConfig.getGrantPermissionAction());
241             objectUri.getStore().grantPermission(objectUri, permission);
242         }
243
244         // Fire event
245
if ( permission.isNegative() ) {
246             if ( SecurityEvent.DENY_PERMISSION.isEnabled() ) EventDispatcher.getInstance().fireVetoableEvent(SecurityEvent.DENY_PERMISSION, new SecurityEvent(this, token, namespace, objectUri, permission));
247         } else {
248             if ( SecurityEvent.GRANT_PERMISSION.isEnabled() ) EventDispatcher.getInstance().fireVetoableEvent(SecurityEvent.GRANT_PERMISSION, new SecurityEvent(this, token, namespace, objectUri, permission));
249         }
250     }
251     
252     
253     /**
254      * Deny a new permission.
255      *
256      * @param token Credentials token
257      * @param object Object on which permission is denied
258      * @param subject The subject to whom a action is denied
259      * @param action The action which is denied
260      * @exception ServiceAccessException DataSource access error
261      * @exception ObjectNotFoundException Specified object was not found
262      * in the DataSource
263      * @exception AccessDeniedException Insufficent credentials
264      */

265     public void denyPermission(SlideToken token, ObjectNode object,
266                                SubjectNode subject, ActionNode action)
267         throws ServiceAccessException, ObjectNotFoundException,
268         AccessDeniedException, VetoException {
269         denyPermission(token, object, subject, action, true);
270     }
271     
272     
273     /**
274      * Deny a new permission.
275      *
276      * @param token Credentials token
277      * @param object Object on which permission is granted
278      * @param subject Subject who can perform the action
279      * @param action Action which can be performed
280      * @param inheritable Create an inheritable permission
281      * @exception ServiceAccessException DataSource access error
282      * @exception ObjectNotFoundException Specified object was not found
283      * in the DataSource
284      * @exception AccessDeniedException Insufficent credentials
285      */

286     public void denyPermission(SlideToken token, ObjectNode object,
287                                SubjectNode subject, ActionNode action,
288                                boolean inheritable)
289         throws ServiceAccessException, ObjectNotFoundException,
290         AccessDeniedException, VetoException {
291         NodePermission permission = new NodePermission(object, subject, action,
292                                                        inheritable, true);
293         denyPermission(token, permission);
294     }
295     
296     
297     /**
298      * Deny a new permission.
299      *
300      * @param token Credentials token
301      * @param permission New permission
302      * @exception ServiceAccessException DataSource access error
303      * @exception ObjectNotFoundException Specified object was not found
304      * in the DataSource
305      * @exception AccessDeniedException Insufficent credentials
306      */

307     public void denyPermission(SlideToken token,
308                                NodePermission permission)
309         throws ServiceAccessException, ObjectNotFoundException,
310         AccessDeniedException, VetoException {
311         // Make sure the permission we're about to set is indeed a negative
312
// permission
313
if (!permission.isNegative())
314             permission.setNegative(true);
315         grantPermission(token, permission);
316     }
317     
318     
319     /**
320      * Revokes a permission.
321      *
322      * @param token Credentials token
323      * @param object Object on which permission is revoked
324      * @param subject Subject who can perform the action
325      * @param action Action which can be performed
326      * @exception ServiceAccessException DataSource access error
327      * @exception ObjectNotFoundException Specified object was not found
328      * in the DataSource
329      * @exception AccessDeniedException Insufficent credentials
330      */

331     public void revokePermission(SlideToken token, ObjectNode object,
332                                  SubjectNode subject, ActionNode action)
333         throws ServiceAccessException, ObjectNotFoundException,
334         AccessDeniedException, VetoException {
335         //Domain.info("Revoke permission on " + object.getUri());
336
checkCredentials(token, object, namespaceConfig
337                              .getRevokePermissionAction());
338         NodePermission permission = new NodePermission(object, subject,
339                                                        action);
340         Uri objectUri = namespace.getUri(token, object.getUri());
341         objectUri.getStore()
342             .revokePermission(objectUri, permission);
343
344         // Fire event
345
if ( SecurityEvent.REVOKE_PERMISSION.isEnabled() ) EventDispatcher.getInstance().fireVetoableEvent(SecurityEvent.REVOKE_PERMISSION, new SecurityEvent(this, token, namespace, objectUri, permission));
346     }
347     
348     
349     
350     /**
351      * Revokes a permission.
352      *
353      * @param token Credentials token
354      * @param permission Permission to be removed
355      * @exception ServiceAccessException DataSource access error
356      * @exception ObjectNotFoundException Specified object was not found
357      * in the DataSource
358      * @exception AccessDeniedException Insufficent credentials
359      */

360     public void revokePermission(SlideToken token, NodePermission permission)
361         throws ServiceAccessException, ObjectNotFoundException,
362         AccessDeniedException, VetoException {
363         
364         Uri objectUri = namespace.getUri(token, permission.getObjectUri());
365         ObjectNode object = objectUri.getStore().retrieveObject(objectUri);
366         
367         checkCredentials(token, object,
368                          namespaceConfig.getRevokePermissionAction());
369         objectUri.getStore().revokePermission(objectUri, permission);
370
371         // Fire event
372
if ( SecurityEvent.REVOKE_PERMISSION.isEnabled() ) EventDispatcher.getInstance().fireVetoableEvent(SecurityEvent.REVOKE_PERMISSION, new SecurityEvent(this, token, namespace, objectUri, permission));
373     }
374     
375     
376     /**
377      * Check if the credentials given grants permission to perform
378      * the specified action on the specified subject.
379      *
380      * @param token Credentials token
381      * @param object Object on which the action is performed
382      * @param action Action performed
383      * @exception ServiceAccessException DataSource access error
384      * @exception AccessDeniedException The credentials does not grant
385      * the permission to perform the specified action
386      */

387     public void checkCredentials(SlideToken token, ObjectNode object,
388                                  ActionNode action)
389         throws ServiceAccessException, AccessDeniedException {
390         
391         if (!token.isForceSecurity()) {
392             return;
393         }
394         
395         try {
396             if (Configuration.useIntegratedSecurity()) {
397                 // check if permission has already been checked
398
Boolean permission = token.checkPermissionCache(object, action);
399                 if (permission == null) {
400                     // if not checked before, check now
401
try {
402                         Uri objectUri = namespace.getUri(token, object.getUri());
403                         ObjectNode realObject = objectUri.getStore()
404                             .retrieveObject(objectUri);
405                         checkPermission(token, realObject, action);
406                         token.cachePermission(object, action, true);
407                     } catch (AccessDeniedException ade) {
408                         token.cachePermission(object, action, false);
409                         ade.fillInStackTrace();
410                         throw ade;
411                     }
412                 }
413                 else {
414                     if (!(permission.booleanValue())) {
415                         throw new AccessDeniedException
416                             (object.getUri(),
417                              getPrincipal(token).getPath().toString(),
418                              action.getUri());
419                     }
420                 }
421             }
422         } catch (ObjectNotFoundException e) {
423             String subjectUri = "*** Could not determine principal ***";
424             try {
425                 subjectUri = getPrincipal(token).getPath().toString();
426             } catch (Exception x) {}
427             throw new AccessDeniedException
428                 (object.getUri(),
429                  subjectUri,
430                  action.getUri());
431         }
432     }
433     
434     
435     /**
436      * Check whether or not an actor can perform the specified activity
437      * on a collection.
438      *
439      * @param object Object on which access is tested
440      * @param subject Subject who seeks to perform the action
441      * @param action Action which is to be performed
442      * @exception ServiceAccessException DataSource access error
443      * @exception ObjectNotFoundException Specified object was not found
444      * in the DataSource
445      * @exception AccessDeniedException Insufficent credentials
446      */

447     public void checkPermission(ObjectNode object, SubjectNode subject,
448                                 ActionNode action)
449         throws ServiceAccessException, AccessDeniedException,
450         ObjectNotFoundException {
451         if (!hasPermission(object, subject, action)) {
452             throw new AccessDeniedException(object.getUri(), subject.getUri(),
453                                             action.getUri());
454         }
455
456         determineActionsCacheInvalidation(object, action);
457     }
458     
459     /**
460      * Check whether or not an actor (principal) can perform the specified activity
461      * on the specified resource.
462      *
463      * @param token a SlideToken
464      * @param object Object on which access is tested
465      * @param action Action which is to be performed
466      *
467      * @throws ServiceAccessException
468      * @throws AccessDeniedException
469      * @throws ObjectNotFoundException
470      */

471     public void checkPermission(SlideToken token, ObjectNode object, ActionNode action) throws ServiceAccessException, AccessDeniedException, ObjectNotFoundException {
472         if (!hasPermission(token, object, action)) {
473             throw new AccessDeniedException(object.getUri(), getPrincipal(token).getUri(),
474                                             action.getUri());
475         }
476
477         determineActionsCacheInvalidation(object, action);
478     }
479     
480     
481     /**
482      * Check whether or not an actor can perform the specified activity
483      * on a collection.
484      *
485      * @param object Object on which access is tested
486      * @param subject Subject who seeks to perform the action
487      * @param action Action which is to be performed
488      * @return true if the action can be performed
489      * @exception ServiceAccessException DataSource access error
490      * @exception ObjectNotFoundException Specified object was not found
491      * in the DataSource
492      */

493     public boolean hasPermission(ObjectNode object, SubjectNode subject,
494                                  ActionNode action)
495         throws ServiceAccessException, ObjectNotFoundException {
496         
497         // no check for default action (server intitialization)
498
if (action.equals(ActionNode.DEFAULT)) {
499             return true;
500         }
501         
502         boolean granted = false;
503         boolean denied = false;
504         boolean rootObjectReached = false;
505         
506         ObjectNode courObject = object;
507         
508         Uri subjectUri = namespace.getUri(subject.getUri());
509         Uri actionUri = namespace.getUri(action.getUri());
510         
511         // check if allready granded
512

513         while (!granted && !denied && !rootObjectReached) {
514             
515             Uri courUri = namespace.getUri(courObject.getUri());
516             Enumeration permissions = courUri.getStore()
517                 .enumeratePermissions(courUri);
518             
519             while (permissions.hasMoreElements()) {
520                 
521                 boolean oldGranted = granted;
522                 boolean oldDenied = denied;
523                 
524                 NodePermission permission =
525                     (NodePermission) permissions.nextElement();
526                 String permissionSubject = permission.getSubjectUri();
527                 
528                 if (permissionSubject.equals(SubjectNode.SELF_URI)) {
529                     
530                     boolean check;
531                     check = object.getUri().equals(subjectUri.toString());
532                     if (permission.isInheritable()) {
533                         String subjectUriString = subjectUri.toString();
534                         if(!subjectUriString.endsWith("/"))
535                             subjectUriString = subjectUriString + "/";
536                         
537                         check |= object.getUri().startsWith(subjectUriString);
538                     }
539                     
540                     // Self permission
541
granted = (!permission.isNegative())
542                         && (check)
543                         && (actionUri.toString()
544                                 .startsWith(permission.getActionUri()));
545                     denied = (permission.isNegative())
546                         && (check)
547                         && (actionUri.toString()
548                                 .startsWith(permission.getActionUri()));
549                     
550                 } else if (permission.isInheritable()
551                            || permission.getObjectUri().equals(object.getUri())) {
552                     
553                     if (permissionSubject.startsWith("/")) {
554                         
555                         // Node permission
556

557                         String permSubj = permission.getSubjectUri();
558                         if(!permSubj.endsWith("/"))
559                             permSubj = permSubj + "/";
560                         boolean match = subjectUri.toString().
561                             equals(permission.getSubjectUri()) ||
562                             subjectUri.toString().startsWith(permSubj);
563                         match &= actionUri.toString().
564                             startsWith(permission.getActionUri());
565                         
566                         granted = (!permission.isNegative()) && match;
567                         denied = permission.isNegative() && match;
568                         
569                     } else if (permissionSubject.startsWith("+")) {
570                         
571                         // Permission group which needs to be expanded
572
Uri permissionSubjectUri =
573                             namespace.getUri(permissionSubject.substring(1));
574                         ObjectNode group =
575                             permissionSubjectUri.getStore().retrieveObject
576                             (permissionSubjectUri);
577                         // if the node is a GroupNode, expand it out to
578
// normal permissions
579
if (group instanceof
580                             org.apache.slide.structure.GroupNode ) {
581                             if (group.hasChildren()) {
582                                 Enumeration groupMembers =
583                                     group.enumerateChildren();
584                                 // parse thru the children of the group and
585
// check permissions on each
586
while (groupMembers.hasMoreElements()) {
587                                     
588                                     oldGranted = granted;
589                                     oldDenied = denied;
590                                     
591                                     Uri childUri =
592                                         namespace.getUri
593                                         ((String) groupMembers.nextElement());
594                                     ObjectNode childNode =
595                                         childUri.getStore().retrieveObject
596                                         (childUri);
597                                     String childSubjectUri = childNode
598                                         instanceof LinkNode ?
599                                         ((LinkNode) childNode)
600                                         .getLinkedUri() :
601                                         childNode.getUri() ;
602                                     
603                                     String testUri;
604                                     if(!childSubjectUri.endsWith("/"))
605                                         testUri = childSubjectUri+"/";
606                                     else
607                                         testUri = childSubjectUri;
608                                     
609                                     boolean match = subjectUri.toString().
610                                         equals(childSubjectUri) ||
611                                         subjectUri.toString().
612                                         startsWith(testUri);
613                                     match &= actionUri.toString().
614                                         startsWith(permission.getActionUri());
615                                     
616                                     granted = (!permission.isNegative()) &&
617                                         match;
618                                     denied = permission.isNegative() && match;
619                                     
620                                     granted = granted | oldGranted;
621                                     denied = denied | oldDenied;
622                                     
623                                 }
624                             }
625                         }
626                         
627                     } else {
628                         
629                         // Role permission
630
granted = (!permission.isNegative())
631                             && (hasRole(subject, permissionSubject))
632                             && (actionUri.toString()
633                                     .startsWith(permission.getActionUri()));
634                         denied = (permission.isNegative())
635                             && (hasRole(subject, permissionSubject))
636                             && (actionUri.toString()
637                                     .startsWith(permission.getActionUri()));
638                         
639                     }
640                     
641                 }
642                 
643                 granted = granted | oldGranted;
644                 denied = denied | oldDenied;
645                 
646             }
647             
648             Uri parentUri = courUri.getParentUri();
649             
650             if (parentUri != null) {
651                 courObject = parentUri.getStore()
652                     .retrieveObject(parentUri);
653             } else {
654                 rootObjectReached = true;
655             }
656         }
657         
658         // Negative permissions have priority (if they're defined on the same
659
// node)
660
if (denied) {
661             return false;
662         }
663         
664         if (!granted) {
665             return false;
666         }
667         
668         return true;
669         
670     }
671     
672     /**
673      * Check whether or not an actor (principal) can perform the specified activity
674      * on the specified resource.
675      *
676      * @param token a SlideToken
677      * @param object Object on which access is tested
678      * @param action Action which is to be performed
679      *
680      * @return true if the action can be performed
681      *
682      * @throws ServiceAccessException
683      * @throws ObjectNotFoundException
684      */

685     public boolean hasPermission(SlideToken token, ObjectNode object, ActionNode action) throws ServiceAccessException, ObjectNotFoundException {
686         Boolean cachedPermission = token.checkPermissionCache(object, action);
687         if (cachedPermission != null) {
688             return cachedPermission.booleanValue();
689         }
690         else {
691             return hasPermission(object, (SubjectNode)getPrincipal(token), action);
692         }
693     }
694     
695     
696     /**
697      * Enumerates permissions on an object.
698      *
699      * @param token Credentials token
700      * @param object Object on which permission is granted
701      * @exception ServiceAccessException DataSource access error
702      * @exception ObjectNotFoundException Specified object was not found
703      * in the DataSource
704      * @exception AccessDeniedException Insufficent credentials
705      */

706     public Enumeration enumeratePermissions(SlideToken token,
707                                             ObjectNode object)
708         throws ServiceAccessException, ObjectNotFoundException,
709         AccessDeniedException {
710         
711         return enumeratePermissions(token, object, false);
712     }
713     
714     
715     /**
716      * Enumerates permissions on an object.
717      *
718      * @param token Credentials token
719      * @param object Object on which permission is granted
720      * @exception ServiceAccessException DataSource access error
721      * @exception ObjectNotFoundException Specified object was not found
722      * in the DataSource
723      * @exception AccessDeniedException Insufficent credentials
724      */

725     public Enumeration enumeratePermissions(SlideToken token,
726                                             ObjectNode object,
727                                             boolean includeInherited)
728         throws ServiceAccessException, ObjectNotFoundException {
729         return enumeratePermissions(token, object.getUri(), includeInherited);
730     }
731     
732     
733     /**
734      * Enumerates permissions on an object.
735      *
736      * @param token Credentials token
737      * @param object Object on which permission is granted
738      * @exception ServiceAccessException DataSource access error
739      * @exception ObjectNotFoundException Specified object was not found
740      * in the DataSource
741      * @exception AccessDeniedException Insufficent credentials
742      */

743     public Enumeration enumeratePermissions(SlideToken token,
744                                             String object)
745         throws ServiceAccessException, ObjectNotFoundException,
746         AccessDeniedException {
747         
748         return enumeratePermissions(token, object, false);
749     }
750     
751     
752     /**
753      * Enumerates permissions on an object.
754      *
755      * @param token Credentials token
756      * @param object Object on which permission is granted
757      * @exception ServiceAccessException DataSource access error
758      * @exception ObjectNotFoundException Specified object was not found
759      * in the DataSource
760      * @exception AccessDeniedException Insufficent credentials
761      */

762     public Enumeration enumeratePermissions(SlideToken token,
763                                             String object,
764                                             boolean includeInherited)
765         throws ServiceAccessException, ObjectNotFoundException {
766         
767         Uri objectUri = namespace.getUri(token, object);
768         if (!includeInherited) {
769             return objectUri.getStore().enumeratePermissions(objectUri);
770         }
771         else {
772             ObjectNode objectNode = objectUri.getStore().retrieveObject(objectUri);
773             Iterator i = retrieveAclSourceNodes(token, objectNode).iterator();
774             Vector permissions = new Vector();
775             while (i.hasNext()) {
776                 ObjectNode oNode = (ObjectNode)i.next();
777                 Uri oUri = namespace.getUri(token, oNode.getUri());
778                 Enumeration permEnum = oUri.getStore().enumeratePermissions(oUri);
779                 while (permEnum.hasMoreElements()) {
780                     NodePermission perm = (NodePermission)permEnum.nextElement();
781                     if (object.equals(oNode.getUri())) {
782                         // FIXME A node should not be able to inherit permissions from itself.
783
// Hide this from the client when it happens.
784
perm.setInheritedFrom(null);
785                         permissions.add(perm);
786                     }
787                     else if (perm.isInheritable()) {
788                         perm.setInheritedFrom(oNode.getUri());
789                         permissions.add(perm);
790                     }
791                 }
792             }
793             return permissions.elements();
794         }
795     }
796     
797     
798     /**
799      * Retrieve the list of object nodes from which to get the ACLs.
800      * The specified object is returned as first element of the list.
801      *
802      * @param token a SlideToken
803      * @param object an ObjectNode
804      *
805      * @return a List of ObjectNode
806      *
807      * @throws ServiceAccessException
808      * @throws ObjectNotFoundException
809      */

810     public List retrieveAclSourceNodes(SlideToken token, ObjectNode object)
811         throws ServiceAccessException, ObjectNotFoundException {
812         
813         List result = new ArrayList();
814         
815         Uri uri;
816         switch (aclInheritanceType) {
817             case NamespaceConfig.ACL_INHERIT_TYPE_NONE:
818                 uri = namespace.getUri(token, object.getUri());
819                 result.add( uri.getStore().retrieveObject(uri) );
820                 break;
821             case NamespaceConfig.ACL_INHERIT_TYPE_ROOT:
822                 uri = namespace.getUri(token, object.getUri());
823                 Uri rootUri = namespace.getUri(token, uri.getScope().toString());
824                 result.add( uri.getStore().retrieveObject(uri) );
825                 result.add( rootUri.getStore().retrieveObject(rootUri) );
826                 break;
827             case NamespaceConfig.ACL_INHERIT_TYPE_PATH:
828                 uri = namespace.getUri(token, object.getUri());
829                 Enumeration enum = uri.getScopes();
830                 while (enum.hasMoreElements()) {
831                     Uri element = namespace.getUri(token, (String)enum.nextElement());
832                     ObjectNode objectNode = element.getStore().retrieveObject(element);
833                     result.add(objectNode);
834                 }
835                 break;
836             case NamespaceConfig.ACL_INHERIT_TYPE_FULL:
837                 //TODO
838
break;
839             default:
840                 break;
841         }
842         
843         return result;
844     }
845     
846     /**
847      * Check whether or not the current user has the specified role.
848      *
849      * @param token Credentials token
850      * @param role Role
851      * @exception ServiceAccessException DataSource access error
852      * @exception ObjectNotFoundException Specified object was not found
853      * in the DataSource
854      */

855     public boolean hasRole(SlideToken token, String role)
856         throws ServiceAccessException, ObjectNotFoundException {
857         
858         ObjectNode subject = getPrincipal(token);
859         
860         return hasRole(subject, role);
861         
862     }
863     
864     
865     /**
866      * Check whether or not the current user has the specified role.
867      *
868      * @param object Object node
869      * @param role Role
870      * @exception ServiceAccessException DataSource access error
871      * @exception ObjectNotFoundException Specified object was not found
872      * in the DataSource
873      */

874     public boolean hasRole(ObjectNode object, String role)
875         throws ServiceAccessException, ObjectNotFoundException {
876         
877         if (role.equals(NamespaceConfig.NOBODY))
878             return true;
879         String associatedRole = namespaceConfig.getRoleMapping(role);
880         if ((associatedRole != null)
881             && (associatedRole.equals(NamespaceConfig.NOBODY)))
882             return true;
883         
884         Class roleClass = (Class) rolesCache.get(role);
885         if ((roleClass == null) && (associatedRole != null)) {
886             roleClass = (Class) rolesCache.get(associatedRole);
887             if (roleClass == null) {
888                 try {
889                     roleClass = Class.forName(associatedRole);
890                     rolesCache.put(role, roleClass);
891                     rolesCache.put(associatedRole, roleClass);
892                 } catch (ClassNotFoundException ex) {
893                 }
894             }
895         }
896         if (roleClass == null) {
897             try {
898                 roleClass = Class.forName(role);
899                 rolesCache.put(role, roleClass);
900             } catch (ClassNotFoundException e) {
901             }
902         }
903         if (roleClass == null) {
904             return false;
905         }
906         
907         if (roleClass.isInstance(object))
908             return true;
909         
910         return false;
911         
912     }
913     
914     
915     /**
916      * Return the list of roles the specified node has.
917      *
918      * @param object Object node
919      */

920     public Enumeration getRoles(ObjectNode object) {
921         
922         Vector result = new Vector();
923         result.addElement(NamespaceConfig.NOBODY);
924         
925         Class currentObjectClass = object.getClass();
926         
927         while (!currentObjectClass.equals(ObjectNode.class)) {
928             
929             Class[] interfaces = currentObjectClass.getInterfaces();
930             for (int i = 0; i < interfaces.length; i++) {
931                 String className = interfaces[i].getName();
932                 String associatedName =
933                     namespaceConfig.getRoleMapping(className);
934                 if (associatedName != null)
935                     result.addElement(associatedName);
936                 else
937                     result.addElement(className);
938             }
939             
940             currentObjectClass = currentObjectClass.getSuperclass();
941             if (currentObjectClass == null) {
942                 // Illegal state
943
throw new IllegalStateException("Invalid node");
944             }
945             
946         }
947         
948         return result.elements();
949         
950     }
951     
952     
953     /**
954      * Return the list of roles the specified token has.
955      *
956      * @param token Credentials token
957      */

958     public Enumeration getRoles(SlideToken token)
959         throws ServiceAccessException, ObjectNotFoundException {
960         return getRoles(getPrincipal(token));
961     }
962     
963     public Enumeration getRoles(SlideToken token, SubjectNode subjectNode)
964         throws ServiceAccessException, ObjectNotFoundException {
965         return getRoles(subjectNode);
966     }
967     
968     /**
969      * Get the SubjectNode associated with the credentials token.
970      *
971      * @param token a SlideToken
972      * @return an ObjectNode
973      * @throws ServiceAccessException
974      * @throws ObjectNotFoundException
975      */

976     public ObjectNode getPrincipal(SlideToken token)
977         throws ServiceAccessException, ObjectNotFoundException {
978         
979         String user =
980             token.getCredentialsToken().getPublicCredentials();
981         if ((user == null) || user.equals("") || user.equals("/")) {
982             return SubjectNode.UNAUTHENTICATED;
983         }
984         
985         Uri subjectUri = namespace.getUri
986             (token, namespaceConfig.getUsersPath()+"/"+user);
987         
988         try {
989             return subjectUri.getStore().retrieveObject(subjectUri);
990         } catch (ObjectNotFoundException e) {
991             if (!namespaceConfig.isAutoCreateUsers()) {
992                 throw e;
993             }
994             else {
995                 try {
996                     Uri parentUri = subjectUri.getParentUri();
997                     ObjectNode parent =
998                         subjectUri.getStore().retrieveObject(parentUri);
999                     Enumeration childrenEnum = parent.enumerateChildren();
1000                    Enumeration linksEnum = parent.enumerateLinks();
1001                    Vector children = new Vector();
1002                    while (childrenEnum.hasMoreElements()) {
1003                        children.addElement(childrenEnum.nextElement());
1004                    }
1005                    children.addElement(subjectUri.toString());
1006                    Vector links = new Vector();
1007                    while (linksEnum.hasMoreElements()) {
1008                        links.addElement(linksEnum.nextElement());
1009                    }
1010                    
1011                    // First, load the object's class
1012
Class objectClass = Class.forName
1013                        (namespaceConfig.getAutoCreateUsersRole());
1014                    Class[] types = { String.class };
1015                    Object[] args = { subjectUri.toString() };
1016                    Constructor constructor =
1017                        objectClass.getConstructor(types);
1018                    ObjectNode object =
1019                        (ObjectNode) constructor.newInstance(args);
1020                    subjectUri.getStore().createObject(subjectUri, object);
1021                    
1022                    Class[] types2 =
1023                    { String.class, Vector.class, Vector.class };
1024                    Object[] args2 = { parentUri.toString(), children, links };
1025                    constructor = parent.getClass().getConstructor(types2);
1026                    object = (ObjectNode) constructor.newInstance(args2);
1027                    parentUri.getStore().storeObject(parentUri, object);
1028                    
1029                    NodeRevisionNumber initialRevision = new NodeRevisionNumber(1, 0); // new NodeRevisionNumber();
1030
Hashtable workingRevisions = new Hashtable();
1031                    workingRevisions.put(NodeRevisionDescriptors.MAIN_BRANCH, initialRevision);
1032                    Hashtable latestRevisionNumbers = new Hashtable();
1033                    latestRevisionNumbers.put(NodeRevisionDescriptors.MAIN_BRANCH, initialRevision);
1034                    Hashtable branches = new Hashtable();
1035                    branches.put(initialRevision, new Vector());
1036                    boolean isVersioned = false;
1037
1038                    NodeRevisionDescriptors revisionDescriptors = new NodeRevisionDescriptors(subjectUri.toString(),
1039                            initialRevision, workingRevisions, latestRevisionNumbers, branches, isVersioned);
1040
1041                    NodeRevisionDescriptor revisionDescriptor = new NodeRevisionDescriptor(initialRevision,
1042                            NodeRevisionDescriptors.MAIN_BRANCH, new Vector(), new Hashtable());
1043
1044                    subjectUri.getStore().createRevisionDescriptors(subjectUri, revisionDescriptors);
1045                    subjectUri.getStore().createRevisionDescriptor(subjectUri, revisionDescriptor);
1046                    
1047                } catch (ClassNotFoundException ex) {
1048                    // Can't find role implementing class
1049
throw new ObjectNotFoundException(subjectUri);
1050                } catch (NoSuchMethodException ex) {
1051                    // Can't find appropriate constructor
1052
throw new ObjectNotFoundException(subjectUri);
1053                } catch (InstantiationException ex) {
1054                    // Can't instatiate object
1055
throw new ObjectNotFoundException(subjectUri);
1056                } catch (InvocationTargetException ex) {
1057                    // Can't invoke constructor
1058
throw new ObjectNotFoundException(subjectUri);
1059                } catch (IllegalAccessException ex) {
1060                    // Constructor is not public
1061
throw new ObjectNotFoundException(subjectUri);
1062                } catch (ObjectAlreadyExistsException ex) {
1063                    // Should never happen
1064
ex.printStackTrace();
1065                    throw new ObjectNotFoundException(subjectUri);
1066                }
1067                return subjectUri.getStore().retrieveObject(subjectUri);
1068            }
1069        }
1070    }
1071    
1072    /**
1073     * Get the direct aggregates
1074     *
1075     * @param aNode an ActionNode
1076     * @return set of direct aggregates (ActionNode objects)
1077     * @throws SlideException
1078     * @throws JDOMException
1079     */

1080    private static synchronized Set getActionAggregates(SecurityImpl security, SlideToken token, ActionNode aNode) throws SlideException, JDOMException {
1081        Set result = new HashSet();
1082        Uri aNodeUri = security.namespace.getUri(token, aNode.getUri());
1083        NodeRevisionDescriptor aNrd = aNodeUri.getStore().retrieveRevisionDescriptor(aNodeUri, new NodeRevisionNumber());
1084        NodeProperty membersProp = aNrd.getProperty(PRIVILEGE_MEMBER_SET);
1085        if (membersProp != null && membersProp.getValue() != null) {
1086            XMLValue membersVal;
1087            if (membersProp.getValue() instanceof XMLValue) {
1088                membersVal = (XMLValue)membersProp.getValue();
1089            }
1090            else {
1091                membersVal = new XMLValue((String)membersProp.getValue());
1092            }
1093            security.logger.log(membersVal.getHrefStrings(), LOG_CHANNEL, Logger.DEBUG);
1094            Iterator mUris = membersVal.getHrefStrings().iterator();
1095            while (mUris.hasNext()) {
1096                String uriAsString = (String)mUris.next();
1097                Uri uri = security.namespace.getUri(token, uriAsString);
1098                NodeRevisionNumber latestRevisionNumber = aNodeUri.getStore().retrieveRevisionDescriptors(uri).getLatestRevision();
1099                if (latestRevisionNumber != null) {
1100                    NodeProperty privilegeNamespace = aNodeUri.getStore().retrieveRevisionDescriptor(uri, latestRevisionNumber).getProperty(PRIVILEGE_NAMESPACE, "DAV:");
1101                    org.jdom.Namespace namespace = null;
1102                    if (privilegeNamespace != null && privilegeNamespace.getValue() instanceof String) {
1103                        namespace = org.jdom.Namespace.getNamespace((String) privilegeNamespace.getValue());
1104                    } else {
1105                        namespace = org.jdom.Namespace.getNamespace("DAV:");
1106                    }
1107                    result.add(ActionNode.getActionNode(uriAsString, namespace));
1108                }
1109            }
1110        }
1111        return result;
1112    }
1113    
1114    /**
1115     * Return true, if-and-only-if checkAction matches permAction.
1116     *
1117     * @param checkAction the "current" action
1118     * @param permAction the action to check against
1119     * (from NodePermission or NodeLock)
1120     *
1121     * @return a boolean
1122     *
1123     */

1124    public boolean matchAction(SlideToken token, ActionNode checkAction, ActionNode permAction) throws ServiceAccessException {
1125        if (permAction.equals(ActionNode.ALL)) {
1126            return true;
1127        }
1128        Map actionAggregationClosure = getActionAggregationClosureImpl(this, token, checkAction.getUri());
1129        Set permActionSet = (Set)actionAggregationClosure.get(permAction);
1130        if (permActionSet == null) {
1131            logger.log("Unknown action " + permAction.getUri() , LOG_CHANNEL, Logger.WARNING);
1132            return false;
1133        }
1134        return permActionSet.contains(checkAction);
1135    }
1136
1137    /**
1138     * Return true, if-and-only-if checkSubject matches permSubject.
1139     *
1140     * @param token a SlideToken
1141     * @param checkSubject the "current" principal
1142     * @param matchSubject the principal to check against (e.g. user
1143     * or group from NodePermission or NodeLock)
1144     *
1145     * @return a boolean
1146     *
1147     * @throws ServiceAccessException
1148     *
1149     */

1150    public boolean matchPrincipal(SlideToken token, SubjectNode checkSubject, SubjectNode matchSubject) throws ServiceAccessException {
1151        Boolean b = token.checkMatchPrincipalCache(checkSubject, matchSubject);
1152        if (b != null) {
1153            return b.booleanValue();
1154        }
1155        else {
1156            boolean match = matchPrincipal(token, checkSubject, matchSubject, namespaceConfig.getNestedRolesMaxDepth());
1157            token.cacheMatchPrincipal(checkSubject, matchSubject, match);
1158            return match;
1159        }
1160    }
1161    
1162    /**
1163     * Return true, if-and-only-if checkSubject matches permSubject.
1164     *
1165     * @param token a SlideToken
1166     * @param checkSubject the "current" principal
1167     * @param matchSubject the principal to check against (e.g. user
1168     * or group from NodePermission or NodeLock)
1169     *
1170     * @return a boolean
1171     *
1172     * @throws ServiceAccessException
1173     *
1174     */

1175    public boolean matchPrincipal(SlideToken token, SubjectNode checkSubject, SubjectNode matchSubject, int level) throws ServiceAccessException {
1176        if (matchSubject.equals(checkSubject)) {
1177            return true;
1178        }
1179        else {
1180            Uri groupUri = namespace.getUri(token, matchSubject.getUri());
1181            try {
1182                NodeRevisionDescriptor nrd =
1183                    groupUri.getStore().retrieveRevisionDescriptor(groupUri, new NodeRevisionNumber());
1184                NodeProperty membersetProp = nrd.getProperty("group-member-set");
1185                if (membersetProp != null && membersetProp.getValue() != null) {
1186                    XMLValue xmlVal = new XMLValue((String)membersetProp.getValue());
1187                    List memberNodes = xmlVal.getHrefNodes();
1188                    if (memberNodes.contains(checkSubject)) {
1189                        return true;
1190                    }
1191                    else if (level > 0) {
1192                        int nextLevel = level - 1;
1193                        boolean match = false;
1194                        Iterator i = memberNodes.iterator();
1195                        while (!match && i.hasNext()) {
1196                            SubjectNode nextMatchNode = (SubjectNode)i.next();
1197                            if (namespaceConfig.isRole(nextMatchNode.getUri())
1198                                || namespaceConfig.isGroup(nextMatchNode.getUri())) {
1199                                
1200                                match = matchPrincipal(token, checkSubject, nextMatchNode, nextLevel);
1201                            }
1202                        }
1203                        return match;
1204                    }
1205                    else {
1206                        return false;
1207                    }
1208                }
1209                else {
1210                    return false;
1211                }
1212            }
1213            catch (RevisionDescriptorNotFoundException e) {
1214                return false;
1215            }
1216            catch (ServiceAccessException e) {
1217                throw e;
1218            }
1219            catch (JDOMException e) {
1220                e.printStackTrace();
1221                return false;
1222            }
1223        }
1224    }
1225    
1226    /**
1227     * Method getActionAggregation
1228     * @return a Map: actionNode -> Set-of-aggregated-nodes (direct aggregates)
1229     */

1230    public Map getActionAggregation(SlideToken token) {
1231        logger.log("Action aggregation being retrieved", LOG_CHANNEL, Logger.DEBUG);
1232        return Collections.unmodifiableMap(getActionAggregationImpl(this, token));
1233    }
1234
1235    /**
1236     * Get the actions that modify objects in the repository. Which actions
1237     * these are is defined in the configuration.
1238     *
1239     * @return The actions that modify objects in the repository.
1240     */

1241    private synchronized Set getModificationActions() {
1242        if (this.modificationActions == null) {
1243            Set modificationActions = new HashSet();
1244            modificationActions.add(namespaceConfig.getBindMemberAction());
1245            modificationActions.add(namespaceConfig.getCreateObjectAction());
1246            modificationActions.add(namespaceConfig.getCreateRevisionContentAction());
1247            modificationActions.add(namespaceConfig.getCreateRevisionMetadataAction());
1248            modificationActions.add(namespaceConfig.getModifyRevisionContentAction());
1249            modificationActions.add(namespaceConfig.getModifyRevisionMetadataAction());
1250            modificationActions.add(namespaceConfig.getRemoveObjectAction());
1251            modificationActions.add(namespaceConfig.getRemoveRevisionContentAction());
1252            modificationActions.add(namespaceConfig.getRemoveRevisionMetadataAction());
1253            modificationActions.add(namespaceConfig.getUnbindMemberAction());
1254            
1255            modificationActions.remove(namespaceConfig.getDefaultAction());
1256            
1257            this.modificationActions = Collections.unmodifiableSet(modificationActions);
1258        }
1259        return this.modificationActions;
1260    }
1261    
1262    /**
1263     * Get whether an acion can modify objects in the repository.
1264     *
1265     * @param action The action for which to check whether it can modify
1266     * objects in the repository.
1267     * @return True if the actions can modify objects in the repository,
1268     * false otherwise.
1269     */

1270    private boolean isModificationAction(ActionNode action) {
1271        return getModificationActions().contains(action);
1272    }
1273    
1274    /**
1275     * Determine whether an operation on an object in the repository
1276     * invalidates the actions cache.
1277     *
1278     * @param object The subject of the operation.
1279     * @param action The operation.
1280     */

1281    private void determineActionsCacheInvalidation(ObjectNode object, ActionNode action) {
1282        if (object.getUri().startsWith(namespaceConfig.getActionsPath())) {
1283            if (isModificationAction(action)) {
1284                if (logger.isEnabled(Logger.DEBUG)) {
1285                    logger.log("Actions cache invalidated for operation " + action.getUri()
1286                            + " on action " + object.getUri(), LOG_CHANNEL, Logger.DEBUG);
1287                }
1288                invalidateActionsCache(this);
1289            }
1290        }
1291    }
1292
1293    /**
1294     * Invalidates the actions cache causing it to be reloaded the next time it
1295     * is needed.
1296     */

1297    private static synchronized void invalidateActionsCache(SecurityImpl security) {
1298        ActionsCache cache = getActionsCache(security);
1299        cache.invalidate();
1300    }
1301    
1302    private static synchronized ActionsCache getActionsCache(SecurityImpl security) {
1303        String namespaceName = security.namespace.getName();
1304        ActionsCache result = (ActionsCache)caches.get(namespaceName);
1305        if (result == null)
1306        {
1307            result = new ActionsCache();
1308            caches.put(namespaceName, result);
1309        }
1310        return result;
1311    }
1312    
1313    private static final Map caches = new HashMap();
1314
1315    /**
1316     * Populate the actions cache.
1317     *
1318     * @param namespace
1319     * @param namespaceConfig
1320     */

1321    private static synchronized void loadActionsCache(SecurityImpl security, SlideToken token) {
1322        ActionsCache cache = getActionsCache(security);
1323        try {
1324            cache.aggregation = new HashMap();
1325            cache.aggregationClosure = new HashMap();
1326            String actionsPath = security.namespaceConfig.getActionsPath();
1327            Uri actionsPathUri = security.namespace.getUri(token, actionsPath);
1328            ObjectNode actionsPathNode = actionsPathUri.getStore().retrieveObject(actionsPathUri);
1329            Enumeration actions = actionsPathNode.enumerateChildren();
1330            addActionLeafsToActionAggregation(security, token, cache, actions);
1331
1332            Iterator keys = cache.aggregationClosure.keySet().iterator();
1333            while (keys.hasNext()) {
1334                ActionNode aNode = (ActionNode)keys.next();
1335                Set aClosure = (Set)cache.aggregationClosure.get(aNode);
1336                cache.aggregationClosure.put(aNode, buildClosure(cache, aClosure));
1337            }
1338            // log success
1339
if (security.logger.isEnabled(LOG_CHANNEL, Logger.DEBUG)) {
1340                security.logger.log("Action aggregations loaded successfully", LOG_CHANNEL, Logger.DEBUG);
1341            }
1342            if (security.logger.isEnabled(LOG_CHANNEL, Logger.DEBUG)) {
1343                security.logger.log("\n@@@ Actions aggregations", LOG_CHANNEL, Logger.DEBUG);
1344                Iterator i = cache.aggregation.entrySet().iterator();
1345                while (i.hasNext()) {
1346                    security.logger.log(" "+i.next(), LOG_CHANNEL, Logger.DEBUG);
1347                }
1348                security.logger.log("\n@@@ Action aggregations (transitive closure)", LOG_CHANNEL, Logger.DEBUG);
1349                i = cache.aggregationClosure.entrySet().iterator();
1350                while (i.hasNext()) {
1351                    security.logger.log(" "+i.next(), LOG_CHANNEL, Logger.DEBUG);
1352                }
1353            }
1354        }
1355        catch (Throwable e) {
1356            security.logger.log(e, LOG_CHANNEL, Logger.ERROR);
1357            cache.fail();
1358        }
1359    }
1360    
1361    /**
1362     * Add children of <code>actions</code> which are leafs, collections
1363     * without children, to the action cache. Recursively invoke this method
1364     * for each child which is not a leaf.
1365     *
1366     * @param actions The collection containing child nodes.
1367     * @throws SlideException
1368     * @throws JDOMException
1369     */

1370    private static synchronized void addActionLeafsToActionAggregation(SecurityImpl security, SlideToken token, ActionsCache cache, Enumeration actions) throws SlideException, JDOMException {
1371        while (actions.hasMoreElements()) {
1372            Uri aNodeUri = security.namespace.getUri(token, (String)actions.nextElement());
1373            ObjectNode oNode = security.namespace.getStore(aNodeUri.getScope()).retrieveObject(aNodeUri);
1374            if (oNode.hasChildren()) {
1375                if (security.logger.isEnabled(Logger.DEBUG)) {
1376                    security.logger.log("Adding children of action " + oNode.getUri() + " to action aggregation", LOG_CHANNEL, Logger.DEBUG);
1377                }
1378                addActionLeafsToActionAggregation(security, token, cache, oNode.enumerateChildren());
1379            } else {
1380                if (security.logger.isEnabled(Logger.DEBUG)) {
1381                    security.logger.log("Adding action " + oNode.getUri() + " to action aggregation", LOG_CHANNEL, Logger.DEBUG);
1382                }
1383                NodeRevisionNumber latestRevisionNumber = security.namespace.getStore(aNodeUri.getScope()).retrieveRevisionDescriptors(aNodeUri).getLatestRevision();
1384                NodeProperty privilegeNamespace = security.namespace.getStore(aNodeUri.getScope()).retrieveRevisionDescriptor(aNodeUri, latestRevisionNumber).getProperty(PRIVILEGE_NAMESPACE, "DAV:");
1385                ActionNode aNode;
1386                org.jdom.Namespace actionNamespace;
1387                if (privilegeNamespace != null && privilegeNamespace.getValue() instanceof String) {
1388                    actionNamespace = org.jdom.Namespace.getNamespace((String) privilegeNamespace.getValue());
1389                } else {
1390                    actionNamespace = org.jdom.Namespace.getNamespace("DAV:");
1391                }
1392                aNode = ActionNode.getActionNode(oNode.getUri(), actionNamespace);
1393                Set directAggregates = getActionAggregates(security, token, aNode);
1394                cache.aggregation.put(aNode, directAggregates);
1395                Set aClosure = new HashSet();
1396                aClosure.add(aNode);
1397                aClosure.addAll(directAggregates);
1398                cache.aggregationClosure.put(aNode, aClosure);
1399            }
1400        }
1401    }
1402    
1403    /**
1404     * Determines the complete set of children and grandchildren of an action.
1405     * These are the children/grandchildren determined by the
1406     * <code>D:privilege-member-set</code> hierarchy.
1407     *
1408     * @param aClosure A collection containing the action and its known
1409     * children and grandchildren.
1410     * @return A collection containing the action, its known and additionally
1411     * found children and grandchildren.
1412     */

1413    private static synchronized Set buildClosure(ActionsCache cache, Set aClosure) {
1414        Set result = new HashSet(aClosure);
1415        int size = 0;
1416        while (result.size() > size) {
1417            size = result.size();
1418            Set newResult = new HashSet();
1419            Iterator i = result.iterator();
1420            while (i.hasNext()) {
1421                Object member = i.next();
1422                Set membersOfMember = (Set)cache.aggregationClosure.get(member);
1423                if (membersOfMember != null) {
1424                    newResult.addAll(membersOfMember);
1425                }
1426            }
1427            result = newResult;
1428        }
1429        return result;
1430    }
1431    
1432    /**
1433     * Get a map which maps an action to its direct aggregated actions.
1434     *
1435     * If the actions cache is not loaded, an attempt will be made to load the
1436     * actions cache.
1437     *
1438     * @return A map from actions to their aggregated actions, or and empty map
1439     * if loading of the actions cache failed.
1440     */

1441    private static synchronized Map getActionAggregationImpl(SecurityImpl security, SlideToken token) {
1442        ActionsCache cache = getActionsCache(security);
1443        if (!cache.hasBeenLoaded()) {
1444            loadActionsCache(security, token);
1445        }
1446        if (cache.hasLoadingFailed) {
1447            security.logger.log("actionAggregation retrieved but cache didn't load successfully" , LOG_CHANNEL, Logger.WARNING);
1448            return new HashMap();
1449        }
1450        return cache.aggregation;
1451    }
1452    
1453    /**
1454     * Get a map which maps an action to all its aggregated actions.
1455     *
1456     * If the actions cache is not loaded, an attempt will be made to load the
1457     * actions cache.
1458     *
1459     * @return A map from actions to their aggregated actions.
1460     * @throws ServiceAccessException Indicates the loading of the actions
1461     * cache failed.
1462     */

1463    private static synchronized Map getActionAggregationClosureImpl(SecurityImpl security, SlideToken token, String uri) throws ServiceAccessException {
1464        ActionsCache cache = getActionsCache(security);
1465        if (!cache.hasBeenLoaded()) {
1466            loadActionsCache(security, token);
1467        }
1468        if (cache.hasLoadingFailed()) {
1469            Uri u = security.namespace.getUri(token, uri);
1470            Store s = u.getStore();
1471            throw new ServiceAccessException(s, "Actions cache not loaded");
1472        }
1473        return cache.aggregationClosure;
1474    }
1475}
1476
Popular Tags