View Javadoc

1   package org.apache.turbine.services.security.torque;
2   
3   /*
4    * Copyright 2001-2005 The Apache Software Foundation.
5    *
6    * Licensed under the Apache License, Version 2.0 (the "License")
7    * you may not use this file except in compliance with the License.
8    * You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  
19  import java.util.ArrayList;
20  import java.util.Hashtable;
21  import java.util.Iterator;
22  import java.util.List;
23  
24  import org.apache.commons.configuration.Configuration;
25  
26  import org.apache.commons.lang.StringUtils;
27  
28  import org.apache.commons.logging.Log;
29  import org.apache.commons.logging.LogFactory;
30  
31  import org.apache.torque.om.NumberKey;
32  import org.apache.torque.om.Persistent;
33  import org.apache.torque.util.Criteria;
34  
35  import org.apache.turbine.om.security.Group;
36  import org.apache.turbine.om.security.Permission;
37  import org.apache.turbine.om.security.Role;
38  import org.apache.turbine.om.security.User;
39  import org.apache.turbine.services.InitializationException;
40  import org.apache.turbine.services.security.BaseSecurityService;
41  import org.apache.turbine.services.security.TurbineSecurity;
42  import org.apache.turbine.services.security.torque.om.TurbineRolePermissionPeer;
43  import org.apache.turbine.services.security.torque.om.TurbineUserGroupRolePeer;
44  import org.apache.turbine.util.security.AccessControlList;
45  import org.apache.turbine.util.security.DataBackendException;
46  import org.apache.turbine.util.security.EntityExistsException;
47  import org.apache.turbine.util.security.GroupSet;
48  import org.apache.turbine.util.security.PermissionSet;
49  import org.apache.turbine.util.security.RoleSet;
50  import org.apache.turbine.util.security.UnknownEntityException;
51  
52  /***
53   * An implementation of SecurityService that uses torque objects.
54   *
55   * @author <a href="mailto:Rafal.Krzewski@e-point.pl">Rafal Krzewski</a>
56   * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a>
57   * @author <a href="mailto:marco@intermeta.de">Marco Kn&uuml;ttel</a>
58   * @version $Id: TorqueSecurityService.java 264148 2005-08-29 14:21:04Z henning $
59   */
60  public class TorqueSecurityService
61      extends BaseSecurityService
62  {
63      /*** Logging */
64      private static Log log = LogFactory.getLog(TorqueSecurityService.class);
65  
66      /***
67       * Initializes the TorqueSecurityService, loading the various class objects
68       * representing the security entity peer classes
69       *
70       * @exception InitializationException A problem occured during initialization
71       */
72  
73      public void init()
74          throws InitializationException
75      {
76          Configuration conf = getConfiguration();
77  
78          GroupPeerManager.init(conf);
79          RolePeerManager.init(conf);
80          PermissionPeerManager.init(conf);
81  
82          /* At the end, because it calls setInit(true)! */
83          super.init();
84      }
85  
86  
87      /*-----------------------------------------------------------------------
88        Creation of AccessControlLists
89        -----------------------------------------------------------------------*/
90  
91      /***
92       * Constructs an AccessControlList for a specific user.
93       *
94       * This method creates a snapshot of the state of security information
95       * concerning this user, at the moment of invocation and stores it
96       * into an AccessControlList object.
97       *
98       * @param user the user for whom the AccessControlList are to be retrieved
99       * @return A new AccessControlList object.
100      * @throws DataBackendException if there was an error accessing the data
101      *         backend.
102      * @throws UnknownEntityException if user account is not present.
103      */
104     public AccessControlList getACL(User user)
105         throws DataBackendException, UnknownEntityException
106     {
107         if (!TurbineSecurity.accountExists(user))
108         {
109             throw new UnknownEntityException("The account '"
110                                              + user.getName() + "' does not exist");
111         }
112         try
113         {
114             Hashtable roles = new Hashtable();
115             Hashtable permissions = new Hashtable();
116             // notify the state modifiers (writers) that we want to create
117             // the snapshot.
118             lockShared();
119 
120             // construct the snapshot:
121 
122             // foreach group in the system
123             for (Iterator groupsIterator = getAllGroups().iterator();
124                  groupsIterator.hasNext();)
125             {
126                 Group group = (Group) groupsIterator.next();
127                 // get roles of user in the group
128                 RoleSet groupRoles = RolePeerManager.retrieveSet(user, group);
129                 // put the Set into roles(group)
130                 roles.put(group, groupRoles);
131                 // collect all permissions in this group
132                 PermissionSet groupPermissions = new PermissionSet();
133                 // foreach role in Set
134                 for (Iterator rolesIterator = groupRoles.iterator();
135                      rolesIterator.hasNext();)
136                 {
137                     Role role = (Role) rolesIterator.next();
138                     // get permissions of the role
139                     PermissionSet rolePermissions =
140                         PermissionPeerManager.retrieveSet(role);
141                     groupPermissions.add(rolePermissions);
142                 }
143                 // put the Set into permissions(group)
144                 permissions.put(group, groupPermissions);
145             }
146             return getAclInstance(roles, permissions);
147         }
148         catch (Exception e)
149         {
150             throw new DataBackendException("Failed to build ACL for user '" +
151                                            user.getName() + "'" , e);
152         }
153         finally
154         {
155             // notify the state modifiers that we are done creating the snapshot.
156             unlockShared();
157         }
158     }
159 
160     /*-----------------------------------------------------------------------
161       Security management
162       -----------------------------------------------------------------------*/
163 
164     /***
165      * Grant an User a Role in a Group.
166      *
167      * @param user the user.
168      * @param group the group.
169      * @param role the role.
170      * @throws DataBackendException if there was an error accessing the data
171      *         backend.
172      * @throws UnknownEntityException if user account, group or role is not
173      *         present.
174      */
175     public synchronized void grant(User user, Group group, Role role)
176         throws DataBackendException, UnknownEntityException
177     {
178         boolean userExists = false;
179         boolean groupExists = false;
180         boolean roleExists = false;
181         try
182         {
183             lockExclusive();
184             userExists = TurbineSecurity.accountExists(user);
185             groupExists = checkExists(group);
186             roleExists = checkExists(role);
187             if (userExists && groupExists && roleExists)
188             {
189                 Criteria criteria = new Criteria();
190                 criteria.add(TurbineUserGroupRolePeer.USER_ID,
191                              ((Persistent) user).getPrimaryKey());
192                 criteria.add(TurbineUserGroupRolePeer.GROUP_ID,
193                              ((Persistent) group).getPrimaryKey());
194                 criteria.add(TurbineUserGroupRolePeer.ROLE_ID,
195                              ((Persistent) role).getPrimaryKey());
196                 TurbineUserGroupRolePeer.doInsert(criteria);
197                 return;
198             }
199         }
200         catch (Exception e)
201         {
202             throw new DataBackendException("grant(User,Group,Role) failed", e);
203         }
204         finally
205         {
206             unlockExclusive();
207         }
208         if (!userExists)
209         {
210             throw new UnknownEntityException("Unknown user '"
211                                              + user.getName() + "'");
212         }
213         if (!groupExists)
214         {
215             throw new UnknownEntityException("Unknown group '"
216                                              + group.getName() + "'");
217         }
218         if (!roleExists)
219         {
220             throw new UnknownEntityException("Unknown role '"
221                                              + role.getName() + "'");
222         }
223     }
224 
225     /***
226      * Revoke a Role in a Group from an User.
227      *
228      * @param user the user.
229      * @param group the group.
230      * @param role the role.
231      * @throws DataBackendException if there was an error accessing the data
232      *         backend.
233      * @throws UnknownEntityException if user account, group or role is not
234      *         present.
235      */
236     public synchronized void revoke(User user, Group group, Role role)
237         throws DataBackendException, UnknownEntityException
238     {
239         boolean userExists = false;
240         boolean groupExists = false;
241         boolean roleExists = false;
242         try
243         {
244             lockExclusive();
245             userExists = TurbineSecurity.accountExists(user);
246             groupExists = checkExists(group);
247             roleExists = checkExists(role);
248             if (userExists && groupExists && roleExists)
249             {
250                 Criteria criteria = new Criteria();
251                 criteria.add(TurbineUserGroupRolePeer.USER_ID,
252                              ((Persistent) user).getPrimaryKey());
253                 criteria.add(TurbineUserGroupRolePeer.GROUP_ID,
254                              ((Persistent) group).getPrimaryKey());
255                 criteria.add(TurbineUserGroupRolePeer.ROLE_ID,
256                              ((Persistent) role).getPrimaryKey());
257                 TurbineUserGroupRolePeer.doDelete(criteria);
258                 return;
259             }
260         }
261         catch (Exception e)
262         {
263             throw new DataBackendException("revoke(User,Role,Group) failed", e);
264         }
265         finally
266         {
267             unlockExclusive();
268         }
269         if (!userExists)
270         {
271             throw new UnknownEntityException("Unknown user '"
272                                              + user.getName() + "'");
273         }
274         if (!groupExists)
275         {
276             throw new UnknownEntityException("Unknown group '"
277                                              + group.getName() + "'");
278         }
279         if (!roleExists)
280         {
281             throw new UnknownEntityException("Unknown role '"
282                                              + role.getName() + "'");
283         }
284     }
285 
286     /***
287      * Revokes all roles from an User.
288      *
289      * This method is used when deleting an account.
290      *
291      * @param user the User.
292      * @throws DataBackendException if there was an error accessing the data
293      *         backend.
294      * @throws UnknownEntityException if the account is not present.
295      */
296     public synchronized void revokeAll(User user)
297         throws DataBackendException, UnknownEntityException
298     {
299         boolean userExists = false;
300         try
301         {
302             lockExclusive();
303             userExists = TurbineSecurity.accountExists(user);
304             if (userExists)
305             {
306                 // The following would not work, due to an annoying misfeature
307                 // of Village. Village allows only a single row to be deleted at
308                 // a time. I wish that it was possible to disable this
309                 // behaviour!
310 
311                 // Criteria criteria = new Criteria();
312                 // criteria.add(UserGroupRolePeer.USER_ID,
313                 //           ((Persistent) user).getPrimaryKey());
314                 // UserGroupRolePeer.doDelete(criteria);
315                 int id = ((NumberKey) ((Persistent) user)
316                           .getPrimaryKey()).intValue();
317                 TurbineUserGroupRolePeer.deleteAll(
318                     TurbineUserGroupRolePeer.TABLE_NAME,
319                     TurbineUserGroupRolePeer.USER_ID, id);
320                 return;
321             }
322         }
323         catch (Exception e)
324         {
325             throw new DataBackendException("revokeAll(User) failed", e);
326         }
327         finally
328         {
329             unlockExclusive();
330         }
331         throw new UnknownEntityException("Unknown user '"
332                                          + user.getName() + "'");
333     }
334 
335     /***
336      * Grants a Role a Permission
337      *
338      * @param role the Role.
339      * @param permission the Permission.
340      * @throws DataBackendException if there was an error accessing the data
341      *         backend.
342      * @throws UnknownEntityException if role or permission is not present.
343      */
344     public synchronized void grant(Role role, Permission permission)
345         throws DataBackendException, UnknownEntityException
346     {
347         boolean roleExists = false;
348         boolean permissionExists = false;
349         try
350         {
351             lockExclusive();
352             roleExists = checkExists(role);
353             permissionExists = checkExists(permission);
354             if (roleExists && permissionExists)
355             {
356                 Criteria criteria = new Criteria();
357                 criteria.add(TurbineRolePermissionPeer.ROLE_ID,
358                              ((Persistent) role).getPrimaryKey());
359                 criteria.add(TurbineRolePermissionPeer.PERMISSION_ID,
360                              ((Persistent) permission).getPrimaryKey());
361                 TurbineRolePermissionPeer.doInsert(criteria);
362                 return;
363             }
364         }
365         catch (Exception e)
366         {
367             throw new DataBackendException("grant(Role,Permission) failed", e);
368         }
369         finally
370         {
371             unlockExclusive();
372         }
373         if (!roleExists)
374         {
375             throw new UnknownEntityException("Unknown role '"
376                                              + role.getName() + "'");
377         }
378         if (!permissionExists)
379         {
380             throw new UnknownEntityException("Unknown permission '"
381                                              + permission.getName() + "'");
382         }
383     }
384 
385     /***
386      * Revokes a Permission from a Role.
387      *
388      * @param role the Role.
389      * @param permission the Permission.
390      * @throws DataBackendException if there was an error accessing the data
391      *         backend.
392      * @throws UnknownEntityException if role or permission is not present.
393      */
394     public synchronized void revoke(Role role, Permission permission)
395         throws DataBackendException, UnknownEntityException
396     {
397         boolean roleExists = false;
398         boolean permissionExists = false;
399         try
400         {
401             lockExclusive();
402             roleExists = checkExists(role);
403             permissionExists = checkExists(permission);
404             if (roleExists && permissionExists)
405             {
406                 Criteria criteria = new Criteria();
407                 criteria.add(TurbineRolePermissionPeer.ROLE_ID,
408                              ((Persistent) role).getPrimaryKey());
409                 criteria.add(TurbineRolePermissionPeer.PERMISSION_ID,
410                              ((Persistent) permission).getPrimaryKey());
411                 TurbineRolePermissionPeer.doDelete(criteria);
412                 return;
413             }
414         }
415         catch (Exception e)
416         {
417             throw new DataBackendException("revoke(Role,Permission) failed", e);
418         }
419         finally
420         {
421             unlockExclusive();
422         }
423         if (!roleExists)
424         {
425             throw new UnknownEntityException("Unknown role '"
426                                              + role.getName() + "'");
427         }
428         if (!permissionExists)
429         {
430             throw new UnknownEntityException("Unknown permission '"
431                                              + permission.getName() + "'");
432         }
433     }
434 
435     /***
436      * Revokes all permissions from a Role.
437      *
438      * This method is user when deleting a Role.
439      *
440      * @param role the Role
441      * @throws DataBackendException if there was an error accessing the data
442      *         backend.
443      * @throws UnknownEntityException if the Role is not present.
444      */
445     public synchronized void revokeAll(Role role)
446         throws DataBackendException, UnknownEntityException
447     {
448         boolean roleExists = false;
449         try
450         {
451             lockExclusive();
452             roleExists = checkExists(role);
453             if (roleExists)
454             {
455                 // The following would not work, due to an annoying misfeature
456                 // of Village. see revokeAll( user )
457 
458                 // Criteria criteria = new Criteria();
459                 // criteria.add(RolePermissionPeer.ROLE_ID,
460                 //         role.getPrimaryKey());
461                 // RolePermissionPeer.doDelete(criteria);
462 
463                 int id = ((NumberKey) ((Persistent) role)
464                           .getPrimaryKey()).intValue();
465                 TurbineRolePermissionPeer.deleteAll(
466                     TurbineRolePermissionPeer.TABLE_NAME,
467                     TurbineRolePermissionPeer.ROLE_ID, id);
468                 return;
469             }
470         }
471         catch (Exception e)
472         {
473             throw new DataBackendException("revokeAll(Role) failed", e);
474         }
475         finally
476         {
477             unlockExclusive();
478         }
479         throw new UnknownEntityException("Unknown role '"
480                                          + role.getName() + "'");
481     }
482 
483     /*-----------------------------------------------------------------------
484       Group/Role/Permission management
485       -----------------------------------------------------------------------*/
486 
487     /***
488      * Retrieve a set of Groups that meet the specified Criteria.
489      *
490      * @param criteria A Criteria of Group selection.
491      * @return a set of Groups that meet the specified Criteria.
492      * @throws DataBackendException if there was an error accessing the data
493      *         backend.
494      */
495     public GroupSet getGroups(Criteria criteria)
496         throws DataBackendException
497     {
498         Criteria torqueCriteria = new Criteria();
499         Iterator keys = criteria.keySet().iterator();
500         while (keys.hasNext())
501         {
502             String key = (String) keys.next();
503             torqueCriteria.put(GroupPeerManager.getColumnName(key),
504                     criteria.get(key));
505         }
506         List groups = new ArrayList(0);
507         try
508         {
509             groups = GroupPeerManager.doSelect(criteria);
510         }
511         catch (Exception e)
512         {
513             throw new DataBackendException("getGroups(Criteria) failed", e);
514         }
515         return new GroupSet(groups);
516     }
517 
518     /***
519      * Retrieve a set of Roles that meet the specified Criteria.
520      *
521      * @param criteria A Criteria of Roles selection.
522      * @return a set of Roles that meet the specified Criteria.
523      * @throws DataBackendException if there was an error accessing the data
524      *         backend.
525      */
526     public RoleSet getRoles(Criteria criteria)
527         throws DataBackendException
528     {
529         Criteria torqueCriteria = new Criteria();
530         Iterator keys = criteria.keySet().iterator();
531         while (keys.hasNext())
532         {
533             String key = (String) keys.next();
534             torqueCriteria.put(RolePeerManager.getColumnName(key),
535                     criteria.get(key));
536         }
537         List roles = new ArrayList(0);
538         try
539         {
540             roles = RolePeerManager.doSelect(criteria);
541         }
542         catch (Exception e)
543         {
544             throw new DataBackendException("getRoles(Criteria) failed", e);
545         }
546         return new RoleSet(roles);
547     }
548 
549     /***
550      * Retrieve a set of Permissions that meet the specified Criteria.
551      *
552      * @param criteria A Criteria of Permissions selection.
553      * @return a set of Permissions that meet the specified Criteria.
554      * @throws DataBackendException if there was an error accessing the data
555      *         backend.
556      */
557     public PermissionSet getPermissions(Criteria criteria)
558         throws DataBackendException
559     {
560         Criteria torqueCriteria = new Criteria();
561         Iterator keys = criteria.keySet().iterator();
562         while (keys.hasNext())
563         {
564             String key = (String) keys.next();
565             torqueCriteria.put(PermissionPeerManager.getColumnName(key),
566                     criteria.get(key));
567         }
568         List permissions = new ArrayList(0);
569         try
570         {
571             permissions = PermissionPeerManager.doSelect(criteria);
572         }
573         catch (Exception e)
574         {
575             throw new DataBackendException(
576                 "getPermissions(Criteria) failed", e);
577         }
578         return new PermissionSet(permissions);
579     }
580 
581     /***
582      * Retrieves all permissions associated with a role.
583      *
584      * @param role the role name, for which the permissions are to be retrieved.
585      * @return A Permission set for the Role.
586      * @throws DataBackendException if there was an error accessing the data
587      *         backend.
588      * @throws UnknownEntityException if the role is not present.
589      */
590     public PermissionSet getPermissions(Role role)
591         throws DataBackendException, UnknownEntityException
592     {
593         boolean roleExists = false;
594         try
595         {
596             lockShared();
597             roleExists = checkExists(role);
598             if (roleExists)
599             {
600                 return PermissionPeerManager.retrieveSet(role);
601             }
602         }
603         catch (Exception e)
604         {
605             throw new DataBackendException("getPermissions(Role) failed", e);
606         }
607         finally
608         {
609             unlockShared();
610         }
611         throw new UnknownEntityException("Unknown role '"
612                                          + role.getName() + "'");
613     }
614 
615     /***
616      * Stores Group's attributes. The Groups is required to exist in the system.
617      *
618      * @param group The Group to be stored.
619      * @throws DataBackendException if there was an error accessing the data
620      *         backend.
621      * @throws UnknownEntityException if the group does not exist.
622      */
623     public void saveGroup(Group group)
624         throws DataBackendException, UnknownEntityException
625     {
626         boolean groupExists = false;
627         try
628         {
629             groupExists = checkExists(group);
630             if (groupExists)
631             {
632                 Criteria criteria = GroupPeerManager.buildCriteria(group);
633                 GroupPeerManager.doUpdate(criteria);
634                 return;
635             }
636         }
637         catch (Exception e)
638         {
639             throw new DataBackendException("saveGroup(Group) failed", e);
640         }
641         throw new UnknownEntityException("Unknown group '" + group + "'");
642     }
643 
644     /***
645      * Stores Role's attributes. The Roles is required to exist in the system.
646      *
647      * @param role The Role to be stored.
648      * @throws DataBackendException if there was an error accessing the data
649      *         backend.
650      * @throws UnknownEntityException if the role does not exist.
651      */
652     public void saveRole(Role role)
653         throws DataBackendException, UnknownEntityException
654     {
655         boolean roleExists = false;
656         try
657         {
658             roleExists = checkExists(role);
659             if (roleExists)
660             {
661                 Criteria criteria = RolePeerManager.buildCriteria(role);
662                 RolePeerManager.doUpdate(criteria);
663                 return;
664             }
665         }
666         catch (Exception e)
667         {
668             throw new DataBackendException("saveRole(Role) failed", e);
669         }
670         throw new UnknownEntityException("Unknown role '" + role + "'");
671     }
672 
673     /***
674      * Stores Permission's attributes. The Permissions is required to exist in
675      * the system.
676      *
677      * @param permission The Permission to be stored.
678      * @throws DataBackendException if there was an error accessing the data
679      *         backend.
680      * @throws UnknownEntityException if the permission does not exist.
681      */
682     public void savePermission(Permission permission)
683         throws DataBackendException, UnknownEntityException
684     {
685         boolean permissionExists = false;
686         try
687         {
688             permissionExists = checkExists(permission);
689             if (permissionExists)
690             {
691                 Criteria criteria = PermissionPeerManager.buildCriteria(permission);
692                 PermissionPeerManager.doUpdate(criteria);
693                 return;
694             }
695         }
696         catch (Exception e)
697         {
698             throw new DataBackendException(
699                 "savePermission(Permission) failed", e);
700         }
701         throw new UnknownEntityException("Unknown permission '"
702                                          + permission + "'");
703     }
704 
705     /***
706      * Creates a new group with specified attributes.
707      *
708      * @param group the object describing the group to be created.
709      * @return a new Group object that has id set up properly.
710      * @throws DataBackendException if there was an error accessing the data
711      *         backend.
712      * @throws EntityExistsException if the group already exists.
713      */
714     public synchronized Group addGroup(Group group)
715         throws DataBackendException,
716                EntityExistsException
717     {
718         boolean groupExists = false;
719 
720         if (StringUtils.isEmpty(group.getName()))
721         {
722             throw new DataBackendException("Could not create "
723                                            + "a group with empty name!");
724         }
725 
726         try
727         {
728             lockExclusive();
729             groupExists = checkExists(group);
730             if (!groupExists)
731             {
732                 // add a row to the table
733                 Criteria criteria = GroupPeerManager.buildCriteria(group);
734                 GroupPeerManager.doInsert(criteria);
735                 // try to get the object back using the name as key.
736                 criteria = new Criteria();
737                 criteria.add(GroupPeerManager.getNameColumn(),
738                              group.getName());
739                 List results = GroupPeerManager.doSelect(criteria);
740                 if (results.size() != 1)
741                 {
742                     throw new DataBackendException(
743                         "Internal error - query returned "
744                         + results.size() + " rows");
745                 }
746                 Group newGroup = (Group) results.get(0);
747                 // add the group to system-wide cache
748                 getAllGroups().add(newGroup);
749                 // return the object with correct id
750                 return newGroup;
751             }
752         }
753         catch (Exception e)
754         {
755             throw new DataBackendException("addGroup(Group) failed", e);
756         }
757         finally
758         {
759             unlockExclusive();
760         }
761         // the only way we could get here without return/throw tirggered
762         // is that the groupExists was true.
763         throw new EntityExistsException("Group '" + group + "' already exists");
764     }
765 
766     /***
767      * Creates a new role with specified attributes.
768      *
769      * @param role the object describing the role to be created.
770      * @return a new Role object that has id set up properly.
771      * @throws DataBackendException if there was an error accessing the data
772      *         backend.
773      * @throws EntityExistsException if the role already exists.
774      */
775     public synchronized Role addRole(Role role)
776         throws DataBackendException, EntityExistsException
777     {
778         boolean roleExists = false;
779 
780         if (StringUtils.isEmpty(role.getName()))
781         {
782             throw new DataBackendException("Could not create "
783                                            + "a role with empty name!");
784         }
785 
786         try
787         {
788             lockExclusive();
789             roleExists = checkExists(role);
790             if (!roleExists)
791             {
792                 // add a row to the table
793                 Criteria criteria = RolePeerManager.buildCriteria(role);
794                 RolePeerManager.doInsert(criteria);
795                 // try to get the object back using the name as key.
796                 criteria = new Criteria();
797                 criteria.add(RolePeerManager.getNameColumn(), role.getName());
798                 List results = RolePeerManager.doSelect(criteria);
799                 if (results.size() != 1)
800                 {
801                     throw new DataBackendException(
802                         "Internal error - query returned "
803                         + results.size() + " rows");
804                 }
805                 Role newRole = (Role) results.get(0);
806                 // add the role to system-wide cache
807                 getAllRoles().add(newRole);
808                 // return the object with correct id
809                 return newRole;
810             }
811         }
812         catch (Exception e)
813         {
814             throw new DataBackendException("addRole(Role) failed", e);
815         }
816         finally
817         {
818             unlockExclusive();
819         }
820         // the only way we could get here without return/throw tirggered
821         // is that the roleExists was true.
822         throw new EntityExistsException("Role '" + role + "' already exists");
823     }
824 
825     /***
826      * Creates a new permission with specified attributes.
827      *
828      * @param permission the object describing the permission to be created.
829      * @return a new Permission object that has id set up properly.
830      * @throws DataBackendException if there was an error accessing the data
831      *         backend.
832      * @throws EntityExistsException if the permission already exists.
833      */
834     public synchronized Permission addPermission(Permission permission)
835         throws DataBackendException, EntityExistsException
836     {
837         boolean permissionExists = false;
838 
839         if (StringUtils.isEmpty(permission.getName()))
840         {
841             throw new DataBackendException("Could not create "
842                                            + "a permission with empty name!");
843         }
844 
845         try
846         {
847             lockExclusive();
848             permissionExists = checkExists(permission);
849             if (!permissionExists)
850             {
851                 // add a row to the table
852                 Criteria criteria = PermissionPeerManager.buildCriteria(permission);
853                 PermissionPeerManager.doInsert(criteria);
854                 // try to get the object back using the name as key.
855                 criteria = new Criteria();
856                 criteria.add(PermissionPeerManager.getNameColumn(),
857                              permission.getName());
858                 List results = PermissionPeerManager.doSelect(criteria);
859                 if (results.size() != 1)
860                 {
861                     throw new DataBackendException(
862                         "Internal error - query returned "
863                         + results.size() + " rows");
864                 }
865                 Permission newPermission = (Permission) results.get(0);
866                 // add the permission to system-wide cache
867                 getAllPermissions().add(newPermission);
868                 // return the object with correct id
869                 return newPermission;
870             }
871         }
872         catch (Exception e)
873         {
874             throw new DataBackendException(
875                 "addPermission(Permission) failed", e);
876         }
877         finally
878         {
879             unlockExclusive();
880         }
881         // the only way we could get here without return/throw tirggered
882         // is that the permissionExists was true.
883         throw new EntityExistsException("Permission '" + permission
884                                         + "' already exists");
885     }
886 
887     /***
888      * Removes a Group from the system.
889      *
890      * @param group The object describing the group to be removed.
891      * @throws DataBackendException if there was an error accessing the data
892      *         backend.
893      * @throws UnknownEntityException if the group does not exist.
894      */
895     public synchronized void removeGroup(Group group)
896         throws DataBackendException, UnknownEntityException
897     {
898         boolean groupExists = false;
899         try
900         {
901             lockExclusive();
902             groupExists = checkExists(group);
903             if (groupExists)
904             {
905                 Criteria criteria = GroupPeerManager.buildCriteria(group);
906                 GroupPeerManager.doDelete(criteria);
907                 getAllGroups().remove(group);
908                 return;
909             }
910         }
911         catch (Exception e)
912         {
913             log.error("Failed to delete a Group");
914             log.error(e);
915             throw new DataBackendException("removeGroup(Group) failed", e);
916         }
917         finally
918         {
919             unlockExclusive();
920         }
921         throw new UnknownEntityException("Unknown group '" + group + "'");
922     }
923 
924     /***
925      * Removes a Role from the system.
926      *
927      * @param role The object describing the role to be removed.
928      * @throws DataBackendException if there was an error accessing the data
929      *         backend.
930      * @throws UnknownEntityException if the role does not exist.
931      */
932     public synchronized void removeRole(Role role)
933         throws DataBackendException, UnknownEntityException
934     {
935         boolean roleExists = false;
936         try
937         {
938             lockExclusive();
939             roleExists = checkExists(role);
940             if (roleExists)
941             {
942                 // revoke all permissions from the role to be deleted
943                 revokeAll(role);
944                 Criteria criteria = RolePeerManager.buildCriteria(role);
945                 RolePeerManager.doDelete(criteria);
946                 getAllRoles().remove(role);
947                 return;
948             }
949         }
950         catch (Exception e)
951         {
952             throw new DataBackendException("removeRole(Role)", e);
953         }
954         finally
955         {
956             unlockExclusive();
957         }
958         throw new UnknownEntityException("Unknown role '" + role + "'");
959     }
960 
961     /***
962      * Removes a Permission from the system.
963      *
964      * @param permission The object describing the permission to be removed.
965      * @throws DataBackendException if there was an error accessing the data
966      *         backend.
967      * @throws UnknownEntityException if the permission does not exist.
968      */
969     public synchronized void removePermission(Permission permission)
970         throws DataBackendException, UnknownEntityException
971     {
972         boolean permissionExists = false;
973         try
974         {
975             lockExclusive();
976             permissionExists = checkExists(permission);
977             if (permissionExists)
978             {
979                 Criteria criteria = PermissionPeerManager.buildCriteria(permission);
980                 PermissionPeerManager.doDelete(criteria);
981                 getAllPermissions().remove(permission);
982                 return;
983             }
984         }
985         catch (Exception e)
986         {
987             throw new DataBackendException("removePermission(Permission)", e);
988         }
989         finally
990         {
991             unlockExclusive();
992         }
993         throw new UnknownEntityException("Unknown permission '"
994                                          + permission + "'");
995     }
996 
997     /***
998      * Renames an existing Group.
999      *
1000      * @param group The object describing the group to be renamed.
1001      * @param name the new name for the group.
1002      * @throws DataBackendException if there was an error accessing the data
1003      *         backend.
1004      * @throws UnknownEntityException if the group does not exist.
1005      */
1006     public synchronized void renameGroup(Group group, String name)
1007         throws DataBackendException, UnknownEntityException
1008     {
1009         boolean groupExists = false;
1010         try
1011         {
1012             lockExclusive();
1013             groupExists = checkExists(group);
1014             if (groupExists)
1015             {
1016                 group.setName(name);
1017                 Criteria criteria = GroupPeerManager.buildCriteria(group);
1018                 GroupPeerManager.doUpdate(criteria);
1019                 return;
1020             }
1021         }
1022         catch (Exception e)
1023         {
1024             throw new DataBackendException("renameGroup(Group,String)", e);
1025         }
1026         finally
1027         {
1028             unlockExclusive();
1029         }
1030         throw new UnknownEntityException("Unknown group '" + group + "'");
1031     }
1032 
1033     /***
1034      * Renames an existing Role.
1035      *
1036      * @param role The object describing the role to be renamed.
1037      * @param name the new name for the role.
1038      * @throws DataBackendException if there was an error accessing the data
1039      *         backend.
1040      * @throws UnknownEntityException if the role does not exist.
1041      */
1042     public synchronized void renameRole(Role role, String name)
1043         throws DataBackendException, UnknownEntityException
1044     {
1045         boolean roleExists = false;
1046         try
1047         {
1048             lockExclusive();
1049             roleExists = checkExists(role);
1050             if (roleExists)
1051             {
1052                 role.setName(name);
1053                 Criteria criteria = RolePeerManager.buildCriteria(role);
1054                 RolePeerManager.doUpdate(criteria);
1055                 return;
1056             }
1057         }
1058         catch (Exception e)
1059         {
1060             throw new DataBackendException("renameRole(Role,String)", e);
1061         }
1062         finally
1063         {
1064             unlockExclusive();
1065         }
1066         throw new UnknownEntityException("Unknown role '" + role + "'");
1067     }
1068 
1069     /***
1070      * Renames an existing Permission.
1071      *
1072      * @param permission The object describing the permission to be renamed.
1073      * @param name the new name for the permission.
1074      * @throws DataBackendException if there was an error accessing the data
1075      *         backend.
1076      * @throws UnknownEntityException if the permission does not exist.
1077      */
1078     public synchronized void renamePermission(Permission permission,
1079                                               String name)
1080         throws DataBackendException, UnknownEntityException
1081     {
1082         boolean permissionExists = false;
1083         try
1084         {
1085             lockExclusive();
1086             permissionExists = checkExists(permission);
1087             if (permissionExists)
1088             {
1089                 permission.setName(name);
1090                 Criteria criteria = PermissionPeerManager.buildCriteria(permission);
1091                 PermissionPeerManager.doUpdate(criteria);
1092                 return;
1093             }
1094         }
1095         catch (Exception e)
1096         {
1097             throw new DataBackendException(
1098                 "renamePermission(Permission,name)", e);
1099         }
1100         finally
1101         {
1102             unlockExclusive();
1103         }
1104         throw new UnknownEntityException("Unknown permission '"
1105                                          + permission + "'");
1106     }
1107 
1108     /* Service specific implementation methods */
1109 
1110     /***
1111      * Determines if the <code>Group</code> exists in the security system.
1112      *
1113      * @param group a <code>Group</code> value
1114      * @return true if the group exists in the system, false otherwise
1115      * @throws DataBackendException when more than one Group with
1116      *         the same name exists.
1117      * @throws Exception A generic exception.
1118      */
1119     protected boolean checkExists(Group group)
1120         throws DataBackendException, Exception
1121     {
1122         return GroupPeerManager.checkExists(group);
1123     }
1124 
1125     /***
1126      * Determines if the <code>Role</code> exists in the security system.
1127      *
1128      * @param role a <code>Role</code> value
1129      * @return true if the role exists in the system, false otherwise
1130      * @throws DataBackendException when more than one Role with
1131      *         the same name exists.
1132      * @throws Exception A generic exception.
1133      */
1134     protected boolean checkExists(Role role)
1135         throws DataBackendException, Exception
1136     {
1137         return RolePeerManager.checkExists(role);
1138     }
1139 
1140     /***
1141      * Determines if the <code>Permission</code> exists in the security system.
1142      *
1143      * @param permission a <code>Permission</code> value
1144      * @return true if the permission exists in the system, false otherwise
1145      * @throws DataBackendException when more than one Permission with
1146      *         the same name exists.
1147      * @throws Exception A generic exception.
1148      */
1149     protected boolean checkExists(Permission permission)
1150         throws DataBackendException, Exception
1151     {
1152         return PermissionPeerManager.checkExists(permission);
1153     }
1154 
1155 }