View Javadoc

1   /*
2    * <cvs:source>$Source: /devel/astrogrid/community/server/src/java/org/astrogrid/community/server/policy/manager/GroupManagerImpl.java,v $</cvs:source>
3    * <cvs:author>$Author: jdt $</cvs:author>
4    * <cvs:date>$Date: 2004/11/22 13:03:04 $</cvs:date>
5    * <cvs:version>$Revision: 1.12 $</cvs:version>
6    *
7    * <cvs:log>
8    *   $Log: GroupManagerImpl.java,v $
9    *   Revision 1.12  2004/11/22 13:03:04  jdt
10   *   Merges from Comm_KMB_585
11   *
12   *   Revision 1.11  2004/10/29 15:50:05  jdt
13   *   merges from Community_AdminInterface (bug 579)
14   *
15   *   Revision 1.10.18.2  2004/10/18 22:10:28  KevinBenson
16   *   some bug fixes to the PermissionManager.  Also made it throw some exceptions.
17   *   Made  it and GroupManagerImnpl use the Resolver objects to actually get a group(PermissionManageriMnpl)
18   *   or account (GroupMember) from the other community.  Changed also for it to grab a ResourceData from the
19   *   database to verifity it is in our database.  Add a few of these resolver dependencies as well.
20   *   And last but not least fixed the GroupMemberData object to get rid of a few set methods so Castor
21   *   will now work correctly in Windows
22   *
23   *   Revision 1.10.18.1  2004/10/15 10:13:51  KevinBenson
24   *   adding the admin interface into a jsp fashion.  Correcting a few mistakes on the other
25   *   java files.
26   *
27   *   Revision 1.10  2004/09/16 23:18:08  dave
28   *   Replaced debug logging in Community.
29   *   Added stream close() to FileStore.
30   *
31   *   Revision 1.9.82.1  2004/09/16 09:58:48  dave
32   *   Replaced debug with commons logging ....
33   *
34   *   Revision 1.9  2004/06/18 13:45:20  dave
35   *   Merged development branch, dave-dev-200406081614, into HEAD
36   *
37   *   Revision 1.8.32.2  2004/06/17 15:24:31  dave
38   *   Removed unused imports (PMD report).
39   *
40   *   Revision 1.8.32.1  2004/06/17 13:38:59  dave
41   *   Tidied up old CVS log entries
42   *
43   * </cvs:log>
44   *
45   */
46  package org.astrogrid.community.server.policy.manager ;
47  
48  import org.apache.commons.logging.Log ;
49  import org.apache.commons.logging.LogFactory ;
50  
51  import java.util.Vector ;
52  import java.util.Collection ;
53  
54  import org.exolab.castor.jdo.Database;
55  import org.exolab.castor.jdo.OQLQuery;
56  import org.exolab.castor.jdo.QueryResults;
57  import org.exolab.castor.jdo.ObjectNotFoundException ;
58  import org.exolab.castor.jdo.DuplicateIdentityException ;
59  
60  import org.exolab.castor.persist.spi.Complex ;
61  
62  import org.astrogrid.community.common.policy.data.GroupData ;
63  import org.astrogrid.community.common.policy.data.GroupMemberData ;
64  import org.astrogrid.community.common.policy.data.AccountData ;
65  import org.astrogrid.community.common.policy.data.GroupMemberData ;
66  
67  import org.astrogrid.community.common.ivorn.CommunityIvornParser ;
68  
69  import org.astrogrid.community.common.policy.manager.GroupManager ;
70  import org.astrogrid.community.common.policy.manager.GroupMemberManager ;
71  import org.astrogrid.community.common.policy.manager.AccountManager ;
72  
73  import org.astrogrid.community.resolver.CommunityAccountResolver;
74  import org.astrogrid.community.server.service.CommunityServiceImpl ;
75  import org.astrogrid.community.server.database.configuration.DatabaseConfiguration ;
76  
77  import org.astrogrid.community.common.exception.CommunityPolicyException     ;
78  import org.astrogrid.community.common.exception.CommunityServiceException    ;
79  import org.astrogrid.community.common.exception.CommunityIdentifierException ;
80  import org.astrogrid.community.resolver.exception.CommunityResolverException ;
81  
82  import org.astrogrid.registry.RegistryException;
83  
84  /***
85   * Server side implementation of the GroupManager service.
86   *
87   */
88  public class GroupManagerImpl
89      extends CommunityServiceImpl
90      implements GroupManager, GroupMemberManager
91      {
92      /***
93       * Our debug logger.
94       *
95       */
96      private static Log log = LogFactory.getLog(GroupManagerImpl.class);
97  
98      /***
99       * Public constructor, using default database configuration.
100      *
101      */
102     public GroupManagerImpl()
103         {
104         super() ;
105         }
106 
107     /***
108      * Public constructor, using specific database configuration.
109      * @param config A specific DatabaseConfiguration.
110      *
111      */
112     public GroupManagerImpl(DatabaseConfiguration config)
113         {
114         super(config) ;
115         }
116 
117     /***
118      * Public constructor, using a parent service.
119      * @param parent A parent CommunityServiceImpl.
120      *
121      */
122     public GroupManagerImpl(CommunityServiceImpl parent)
123         {
124         super(parent) ;
125         }
126 
127     /***
128      * Reference to our local AccountManager.
129      * The GroupManager needs access to the current AccountManagerImpl because Castor maintains an
130      * in-memory cache of AccountData objects, with read-write locks.
131      *
132      */
133     private AccountManagerImpl accountManager ;
134 
135     /***
136      * Public constructor, using a parent service and an AccountManager instance.
137      * @param parent A parent CommunityServiceImpl.
138      * @param accountManager An AccountManager instance.
139      * The GroupManager needs access to the current AccountManagerImpl because Castor maintains an
140      * in-memory cache of AccountData objects, with read-write locks.
141      *
142      */
143     public GroupManagerImpl(CommunityServiceImpl parent, AccountManagerImpl accountManager)
144         {
145         super(parent) ;
146         this.accountManager = accountManager ;
147         }
148 
149     /***
150      * Add a new Group, given the Group ident.
151      * @param  ident The Group identifier.
152      * @return A GroupData for the Group.
153      * @throws CommunityIdentifierException If the identifier is not valid.
154      * @throws CommunityPolicyException If the identifier is already in the database.
155      * @throws CommunityServiceException If there is an internal error in the service.
156      *
157      */
158     public GroupData addGroup(String ident)
159         throws CommunityServiceException, CommunityIdentifierException, CommunityPolicyException
160         {
161         return this.addGroup(
162             new GroupData(
163                 ident
164                 )
165             ) ;
166         }
167 
168     /***
169      * Add a new Group, given the Group ident.
170      * @param  ident The Group identifier.
171      * @return An GroupData for the Group.
172      * @throws CommunityIdentifierException If the identifier is not valid.
173      * @throws CommunityPolicyException If the identifier is already in the database.
174      * @throws CommunityServiceException If there is an internal error in the service.
175      *
176     protected GroupData addGroup(CommunityIdent ident)
177         throws CommunityServiceException, CommunityIdentifierException, CommunityPolicyException
178         {
179         log.debug("") ;
180         log.debug("----\"----") ;
181         log.debug("GroupManagerImpl.addGroup()") ;
182         log.debug("  Ident : " + ident) ;
183         //
184         // Check for null ident.
185         if (null == ident)
186             {
187             throw new CommunityIdentifierException(
188                 "Null identifier"
189                 ) ;
190             }
191         //
192         // Create our new Group object.
193         return this.addGroup(
194             new GroupData(
195                 ident.toString()
196                 )
197             ) ;
198         }
199      */
200 
201     /***
202      * Add a new Group, given the Group data.
203      * @param  group The GroupData to add.
204      * @return A new GroupData for the Group.
205      * @throws CommunityIdentifierException If the identifier is not valid.
206      * @throws CommunityPolicyException If the identifier is not local.
207      * @throws CommunityPolicyException If the identifier is already in the database.
208      * @throws CommunityServiceException If there is an internal error in the service.
209      * @todo Verify that the finally gets executed, even if a new Exception is thrown.
210      * @todo Prevent private groups.
211      *
212      */
213     public GroupData addGroup(GroupData group)
214         throws CommunityServiceException, CommunityIdentifierException, CommunityPolicyException
215         {
216         log.debug("") ;
217         log.debug("----\"----") ;
218         log.debug("GroupManagerImpl.addGroup()") ;
219         log.debug("  Group : " + ((null != group) ? group.getIdent() : null)) ;
220         //
221         // Check for null group.
222         if (null == group)
223             {
224             throw new CommunityIdentifierException(
225                 "Null group"
226                 ) ;
227             }
228         //
229         // Get the Group ident.
230         CommunityIvornParser ident = new CommunityIvornParser(
231             group.getIdent()
232             ) ;
233         //
234         // Set the Group ident.
235         group.setIdent(
236             ident.getAccountIdent()
237             ) ;
238         //
239         // If the ident is local.
240         if (ident.isLocal())
241             {
242             //
243             // Try performing our transaction.
244             Database database = null ;
245             try {
246                 //
247                 // Open our database connection.
248                 database = this.getDatabase() ;
249                 //
250                 // Begin a new database transaction.
251                 database.begin();
252                 //
253                 // Try creating the group in the database.
254                 database.create(group);
255                 //
256                 // Commit the transaction.
257                 database.commit() ;
258                 }
259             //
260             // If we already have an object with that ident.
261             catch (DuplicateIdentityException ouch)
262                 {
263                 //
264                 // Cancel the database transaction.
265                 rollbackTransaction(database) ;
266                 //
267                 // Throw a new Exception.
268                 throw new CommunityPolicyException(
269                     "Duplicate Group already exists",
270                     ident.getAccountIdent()
271                     ) ;
272                 }
273             //
274             // If anything else went bang.
275             catch (Exception ouch)
276                 {
277                 //
278                 // Log the exception.
279                 logException(
280                     ouch,
281                     "GroupManagerImpl.addGroup()"
282                     ) ;
283                 //
284                 // Cancel the database transaction.
285                 rollbackTransaction(database) ;
286                 //
287                 // Throw a new Exception.
288                 throw new CommunityServiceException(
289                     "Database transaction failed",
290                     ident.getAccountIdent(),
291                     ouch
292                     ) ;
293                 }
294             //
295             // Close our database connection.
296             finally
297                 {
298                 closeConnection(database) ;
299                 }
300             return group ;
301             }
302         //
303         // If the ident is not local.
304         else {
305             throw new CommunityPolicyException(
306                 "Group is not local",
307                 ident.getAccountIdent()
308                 ) ;
309             }
310         }
311 
312     /***
313      * Request a Group details, given the Group ident.
314      * @param  ident The Group identifier.
315      * @return An GroupData for the Group.
316      * @throws CommunityIdentifierException If the identifier is not valid.
317      * @throws CommunityPolicyException If the identifier is not in the database.
318      * @throws CommunityServiceException If there is an internal error in the service.
319      * @todo Refactor to use Ivorn identifiers
320      *
321      */
322     public GroupData getGroup(String ident)
323         throws CommunityServiceException, CommunityIdentifierException, CommunityPolicyException
324         {
325         return this.getGroup(
326             new CommunityIvornParser(
327                 ident
328                 )
329             ) ;
330         }
331 
332     /***
333      * Request a Group details, given the Group ident.
334      * @param  ident The Group identifier.
335      * @return An GroupData for the Group.
336      * @throws CommunityIdentifierException If the identifier is not valid.
337      * @throws CommunityPolicyException If the identifier is not local.
338      * @throws CommunityPolicyException If the identifier is not in the database.
339      * @throws CommunityServiceException If there is an internal error in the service.
340      * @todo Verify that the finally gets executed, even if a new Exception is thrown.
341      *
342      */
343     protected GroupData getGroup(CommunityIvornParser ident)
344         throws CommunityServiceException, CommunityIdentifierException, CommunityPolicyException
345         {
346         log.debug("") ;
347         log.debug("----\"----") ;
348         log.debug("GroupManagerImpl.getGroup()") ;
349         log.debug("  Ident : " + ident) ;
350         //
351         // Check for null ident.
352         if (null == ident)
353             {
354             throw new CommunityIdentifierException(
355                 "Null identifier"
356                 ) ;
357             }
358         //
359         // If the ident is local.
360         if (ident.isLocal())
361             {
362             Database  database = null ;
363             GroupData group    = null ;
364             try {
365                 //
366                 // Open our database connection.
367                 database = this.getDatabase() ;
368                 //
369                 // Begin a new database transaction.
370                 database.begin();
371                 //
372                 // Load the Group from the database.
373                 group = (GroupData) database.load(GroupData.class, ident.getAccountIdent()) ;
374                 //
375                 // Commit the transaction.
376                 database.commit() ;
377                 }
378             //
379             // If we couldn't find the object.
380             catch (ObjectNotFoundException ouch)
381                 {
382                 //
383                 // Cancel the database transaction.
384                 rollbackTransaction(database) ;
385                 //
386                 // Throw a new Exception.
387                 throw new CommunityPolicyException(
388                     "Group not found",
389                     ident.getAccountIdent()
390                     ) ;
391                 }
392             //
393             // If anything else went bang.
394             catch (Exception ouch)
395                 {
396                 //
397                 // Log the exception.
398                 logException(
399                     ouch,
400                     "GroupManagerImpl.getGroup()"
401                     ) ;
402                 //
403                 // Cancel the database transaction.
404                 rollbackTransaction(database) ;
405                 //
406                 // Throw a new Exception.
407                 throw new CommunityServiceException(
408                     "Database transaction failed",
409                     ident.getAccountIdent(),
410                     ouch
411                     ) ;
412                 }
413             //
414             // Close our database connection.
415             finally
416                 {
417                 closeConnection(database) ;
418                 }
419             return group ;
420             }
421         //
422         // If the ident is not local.
423         else {
424             throw new CommunityPolicyException(
425                 "Group is not local",
426                 ident.getAccountIdent()
427                 ) ;
428             }
429         }
430 
431     /***
432      * Update a Group.
433      * @param  account The new GroupData to update.
434      * @return A new GroupData for the Group.
435      * @throws CommunityIdentifierException If the identifier is not valid.
436      * @throws CommunityPolicyException If the identifier is not local.
437      * @throws CommunityPolicyException If the identifier is not in the database.
438      * @throws CommunityServiceException If there is an internal error in the service.
439      * @todo Verify that the finally gets executed, even if a new Exception is thrown.
440      *
441      */
442     public GroupData setGroup(GroupData group)
443         throws CommunityServiceException, CommunityIdentifierException, CommunityPolicyException
444         {
445         log.debug("") ;
446         log.debug("----\"----") ;
447         log.debug("GroupManagerImpl.setGroup()") ;
448         log.debug("  Group : " + ((null != group) ? group.getIdent() : null)) ;
449         //
450         // Check for null group.
451         if (null == group)
452             {
453             throw new CommunityIdentifierException(
454                 "Null group"
455                 ) ;
456             }
457         //
458         // Get the Group ident.
459         CommunityIvornParser ident = new CommunityIvornParser(
460             group.getIdent()
461             ) ;
462         //
463         // If the ident is local.
464         if (ident.isLocal())
465             {
466             //
467             // Try update the database.
468             Database database = null ;
469             try {
470                 //
471                 // Open our database connection.
472                 database = this.getDatabase() ;
473                 //
474                 // Begin a new database transaction.
475                 database.begin();
476                 //
477                 // Load the Group from the database.
478                 GroupData data = (GroupData) database.load(GroupData.class, ident.getAccountIdent()) ;
479                 //
480                 // Update the group data.
481                 data.setDisplayName(group.getDisplayName()) ;
482                 data.setDescription(group.getDescription()) ;
483                 //
484                 // Commit the transaction.
485                 database.commit() ;
486                 }
487             //
488             // If we couldn't find the object.
489             catch (ObjectNotFoundException ouch)
490                 {
491                 //
492                 // Cancel the database transaction.
493                 rollbackTransaction(database) ;
494                 //
495                 // Throw a new Exception.
496                 throw new CommunityPolicyException(
497                     "Group not found",
498                     ident.getAccountIdent()
499                     ) ;
500                 }
501             //
502             // If anything else went bang.
503             catch (Exception ouch)
504                 {
505                 //
506                 // Log the exception.
507                 logException(
508                     ouch,
509                     "GroupManagerImpl.setGroup()"
510                     ) ;
511                 //
512                 // Cancel the database transaction.
513                 rollbackTransaction(database) ;
514                 //
515                 // Throw a new Exception.
516                 throw new CommunityServiceException(
517                     "Database transaction failed",
518                     ident.getAccountIdent(),
519                     ouch
520                     ) ;
521                 }
522             //
523             // Close our database connection.
524             finally
525                 {
526                 closeConnection(database) ;
527                 }
528             return group ;
529             }
530         //
531         // If the ident is not local.
532         else {
533             throw new CommunityPolicyException(
534                 "Group is not local",
535                 ident.getAccountIdent()
536                 ) ;
537             }
538         }
539 
540     /***
541      * Delete a Group.
542      * @param  ident The Group identifier.
543      * @return The GroupData for the old Group.
544      * @throws CommunityIdentifierException If the identifier is not valid.
545      * @throws CommunityPolicyException If the identifier is not in the database.
546      * @throws CommunityServiceException If there is an internal error in the service.
547      *
548      */
549     public GroupData delGroup(String ident)
550         throws CommunityServiceException, CommunityIdentifierException, CommunityPolicyException
551         {
552         return this.delGroup(
553             new CommunityIvornParser(
554                 ident
555                 )
556             ) ;
557         }
558 
559     /***
560      * Delete a Group.
561      * @param  ident The Group identifier.
562      * @return The GroupData for the old Group.
563      * @throws CommunityIdentifierException If the identifier is not valid.
564      * @throws CommunityPolicyException If the identifier is not local.
565      * @throws CommunityServiceException If there is an internal error in the service.
566      * @todo Need to have a mechanism for notifying other Communities that the Group has been deleted.
567      * @todo Verify that the finally gets executed, even if a new Exception is thrown.
568      * @todo Refactor to use Ivorn identifiers.
569      * @todo Prevent the client from deleting a private Group if the Account still exists.
570      *
571      */
572     protected GroupData delGroup(CommunityIvornParser ident)
573         throws CommunityServiceException, CommunityIdentifierException, CommunityPolicyException
574         {
575         log.debug("") ;
576         log.debug("----\"----") ;
577         log.debug("GroupManagerImpl.delGroup()") ;
578         log.debug("  ident : " + ident) ;
579         //
580         // Check for null ident.
581         if (null == ident)
582             {
583             throw new CommunityIdentifierException(
584                 "Null identifier"
585                 ) ;
586             }
587         //
588         // If the ident is local.
589         if (ident.isLocal())
590             {
591             //
592             // Try update the database.
593             GroupData group    = null ;
594             Database  database = null ;
595             try {
596                 //
597                 // Open our database connection.
598                 database = this.getDatabase() ;
599                 //
600                 // Begin a new database transaction.
601                 database.begin();
602                 //
603                 // Load the Group from the database.
604                 group = (GroupData) database.load(GroupData.class, ident.getAccountIdent()) ;
605                 //
606                 // Delete the Group.
607                 database.remove(group) ;
608                 //
609                 // Commit the transaction.
610                 database.commit() ;
611                 }
612             //
613             // If we couldn't find the object.
614             catch (ObjectNotFoundException ouch)
615                 {
616                 //
617                 // Cancel the database transaction.
618                 rollbackTransaction(database) ;
619                 //
620                 // Throw a new Exception.
621                 throw new CommunityPolicyException(
622                     "Group not found",
623                     ident.getAccountIdent()
624                     ) ;
625                 }
626             //
627             // If anything else went bang.
628             catch (Exception ouch)
629                 {
630                 //
631                 // Log the exception.
632                 logException(
633                     ouch,
634                     "GroupManagerImpl.delGroup()"
635                     ) ;
636                 //
637                 // Cancel the database transaction.
638                 rollbackTransaction(database) ;
639                 //
640                 // Throw a new Exception.
641                 throw new CommunityServiceException(
642                     "Database transaction failed",
643                     ident.getAccountIdent(),
644                     ouch
645                     ) ;
646                 }
647             //
648             // Close our database connection.
649             finally
650                 {
651                 closeConnection(database) ;
652                 }
653             return group ;
654             }
655         //
656         // If the ident is not local.
657         else {
658             throw new CommunityPolicyException(
659                 "Group is not local",
660                 ident.getAccountIdent()
661                 ) ;
662             }
663         }
664 
665     /***
666      * Request a list of local Groups.
667      * @return An array of GroupData objects.
668      * @throws CommunityServiceException If there is an internal error in the service.
669      * @todo Return empty array rather than null.
670      *
671      */
672     public Object[] getLocalGroups()
673         throws CommunityServiceException
674         {
675         log.debug("") ;
676         log.debug("----\"----") ;
677         log.debug("GroupManagerImpl.getLocalGroups()") ;
678         //
679         // Try to query the database.
680         Object[] array = null ;
681         Database database = null ;
682         try {
683             //
684             // Open our database connection.
685             database = this.getDatabase() ;
686             //
687             // Begin a new database transaction.
688             database.begin();
689             //
690             // Create our OQL query.
691             OQLQuery query = database.getOQLQuery(
692                 "SELECT groups FROM org.astrogrid.community.common.policy.data.GroupData groups"
693                 );
694 //
695 // TODO
696 // Should only request MULTI groups.
697 //
698             //
699             // Execute our query.
700             QueryResults results = query.execute();
701             //
702             // Transfer our results to a vector.
703             Collection collection = new Vector() ;
704             while (results.hasMore())
705                 {
706                 collection.add((GroupData)results.next()) ;
707                 }
708             //
709             // Convert it into an array.
710             array = collection.toArray() ;
711             //
712             // Commit the transaction.
713             database.commit() ;
714             }
715         //
716         // If anything went bang.
717         catch (Exception ouch)
718             {
719             //
720             // Log the exception.
721             logException(
722                 ouch,
723                 "GroupManagerImpl.getLocalGroups()"
724                 ) ;
725             //
726             // Cancel the database transaction.
727             rollbackTransaction(database) ;
728             //
729             // Throw a new Exception.
730             throw new CommunityServiceException(
731                 "Database transaction failed",
732                 ouch
733                 ) ;
734             }
735         //
736         // Close our database connection.
737         finally
738             {
739             closeConnection(database) ;
740             }
741         return array ;
742         }
743 
744     /***
745      * Add an Account to a Group.
746      * Group must be local, but Account can be local or remote.
747      * @param account The Account identifier.
748      * @param group   The Group identifier.
749      * @return A GroupMemberData for the membership.
750      * @throws CommunityIdentifierException If one of the identifiers is not valid.
751      * @throws CommunityPolicyException If the group is not local.
752      * @throws CommunityPolicyException If the membership already exists.
753      * @throws CommunityServiceException If there is an internal error in the service.
754      *
755      */
756     public GroupMemberData addGroupMember(String account, String group)
757         throws CommunityServiceException, CommunityPolicyException, CommunityIdentifierException
758         {
759         return this.addGroupMember(
760             new CommunityIvornParser(
761                 account
762                 ),
763             new CommunityIvornParser(
764                 group
765                 )
766             ) ;
767         }
768 
769     /***
770      * Add an Account to a Group.
771      * Group must be local, but Account can be local or remote.
772      * @param account The Account identifier.
773      * @param group   The Group identifier.
774      * @return A GroupMemberData for the membership.
775      * @throws CommunityIdentifierException If one of the identifiers is not valid.
776      * @throws CommunityPolicyException If the group is not local.
777      * @throws CommunityPolicyException If the membership already exists.
778      * @throws CommunityServiceException If there is an internal error in the service.
779      * @todo Check the actually exists.
780      * @todo Check the group isn't a private group.
781      *
782      */
783     protected GroupMemberData addGroupMember(CommunityIvornParser account, CommunityIvornParser group)
784         throws CommunityServiceException, CommunityPolicyException, CommunityIdentifierException
785         {
786         log.debug("") ;
787         log.debug("----\"----") ;
788         log.debug("GroupManagerImpl.addGroupMember()") ;
789         log.debug("  account  : " + account) ;
790         log.debug("  group    : " + group) ;
791         //
792         // Check for null account.
793         if (null == account)
794             {
795             throw new CommunityIdentifierException(
796                 "Null account"
797                 ) ;
798             }
799         //
800         // Check for null group.
801         if (null == group)
802             {
803             throw new CommunityIdentifierException(
804                 "Null group"
805                 ) ;
806             }
807         
808         //Checking if this account actually exists
809         
810         AccountData ad = null;
811         if(account.isLocal()) {
812             /*
813              * Previous code ...
814              * AccountManagerImpl ami = new AccountManagerImpl();
815              * ad = ami.getAccount(account);
816              *
817              * The GroupManager needs to use the current AccountManagerImpl because Castor maintains an
818              * in-memory cache of AccountData objects, with read-write locks.
819              *
820              */
821             //
822             // If we have a local AccountManager.
823             if (null != accountManager)
824                 {
825                 ad = accountManager.getAccount(
826                     account
827                     );
828                 }
829             //
830             // If we don't have a local AccountManager.
831             else {
832                 throw new CommunityServiceException(
833                     "Could not resolve local manager"
834                     ) ;
835                 }
836 
837         }else {
838             try {
839                 CommunityAccountResolver car = new CommunityAccountResolver();
840                 ad = car.resolve(account);
841             }catch(CommunityResolverException cre) {
842                 throw new CommunityServiceException(
843                         "Could not resolve account = " + account,
844                         cre
845                         ) ;
846             }catch(RegistryException re) {
847                 throw new CommunityServiceException(
848                         "Could not resolve account = " + account,
849                         re
850                         ) ;            
851             }
852         }
853 
854         //Lets just double check, but the above statements should throw
855         //an exception or give is a valid non-null AccountData
856         if(ad == null) {
857             throw new CommunityServiceException(
858                 "Could not find account = " + account);
859         }
860 
861         
862 //
863 // Check the group isn't an account group.
864 //
865         //
866         // If the group is local.
867         if (group.isLocal())
868             {
869             //
870             // Create our new GroupMemberData.
871             GroupMemberData member = new GroupMemberData() ;
872             member.setAccount(
873                 ad.getIdent()
874                 ) ;                //account.getAccountIdent()
875             member.setGroup(
876                 group.getAccountIdent()
877                 ) ;
878             //
879             // Try performing our transaction.
880             Database database = null ;
881             try {
882                 //
883                 // Open our database connection.
884                 database = this.getDatabase() ;
885                 //
886                 // Begin a new database transaction.
887                 database.begin();
888                 //
889                 // Try creating the record in the database.
890                 database.create(member);
891                 //
892                 // Commit the transaction.
893                 database.commit() ;
894                 }
895             //
896             // If the account is already a member of this group.
897             catch (DuplicateIdentityException ouch)
898                 {
899                 //
900                 // Cancel the database transaction.
901                 rollbackTransaction(database) ;
902                 //
903                 // Throw a new Exception.
904                 throw new CommunityPolicyException(
905                     "GroupMembership already exists",
906                     (account.getAccountIdent() + "|" + group.getAccountIdent())
907                     ) ;
908                 }
909             //
910             // If anything else went bang.
911             catch (Exception ouch)
912                 {
913                 //
914                 // Log the exception.
915                 logException(
916                     ouch,
917                     "GroupManagerImpl.addGroupMember()"
918                     ) ;
919                 //
920                 // Cancel the database transaction.
921                 rollbackTransaction(database) ;
922                 //
923                 // Throw a new Exception.
924                 throw new CommunityServiceException(
925                     "Database transaction failed",
926                     ouch
927                     ) ;
928                 }
929             //
930             // Close our database connection.
931             finally
932                 {
933                 closeConnection(database) ;
934                 }
935             return member ;
936             }
937         //
938         // If the group is not local.
939         else {
940             throw new CommunityPolicyException(
941                 "Group is not local",
942                 group.getAccountIdent()
943                 ) ;
944             }
945         }
946 
947     /***
948      * Remove an Account from a Group.
949      * Group must be local, but Account can be local or remote.
950      * @param account The Account identifier.
951      * @param group   The Group identifier.
952      * @return A GroupMemberData for the membership.
953      * @throws CommunityIdentifierException If one of the identifiers is not valid.
954      * @throws CommunityPolicyException If the membership does not exist.
955      * @throws CommunityServiceException If there is an internal error in the service.
956      *
957      */
958     public GroupMemberData delGroupMember(String account, String group)
959         throws CommunityServiceException, CommunityPolicyException, CommunityIdentifierException
960         {
961         return this.delGroupMember(
962             new CommunityIvornParser(
963                 account
964                 ),
965             new CommunityIvornParser(
966                 group
967                 )
968             ) ;
969         }
970 
971     /***
972      * Remove an Account from a Group.
973      * Group must be local, but Account can be local or remote.
974      * @param account The Account identifier.
975      * @param group   The Group identifier.
976      * @return A GroupMemberData for the membership.
977      * @throws CommunityIdentifierException If one of the identifiers is not valid.
978      * @throws CommunityPolicyException If the membership does not exist.
979      * @throws CommunityServiceException If there is an internal error in the service.
980      * @todo Check the group isn't a private group.
981      *
982      */
983     protected GroupMemberData delGroupMember(CommunityIvornParser account, CommunityIvornParser group)
984         throws CommunityServiceException, CommunityPolicyException, CommunityIdentifierException
985         {
986         log.debug("") ;
987         log.debug("----\"----") ;
988         log.debug("GroupManagerImpl.delGroupMember()") ;
989         log.debug("  account  : " + account) ;
990         log.debug("  group    : " + group) ;
991         //
992         // Check for null account.
993         if (null == account)
994             {
995             throw new CommunityIdentifierException(
996                 "Null account"
997                 ) ;
998             }
999         //
1000         // Check for null group.
1001         if (null == group)
1002             {
1003             throw new CommunityIdentifierException(
1004                 "Null group"
1005                 ) ;
1006             }
1007         //
1008         // No checks if the account ident is valid.
1009         // Still want to delete the record even if the ident is invalid.
1010         //
1011 //
1012 // Check the group isn't an account group.
1013 // But, still proceed if the group does not exist.
1014 // There is a potential mix up here.
1015 // 1) Create a group called 'frog'
1016 // 2) Add members to the group.
1017 // 3) Delete the group.
1018 // 4) Create an account called 'frog'
1019 // 4) Now have account with members, but can't delete them.
1020 //
1021         //
1022         // Try update the database.
1023         GroupMemberData member   = null ;
1024         Database        database = null ;
1025         try {
1026             //
1027             // Open our database connection.
1028             database = this.getDatabase() ;
1029             //
1030             // Begin a new database transaction.
1031             database.begin();
1032             //
1033             // Create the database key.
1034             Complex key = new Complex(
1035                 new Object[]
1036                     {
1037                     account.getAccountIdent(),
1038                     group.getAccountIdent()
1039                     }
1040                 ) ;
1041             //
1042             // Load the GroupMember from the database.
1043             member = (GroupMemberData) database.load(GroupMemberData.class, key) ;
1044             //
1045             // Delete the record.
1046             database.remove(member) ;
1047             //
1048             // Commit the transaction.
1049             database.commit() ;
1050             }
1051         //
1052         // If we couldn't find the object.
1053         catch (ObjectNotFoundException ouch)
1054             {
1055             //
1056             // Cancel the database transaction.
1057             rollbackTransaction(database) ;
1058             //
1059             // Throw a new Exception.
1060             throw new CommunityPolicyException(
1061                 "GroupMembership not found",
1062                 (account.getAccountIdent() + "|" + group.getAccountIdent())
1063                 ) ;
1064             }
1065         //
1066         // If anything else went bang.
1067         catch (Exception ouch)
1068             {
1069             //
1070             // Log the exception.
1071             logException(
1072                 ouch,
1073                 "GroupManagerImpl.delGroupMember()"
1074                 ) ;
1075             //
1076             // Cancel the database transaction.
1077             rollbackTransaction(database) ;
1078             //
1079             // Throw a new Exception.
1080             throw new CommunityServiceException(
1081                 "Database transaction failed",
1082                 ouch
1083                 ) ;
1084             }
1085         //
1086         // Close our database connection.
1087         finally
1088             {
1089             closeConnection(database) ;
1090             }
1091         return member ;
1092         }
1093 
1094     /***
1095      * Request a Group Membership details.
1096      * Group must be local, but Account can be local or remote.
1097      * @param account The Account identifier.
1098      * @param group   The Group identifier.
1099      * @return A GroupMemberData for the membership.
1100      * @throws CommunityIdentifierException If one of the identifiers is not valid.
1101      * @throws CommunityPolicyException If the group is not local.
1102      * @throws CommunityPolicyException If the membership does not exist.
1103      * @throws CommunityServiceException If there is an internal error in the service.
1104      *
1105      */
1106     public GroupMemberData getGroupMember(String account, String group)
1107         throws CommunityServiceException, CommunityPolicyException, CommunityIdentifierException
1108         {
1109         return this.getGroupMember(
1110             new CommunityIvornParser(
1111                 account
1112                 ),
1113             new CommunityIvornParser(
1114                 group
1115                 )
1116             ) ;
1117         }
1118 
1119     /***
1120      * Request a Group Membership details.
1121      * Group must be local, but Account can be local or remote.
1122      * @param account The Account identifier.
1123      * @param group   The Group identifier.
1124      * @return A GroupMemberData for the membership.
1125      * @throws CommunityIdentifierException If one of the identifiers is not valid.
1126      * @throws CommunityPolicyException If the group is not local.
1127      * @throws CommunityPolicyException If the membership does not exist.
1128      * @throws CommunityServiceException If there is an internal error in the service.
1129      *
1130      */
1131     protected GroupMemberData getGroupMember(CommunityIvornParser account, CommunityIvornParser group)
1132         throws CommunityServiceException, CommunityPolicyException, CommunityIdentifierException
1133         {
1134         log.debug("") ;
1135         log.debug("----\"----") ;
1136         log.debug("GroupManagerImpl.getGroupMember()") ;
1137         log.debug("  account  : " + account) ;
1138         log.debug("  group    : " + group) ;
1139         //
1140         // Check for null account.
1141         if (null == account)
1142             {
1143             throw new CommunityIdentifierException(
1144                 "Null account"
1145                 ) ;
1146             }
1147         //
1148         // Check for null group.
1149         if (null == group)
1150             {
1151             throw new CommunityIdentifierException(
1152                 "Null group"
1153                 ) ;
1154             }
1155         //
1156         // If the group is local.
1157         if (group.isLocal())
1158             {
1159             GroupMemberData member   = null ;
1160             Database        database = null ;
1161             try {
1162                 //
1163                 // Open our database connection.
1164                 database = this.getDatabase() ;
1165                 //
1166                 // Begin a new database transaction.
1167                 database.begin();
1168                 //
1169                 // Create the database key.
1170                 Complex key = new Complex(
1171                     new Object[]
1172                         {
1173                         account.getAccountIdent(),
1174                         group.getAccountIdent()
1175                         }
1176                     ) ;
1177                 //
1178                 // Load the GroupMember from the database.
1179                 member = (GroupMemberData) database.load(GroupMemberData.class, key) ;
1180                 //
1181                 // Commit the transaction.
1182                 database.commit() ;
1183                 }
1184             //
1185             // If we couldn't find the object.
1186             catch (ObjectNotFoundException ouch)
1187                 {
1188                 //
1189                 // Cancel the database transaction.
1190                 rollbackTransaction(database) ;
1191                 //
1192                 // Throw a new Exception.
1193                 throw new CommunityPolicyException(
1194                     "GroupMembership not found",
1195                     (account.getAccountIdent() + "|" + group.getAccountIdent())
1196                     ) ;
1197                 }
1198             //
1199             // If anything else went bang.
1200             catch (Exception ouch)
1201                 {
1202                 //
1203                 // Log the exception.
1204                 logException(
1205                     ouch,
1206                     "GroupManagerImpl.getGroupMember()"
1207                     ) ;
1208                 //
1209                 // Cancel the database transaction.
1210                 rollbackTransaction(database) ;
1211                 //
1212                 // Throw a new Exception.
1213                 throw new CommunityServiceException(
1214                     "Database transaction failed",
1215                     ouch
1216                     ) ;
1217                 }
1218             //
1219             // Close our database connection.
1220             finally
1221                 {
1222                 closeConnection(database) ;
1223                 }
1224             return member ;
1225             }
1226         //
1227         // If the group is not local.
1228         else {
1229             throw new CommunityPolicyException(
1230                 "Group is not local",
1231                 group.getAccountIdent()
1232                 ) ;
1233             }
1234         }
1235 
1236     /***
1237      * Request a list of Group Members.
1238      * @param group The Group identifier.
1239      * @return An array of GroupMemberData objects.
1240      * @throws CommunityIdentifierException If one of the identifiers is not valid.
1241      * @throws CommunityPolicyException If the group is not local.
1242      * @throws CommunityServiceException If there is an internal error in the service.
1243      *
1244      */
1245     public Object[] getGroupMembers(String group)
1246         throws CommunityServiceException, CommunityPolicyException, CommunityIdentifierException
1247         {
1248         return this.getGroupMembers(
1249             new CommunityIvornParser(
1250                 group
1251                 )
1252             ) ;
1253         }
1254 
1255     /***
1256      * Request a list of Group Members.
1257      * @param group The Group identifier.
1258      * @return An array of GroupMemberData objects.
1259      * @throws CommunityIdentifierException If one of the identifiers is not valid.
1260      * @throws CommunityPolicyException If the group is not local.
1261      * @throws CommunityServiceException If there is an internal error in the service.
1262      * @todo Return empty array rather than null.
1263      *
1264      */
1265     protected Object[] getGroupMembers(CommunityIvornParser group)
1266         throws CommunityServiceException, CommunityPolicyException, CommunityIdentifierException
1267         {
1268         log.debug("") ;
1269         log.debug("----\"----") ;
1270         log.debug("GroupManagerImpl.getGroupMembers()") ;
1271         log.debug("  group    : " + group) ;
1272         //
1273         // Check for null group.
1274         if (null == group)
1275             {
1276             throw new CommunityIdentifierException(
1277                 "Null group"
1278                 ) ;
1279             }
1280         Object[] array    = null ;
1281         Database database = null ;
1282         //
1283         // If the Group is local.
1284         if (group.isLocal())
1285             {
1286             log.debug("PASS : Group is local") ;
1287             //
1288             // Try to query the database.
1289             try {
1290                 //
1291                 // Open our database connection.
1292                 database = this.getDatabase() ;
1293                 //
1294                 // Begin a new database transaction.
1295                 database.begin();
1296                 //
1297                 // Create our OQL query.
1298                  
1299                 OQLQuery query = database.getOQLQuery(
1300                     "SELECT members FROM org.astrogrid.community.common.policy.data.GroupMemberData members WHERE members.group = $1"
1301                     );
1302                 //
1303                 // Bind the query param.
1304                 query.bind(group.getAccountIdent()) ;
1305                 //
1306                 // Execute our query.
1307                 QueryResults results = query.execute();
1308                 //
1309                 // Transfer our results to a vector.
1310                 Collection collection = new Vector() ;
1311                 while (results.hasMore())
1312                     {
1313                     collection.add((GroupMemberData)results.next()) ;
1314                     }
1315                 // 
1316                 // Convert it into an array.
1317                 array = collection.toArray() ;
1318                 //
1319                 // Commit the transaction.
1320                 database.commit() ;
1321                 }
1322             //
1323             // If anything went bang.
1324             catch (Exception ouch)
1325                 {
1326                 //
1327                 // Log the exception.
1328                 logException(
1329                     ouch,
1330                     "GroupManagerImpl.getGroupMembers()"
1331                     ) ;
1332                 //
1333                 // Cancel the database transaction.
1334                 rollbackTransaction(database) ;
1335                 //
1336                 // Throw a new Exception.
1337                 throw new CommunityServiceException(
1338                     "Database transaction failed",
1339                     ouch
1340                     ) ;
1341                 }
1342             //
1343             // Close our database connection.
1344             finally
1345                 {
1346                 closeConnection(database) ;
1347                 }
1348             }
1349         //
1350         // If the group is not local.
1351         else {
1352             throw new CommunityPolicyException(
1353                 "Group is not local",
1354                 group.getAccountIdent()
1355                 ) ;
1356             }
1357         return array;
1358         }
1359     
1360     /***
1361      * Request a list of Group Members.
1362      * @param group The Group identifier.
1363      * @return An array of GroupMemberData objects.
1364      * @throws CommunityIdentifierException If one of the identifiers is not valid.
1365      * @throws CommunityPolicyException If the group is not local.
1366      * @throws CommunityServiceException If there is an internal error in the service.
1367      * @todo Return empty array rather than null.
1368      *
1369      */
1370     public Object[] getGroupMembers()
1371         throws CommunityServiceException, CommunityPolicyException, CommunityIdentifierException
1372         {
1373         log.debug("") ;
1374         log.debug("----\"----") ;
1375         log.debug("GroupManagerImpl.getGroupMembers()") ;
1376         //log.debug("  group    : " + group) ;
1377         //
1378         // Check for null group.
1379         Object[] array    = null ;
1380         Database database = null ;
1381         try {
1382                 //
1383                 // Open our database connection.
1384                 database = this.getDatabase() ;
1385                 //
1386                 // Begin a new database transaction.
1387                 database.begin();
1388                 //
1389                 // Create our OQL query.
1390                 OQLQuery query = database.getOQLQuery(
1391                     "SELECT members FROM org.astrogrid.community.common.policy.data.GroupMemberData members"
1392                     );
1393                 //
1394                 // Bind the query param.
1395                 //query.bind(group.getAccountIdent()) ;
1396                 //
1397                 // Execute our query.
1398                 QueryResults results = query.execute();
1399                 //
1400                 // Transfer our results to a vector.
1401                 Collection collection = new Vector() ;
1402                 while (results.hasMore())
1403                     {
1404                     collection.add((GroupMemberData)results.next()) ;
1405                     }
1406                 // 
1407                 // Convert it into an array.
1408                 array = collection.toArray() ;
1409                 //
1410                 // Commit the transaction.
1411                 database.commit() ;
1412                 }
1413             //
1414             // If anything went bang.
1415             catch (Exception ouch)
1416                 {
1417                 //
1418                 // Log the exception.
1419                 logException(
1420                     ouch,
1421                     "GroupManagerImpl.getGroupMembers()"
1422                     ) ;
1423                 //
1424                 // Cancel the database transaction.
1425                 rollbackTransaction(database) ;
1426                 //
1427                 // Throw a new Exception.
1428                 throw new CommunityServiceException(
1429                     "Database transaction failed",
1430                     ouch
1431                     ) ;
1432                 }
1433             //
1434             // Close our database connection.
1435             finally
1436                 {
1437                 closeConnection(database) ;
1438                 }
1439         return array;
1440     }
1441     
1442     
1443 
1444     /***
1445      * Request a list of Groups that an Account belongs to.
1446      * @param account The Account identifier.
1447      * @return An array of GroupMemberData objects.
1448      * @throws CommunityIdentifierException If one of the identifiers is not valid.
1449      * @throws CommunityServiceException If there is an internal error in the service.
1450      *
1451      */
1452     public Object[] getLocalAccountGroups(String account)
1453         throws CommunityServiceException, CommunityIdentifierException
1454         {
1455         return this.getLocalAccountGroups(
1456             new CommunityIvornParser(
1457                 account
1458                 )
1459             ) ;
1460         }
1461 
1462     /***
1463      * Request a list of Groups that an Account belongs to.
1464      * @param account The Account identifier.
1465      * @return An array of GroupMemberData objects.
1466      * @throws CommunityIdentifierException If one of the identifiers is not valid.
1467      * @throws CommunityServiceException If there is an internal error in the service.
1468      * @todo Return empty array rather than null.
1469      *
1470      */
1471     protected Object[] getLocalAccountGroups(CommunityIvornParser account)
1472         throws CommunityServiceException, CommunityIdentifierException
1473         {
1474         log.debug("") ;
1475         log.debug("----\"----") ;
1476         log.debug("GroupManagerImpl.getLocalAccountGroups()") ;
1477         log.debug("  account   : " + account) ;
1478         //
1479         // Check for null account.
1480         if (null == account)
1481             {
1482             throw new CommunityIdentifierException(
1483                 "Null account"
1484                 ) ;
1485             }
1486         Object[] array    = null ;
1487         Database database = null ;
1488         //
1489         // Try to query the database.
1490         try {
1491             //
1492             // Open our database connection.
1493             database = this.getDatabase() ;
1494             //
1495             // Begin a new database transaction.
1496             database.begin();
1497             //
1498             // Create our OQL query.
1499             OQLQuery query = database.getOQLQuery(
1500                 "SELECT members FROM org.astrogrid.community.policy.data.GroupMemberData members WHERE members.account = $1"
1501                 );
1502             //
1503             // Bind the query param.
1504             query.bind(account.getAccountIdent()) ;
1505             //
1506             // Execute our query.
1507             QueryResults results = query.execute();
1508             //
1509             // Transfer our results to a vector.
1510             Collection collection = new Vector() ;
1511             while (results.hasMore())
1512                 {
1513                 collection.add(results.next()) ;
1514                 }
1515             // 
1516             // Convert it into an array.
1517             array = collection.toArray() ;
1518             //
1519             // Commit the transaction.
1520             database.commit() ;
1521             }
1522         //
1523         // If anything went bang.
1524         catch (Exception ouch)
1525             {
1526             //
1527             // Log the exception.
1528             logException(
1529                 ouch,
1530                 "GroupManagerImpl.getLocalAccountGroups()"
1531                 ) ;
1532             //
1533             // Cancel the database transaction.
1534             rollbackTransaction(database) ;
1535             //
1536             // Throw a new Exception.
1537             throw new CommunityServiceException(
1538                 "Database transaction failed",
1539                 ouch
1540                 ) ;
1541             }
1542         //
1543         // Close our database connection.
1544         finally
1545             {
1546             closeConnection(database) ;
1547             }
1548         return array ;
1549         }
1550     }