1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50 package org.astrogrid.community.server.policy.manager ;
51
52 import org.apache.commons.logging.Log ;
53 import org.apache.commons.logging.LogFactory ;
54
55 import java.util.Vector ;
56 import java.util.Collection ;
57
58 import org.exolab.castor.jdo.Database;
59 import org.exolab.castor.jdo.OQLQuery;
60 import org.exolab.castor.jdo.QueryResults;
61 import org.exolab.castor.jdo.ObjectNotFoundException ;
62 import org.exolab.castor.jdo.DuplicateIdentityException ;
63
64 import org.astrogrid.store.Ivorn ;
65
66 import org.astrogrid.config.Config ;
67 import org.astrogrid.config.SimpleConfig ;
68 import org.astrogrid.config.PropertyNotFoundException ;
69
70 import org.astrogrid.community.common.policy.data.GroupData ;
71 import org.astrogrid.community.common.policy.data.AccountData ;
72 import org.astrogrid.community.common.policy.data.GroupMemberData ;
73
74 import org.astrogrid.community.common.ivorn.CommunityIvornParser ;
75 import org.astrogrid.community.common.ivorn.CommunityAccountIvornFactory ;
76
77 import org.astrogrid.community.common.policy.manager.AccountManager ;
78
79 import org.astrogrid.community.server.service.CommunityServiceImpl ;
80 import org.astrogrid.community.server.database.configuration.DatabaseConfiguration ;
81
82 import org.astrogrid.community.common.exception.CommunityPolicyException ;
83 import org.astrogrid.community.common.exception.CommunityServiceException ;
84 import org.astrogrid.community.common.exception.CommunityIdentifierException ;
85
86 import org.astrogrid.store.VoSpaceClient ;
87
88 /***
89 * Server side implmenetation of the AccountManager service.
90 *
91 */
92 public class AccountManagerImpl
93 extends CommunityServiceImpl
94 implements AccountManager
95 {
96 /***
97 * Our debug logger.
98 *
99 */
100 private static Log log = LogFactory.getLog(AccountManagerImpl.class);
101
102 /***
103 * Our AstroGrid configuration.
104 *
105 */
106 protected static Config config = SimpleConfig.getSingleton() ;
107
108 /***
109 * The default public group.
110 * @todo This should be in a config file, not hard coded.
111 *
112 */
113 private static String DEFAULT_GROUP_NAME = "everyone" ;
114
115 /***
116 * The default public group.
117 * @todo This should be in a config file, not hard coded.
118 * @todo Find a better way of initialising it.
119 *
120 */
121 private static Ivorn DEFAULT_GROUP_IVORN ;
122
123 static {
124 try {
125 DEFAULT_GROUP_IVORN = CommunityAccountIvornFactory.createLocal(
126 DEFAULT_GROUP_NAME
127 ) ;
128 }
129 catch (Exception ouch)
130 {
131 }
132 }
133
134 /***
135 * Public constructor, using default database configuration.
136 *
137 */
138 public AccountManagerImpl()
139 {
140 super() ;
141 }
142
143 /***
144 * Public constructor, using specific database configuration.
145 * @param config A specific DatabaseConfiguration.
146 *
147 */
148 public AccountManagerImpl(DatabaseConfiguration config)
149 {
150 super(config) ;
151 }
152
153 /***
154 * Public constructor, using a parent service.
155 * @param parent A parent CommunityServiceImpl.
156 *
157 */
158 public AccountManagerImpl(CommunityServiceImpl parent)
159 {
160 super(parent) ;
161 }
162
163 /***
164 * Add a new Account, given the Account ident.
165 * @param ident The Account identifier.
166 * @return An AccountData for the Account.
167 * @throws CommunityIdentifierException If the identifier is not valid.
168 * @throws CommunityPolicyException If the identifier is already in the database.
169 * @throws CommunityServiceException If there is an internal error in the service.
170 *
171 */
172 public AccountData addAccount(String ident)
173 throws CommunityServiceException, CommunityIdentifierException, CommunityPolicyException
174 {
175
176
177 return this.addAccount(
178 new AccountData(
179 ident
180 )
181 ) ;
182 }
183
184 /***
185 * Add a new Account, given the Account data.
186 * @param account The AccountData to add.
187 * @return A new AccountData for the Account.
188 * @throws CommunityIdentifierException If the identifier is not valid.
189 * @throws CommunityPolicyException If the identifier is already in the database.
190 * @throws CommunityServiceException If there is an internal error in the service.
191 * @throws RemoteException If the WebService call fails.
192 * @todo Needs refactoring to make it more robust.
193 * @todo If the 'everyone' group does not exist, then create it.
194 * @todo If the account group already exists (as an AccountGroup) then don't throw a duplicate exception.
195 * @todo If the account already belongs to the account group then don't throw a duplicate exception.
196 * @todo If the account already belongs to the 'everyone' group then don't throw a duplicate exception.
197 * @todo If the MySpace call adds the Account, store the MySpace server and Account details.
198 * @todo Tidy up fragments of old data, e.g. groups, membership and permissions,
199 * @todo Verify that the finally gets executed, even if a new Exception is thrown.
200 *
201 */
202 public AccountData addAccount(AccountData account)
203 throws CommunityServiceException, CommunityIdentifierException, CommunityPolicyException
204 {
205 log.debug("") ;
206 log.debug("----\"----") ;
207 log.debug("AccountManagerImpl.addAccount()") ;
208 log.debug(" Account : " + ((null != account) ? account.getIdent() : null)) ;
209
210
211 if (null == account)
212 {
213 throw new CommunityIdentifierException(
214 "Null account"
215 ) ;
216 }
217
218
219 CommunityIvornParser ident = new CommunityIvornParser(
220 account.getIdent()
221 ) ;
222
223
224 if (ident.isLocal())
225 {
226
227
228 String string = ident.getAccountIdent() ;
229
230
231 account.setIdent(string) ;
232
233
234 GroupData group = new GroupData() ;
235 group.setIdent(string) ;
236 group.setType(GroupData.SINGLE_TYPE) ;
237
238
239 GroupMemberData groupmember = new GroupMemberData() ;
240 groupmember.setAccount(string) ;
241 groupmember.setGroup(string) ;
242
243
244
245
246
247 GroupMemberData guestmember = new GroupMemberData() ;
248 guestmember.setAccount(string) ;
249 guestmember.setGroup(
250 DEFAULT_GROUP_IVORN.toString()
251 ) ;
252
253
254 Database database = null ;
255 try {
256
257
258 database = this.getDatabase() ;
259
260
261 database.begin();
262
263
264 log.debug("Creating community account") ;
265 database.create(account);
266 log.debug("Ok - Created community account") ;
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283 try {
284 log.debug("Creating myspace account") ;
285 allocateSpace(account) ;
286 log.debug("Ok - Created myspace account") ;
287 log.debug("Home : " + account.getHomeSpace()) ;
288 }
289 catch (Exception ouch)
290 {
291
292
293 logException(
294 ouch,
295 "AccountManagerImpl.addAccount.allocateSpace()"
296 ) ;
297 }
298
299
300 database.commit() ;
301 }
302
303
304 catch (DuplicateIdentityException ouch)
305 {
306
307
308 rollbackTransaction(database) ;
309
310
311 throw new CommunityPolicyException(
312 "Duplicate Account identifier",
313 ident.toString()
314 ) ;
315 }
316
317
318 catch (Exception ouch)
319 {
320
321
322 logException(
323 ouch,
324 "AccountManagerImpl.addAccount()"
325 ) ;
326
327
328 rollbackTransaction(database) ;
329
330
331 throw new CommunityServiceException(
332 "Database transaction failed",
333 ident.toString(),
334 ouch
335 ) ;
336 }
337
338
339 finally
340 {
341 closeConnection(database) ;
342 }
343
344
345 return account ;
346 }
347
348
349 else {
350
351
352 throw new CommunityPolicyException(
353 "Account is not local",
354 ident.toString()
355 ) ;
356 }
357 }
358
359 /***
360 * Request an Account details, given the Account ident.
361 * @param ident The Account identifier.
362 * @return An AccountData for the Account.
363 * @throws CommunityIdentifierException If the identifier is not valid.
364 * @throws CommunityPolicyException If the identifier is not in the database.
365 * @throws CommunityServiceException If there is an internal error in the service.
366 *
367 */
368 public AccountData getAccount(String ident)
369 throws CommunityServiceException, CommunityIdentifierException, CommunityPolicyException
370 {
371 return this.getAccount(
372 new CommunityIvornParser(
373 ident
374 )
375 ) ;
376 }
377
378 /***
379 * Request an Account details, given the Account ident.
380 * @param ident The Account identifier.
381 * @return An AccountData for the Account.
382 * @throws CommunityIdentifierException If the identifier is not valid.
383 * @throws CommunityPolicyException If the identifier is not in the database.
384 * @throws CommunityServiceException If there is an internal error in the service.
385 * @todo Verify that the finally gets executed, even if a new Exception is thrown.
386 *
387 */
388 public AccountData getAccount(CommunityIvornParser ident)
389 throws CommunityServiceException, CommunityIdentifierException, CommunityPolicyException
390 {
391 log.debug("") ;
392 log.debug("----\"----") ;
393 log.debug("AccountManagerImpl.getAccount()") ;
394 log.debug(" Ident : " + ident) ;
395
396
397 if (null == ident)
398 {
399 throw new CommunityIdentifierException(
400 "Null identifier"
401 ) ;
402 }
403
404
405 if (ident.isLocal())
406 {
407
408
409 Database database = null ;
410 AccountData account = null ;
411 try {
412
413
414 String string = ident.getAccountIdent() ;
415
416
417 database = this.getDatabase() ;
418
419
420 database.begin();
421
422
423 account = (AccountData) database.load(AccountData.class, string) ;
424
425
426 database.commit() ;
427 }
428
429
430 catch (ObjectNotFoundException ouch)
431 {
432
433
434 rollbackTransaction(database) ;
435
436
437 throw new CommunityPolicyException(
438 "Account not found",
439 ident.toString()
440 ) ;
441 }
442
443
444 catch (Exception ouch)
445 {
446
447
448 logException(
449 ouch,
450 "AccountManagerImpl.getAccount()"
451 ) ;
452
453
454 rollbackTransaction(database) ;
455
456
457 throw new CommunityServiceException(
458 "Database transaction failed",
459 ident.toString(),
460 ouch
461 ) ;
462 }
463
464
465 finally
466 {
467 closeConnection(database) ;
468 }
469
470
471 return account ;
472 }
473
474
475 else {
476
477
478 throw new CommunityPolicyException(
479 "Account is not local",
480 ident.toString()
481 ) ;
482 }
483 }
484
485 /***
486 * Update an Account.
487 * @param account The new AccountData to update.
488 * @return A new AccountData for the Account.
489 * @throws CommunityIdentifierException If the identifier is not valid.
490 * @throws CommunityPolicyException If the identifier is not in the database.
491 * @throws CommunityServiceException If there is an internal error in the service.
492 * @todo Verify that the finally gets executed, even if a new Exception is thrown.
493 *
494 */
495 public AccountData setAccount(AccountData account)
496 throws CommunityServiceException, CommunityIdentifierException, CommunityPolicyException
497 {
498 log.debug("") ;
499 log.debug("----\"----") ;
500 log.debug("AccountManagerImpl.setAccount()") ;
501 log.debug(" Account : " + ((null != account) ? account.getIdent() : null)) ;
502
503
504 if (null == account)
505 {
506 throw new CommunityIdentifierException(
507 "Null account"
508 ) ;
509 }
510
511
512 CommunityIvornParser ident = new CommunityIvornParser(
513 account.getIdent()
514 ) ;
515
516
517 if (ident.isLocal())
518 {
519
520
521 Database database = null ;
522 try {
523
524
525 String string = ident.getAccountIdent() ;
526
527
528 database = this.getDatabase() ;
529
530
531 database.begin();
532
533
534 AccountData data = (AccountData) database.load(AccountData.class, string) ;
535
536
537 data.setHomeSpace(account.getHomeSpace()) ;
538 data.setDisplayName(account.getDisplayName()) ;
539 data.setDescription(account.getDescription()) ;
540 data.setEmailAddress(account.getEmailAddress()) ;
541
542
543 database.commit() ;
544 }
545
546
547 catch (ObjectNotFoundException ouch)
548 {
549
550
551 rollbackTransaction(database) ;
552
553
554 throw new CommunityPolicyException(
555 "Account not found",
556 ident.toString()
557 ) ;
558 }
559
560
561 catch (Exception ouch)
562 {
563
564
565 logException(
566 ouch,
567 "AccountManagerImpl.setAccount()"
568 ) ;
569
570
571 rollbackTransaction(database) ;
572
573
574 throw new CommunityServiceException(
575 "Database transaction failed",
576 ident.toString(),
577 ouch
578 ) ;
579 }
580
581
582 finally
583 {
584 closeConnection(database) ;
585 }
586
587
588 return account ;
589 }
590
591
592 else {
593
594
595 throw new CommunityPolicyException(
596 "Account is not local",
597 ident.toString()
598 ) ;
599 }
600 }
601
602 /***
603 * Delete an Account.
604 * @param ident The Account identifier.
605 * @return The AccountData for the old Account.
606 * @throws CommunityIdentifierException If the identifier is not valid.
607 * @throws CommunityServiceException If there is an internal error in the service.
608 *
609 */
610 public AccountData delAccount(String ident)
611 throws CommunityServiceException, CommunityIdentifierException, CommunityPolicyException
612 {
613 return this.delAccount(
614 new CommunityIvornParser(
615 ident
616 )
617 ) ;
618 }
619
620 /***
621 * Delete an Account.
622 * @param ident The Account identifier.
623 * @return The AccountData for the old Account.
624 * @throws CommunityIdentifierException If the identifier is not valid.
625 * @throws CommunityServiceException If there is an internal error in the service.
626 * @todo Need to have a mechanism for tidying up references to a remote Account.
627 * @todo Need to have a mechanism for tidying up references to an old Account.
628 * @todo Need to have a mechanism for notifying other Communities that the Account has been deleted.
629 * @todo Verify that the finally gets executed, even if a new Exception is thrown.
630 *
631 */
632 protected AccountData delAccount(CommunityIvornParser ident)
633 throws CommunityServiceException, CommunityIdentifierException, CommunityPolicyException
634 {
635 log.debug("") ;
636 log.debug("----\"----") ;
637 log.debug("AccountManagerImpl.delAccount()") ;
638 log.debug(" ident : " + ident) ;
639
640
641 if (null == ident)
642 {
643 throw new CommunityIdentifierException(
644 "Null identifier"
645 ) ;
646 }
647
648
649
650 AccountData account = null ;
651
652
653
654 if (ident.isLocal())
655 {
656 log.debug(" PASS : ident is local") ;
657
658
659 Database database = null ;
660 try {
661
662
663 String string = ident.getAccountIdent() ;
664
665
666 database = this.getDatabase() ;
667
668
669 database.begin();
670
671
672 account = (AccountData) database.load(AccountData.class, string) ;
673
674
675 if (null != account)
676 {
677 log.debug(" PASS : found account") ;
678
679
680 OQLQuery groupQuery = database.getOQLQuery(
681 "SELECT groups FROM org.astrogrid.community.common.policy.data.GroupData groups WHERE groups.ident = $1"
682 );
683
684
685 groupQuery.bind(string) ;
686
687
688 QueryResults groups = groupQuery.execute();
689 if (null != groups)
690 {
691 log.debug(" PASS : found groups") ;
692 }
693 else {
694 log.debug(" FAIL : null groups") ;
695 }
696
697
698 OQLQuery memberQuery = database.getOQLQuery(
699 "SELECT members FROM org.astrogrid.community.common.policy.data.GroupMemberData members WHERE members.account = $1"
700 );
701
702
703 memberQuery.bind(string) ;
704
705
706 QueryResults members = memberQuery.execute();
707 if (null != members)
708 {
709 log.debug(" PASS : found members") ;
710 }
711 else {
712 log.debug(" FAIL : null members") ;
713 }
714
715
716 OQLQuery permissionQuery = database.getOQLQuery(
717 "SELECT permissions FROM org.astrogrid.community.common.policy.data.PolicyPermission permissions WHERE permissions.group = $1"
718 );
719
720
721 permissionQuery.bind(string) ;
722
723
724 QueryResults permissions = permissionQuery.execute();
725 if (null != permissions)
726 {
727 log.debug(" PASS : found permissions") ;
728 }
729 else {
730 log.debug(" FAIL : null permissions") ;
731 }
732
733
734 while (permissions.hasMore())
735 {
736 log.debug(" STEP : deleting permission") ;
737 database.remove(permissions.next()) ;
738 }
739
740
741 while (members.hasMore())
742 {
743 log.debug(" STEP : deleting membership") ;
744 database.remove(members.next()) ;
745 }
746
747
748 while (groups.hasMore())
749 {
750 log.debug(" STEP : deleting group") ;
751 database.remove(groups.next()) ;
752 }
753
754
755 database.remove(account) ;
756 }
757 log.debug(" PASS : finished deleting") ;
758
759
760 database.commit() ;
761 log.debug(" PASS : done commit") ;
762 }
763
764
765 catch (ObjectNotFoundException ouch)
766 {
767
768
769 rollbackTransaction(database) ;
770
771
772 throw new CommunityPolicyException(
773 "Account not found",
774 ident.toString()
775 ) ;
776 }
777
778
779 catch (Exception ouch)
780 {
781
782
783 logException(
784 ouch,
785 "AccountManagerImpl.delAccount()"
786 ) ;
787
788
789 rollbackTransaction(database) ;
790
791
792 throw new CommunityServiceException(
793 "Database transaction failed",
794 ident.toString(),
795 ouch
796 ) ;
797 }
798
799
800 finally
801 {
802 closeConnection(database) ;
803 }
804
805
806 return account ;
807 }
808
809
810 else {
811
812
813 throw new CommunityPolicyException(
814 "Account is not local",
815 ident.toString()
816 ) ;
817 }
818 }
819
820 /***
821 * Request a list of local Accounts.
822 * @return An array of AccountData objects.
823 * @throws CommunityServiceException If there is an internal error in the service.
824 * @todo Return empty array rather than null.
825 *
826 */
827 public Object[] getLocalAccounts()
828 {
829 log.debug("") ;
830 log.debug("----\"----") ;
831 log.debug("AccountManagerImpl.getLocalAccounts()") ;
832
833
834 Object[] array = null ;
835 Database database = null ;
836 try {
837
838
839 database = this.getDatabase() ;
840
841
842 database.begin();
843
844
845 OQLQuery query = database.getOQLQuery(
846 "SELECT accounts FROM org.astrogrid.community.common.policy.data.AccountData accounts"
847 );
848
849
850 QueryResults results = query.execute();
851
852
853 Collection collection = new Vector() ;
854 while (results.hasMore())
855 {
856 collection.add(
857 (AccountData)results.next()
858 ) ;
859 }
860
861
862 array = collection.toArray() ;
863
864
865 database.commit() ;
866 }
867
868
869 catch (Exception ouch)
870 {
871
872
873 logException(ouch, "AccountManagerImpl.getLocalAccounts()") ;
874
875
876 array = null ;
877
878
879 rollbackTransaction(database) ;
880 }
881
882
883 finally
884 {
885 closeConnection(database) ;
886 }
887
888
889 return array ;
890 }
891
892 /***
893 * Allocate VoSpace space for an Account.
894 * @param account The AccountData to update.
895 * @throws CommunityIdentifierException If the identifier is not valid.
896 * @throws CommunityServiceException If the service is unable to allocate the space.
897 *
898 */
899 protected void allocateSpace(AccountData account)
900 throws CommunityServiceException, CommunityIdentifierException
901 {
902 log.debug("") ;
903 log.debug("----\"----") ;
904 log.debug("AccountManagerImpl.allocateSpace()") ;
905 log.debug(" Account : " + ((null != account) ? account.getIdent() : null)) ;
906
907
908 if (null == account)
909 {
910 throw new CommunityIdentifierException(
911 "Null account"
912 ) ;
913 }
914
915
916 if (null == account.getIdent())
917 {
918 throw new CommunityIdentifierException(
919 "Null account identifier"
920 ) ;
921 }
922
923
924 if (null == account.getHomeSpace())
925 {
926
927
928 Ivorn service = this.getDefaultVoSpace() ;
929 if (null != service)
930 {
931
932
933 try {
934
935
936 VoSpaceClient resolver = new VoSpaceClient(null) ;
937
938
939 Ivorn ivorn = resolver.createUser(
940 service,
941 new Ivorn(
942 account.getIdent()
943 )
944 ) ;
945 log.debug(" VoSpace ivorn : " + ivorn) ;
946
947
948 account.setHomeSpace(
949 ivorn.toString()
950 ) ;
951 }
952 catch (Throwable ouch)
953 {
954
955
956 logException(ouch, "AccountManagerImpl.allocateSpace()") ;
957
958
959 throw new CommunityServiceException(
960 "Unable to create VoSpace",
961 ouch
962 ) ;
963 }
964 }
965 }
966 }
967
968 /***
969 * The config property key for our default VoSpace ivorn.
970 *
971 */
972 private static final String DEFAULT_VOSPACE_PROPERTY = "org.astrogrid.community.default.vospace" ;
973
974 /***
975 * Get the default VoSpace ivorn.
976 * @return An Ivorn for the default VoSpace service.
977 * @throws CommunityServiceException If unable to get the VoSpace ivorn.
978 *
979 */
980 public Ivorn getDefaultVoSpace()
981 throws CommunityServiceException
982 {
983 log.debug("") ;
984 log.debug("----\"----") ;
985 log.debug("AccountManagerImpl.getDefaultVoSpace()") ;
986
987
988 String string = null ;
989 try {
990 string = (String) config.getProperty(DEFAULT_VOSPACE_PROPERTY,null) ;
991 }
992 catch (PropertyNotFoundException ouch)
993 {
994 throw new CommunityServiceException(
995 "Default VoSpace not configured"
996 ) ;
997 }
998 log.debug(" Default VoSpace : " + string) ;
999
1000
1001 if (null != string)
1002 {
1003
1004
1005 try {
1006 return new Ivorn(string) ;
1007 }
1008 catch (Exception ouch)
1009 {
1010 throw new CommunityServiceException(
1011 "Unable to convert default VoSpace into Ivorn",
1012 ouch
1013 ) ;
1014 }
1015 }
1016
1017
1018 else {
1019 throw new CommunityServiceException(
1020 "Default VoSpace not configured"
1021 ) ;
1022 }
1023 }
1024 }