1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.river.phoenix.group;
20
21 import java.io.IOException;
22 import java.io.ObjectStreamClass;
23 import java.io.ObjectStreamField;
24 import java.lang.reflect.Constructor;
25 import java.lang.reflect.InvocationTargetException;
26 import java.rmi.MarshalledObject;
27 import java.rmi.NoSuchObjectException;
28 import java.rmi.Remote;
29 import java.rmi.RemoteException;
30 import java.rmi.activation.Activatable;
31 import java.rmi.activation.ActivationDesc;
32 import java.rmi.activation.ActivationException;
33 import java.rmi.activation.ActivationGroupDesc;
34 import java.rmi.activation.ActivationGroupID;
35 import java.rmi.activation.ActivationID;
36 import java.rmi.activation.ActivationInstantiator;
37 import java.rmi.activation.ActivationMonitor;
38 import java.rmi.activation.ActivationSystem;
39 import java.rmi.activation.UnknownGroupException;
40 import java.rmi.activation.UnknownObjectException;
41 import java.rmi.server.ExportException;
42 import java.rmi.server.RemoteObject;
43 import java.rmi.server.UnicastRemoteObject;
44 import java.security.AccessController;
45 import java.security.Permission;
46 import java.security.PrivilegedAction;
47 import java.security.PrivilegedActionException;
48 import java.security.PrivilegedExceptionAction;
49 import java.util.ArrayList;
50 import java.util.HashMap;
51 import java.util.List;
52 import java.util.Map;
53 import javax.security.auth.Subject;
54 import javax.security.auth.login.LoginContext;
55 import javax.security.auth.login.LoginException;
56 import net.jini.activation.ActivationGroup;
57 import net.jini.config.Configuration;
58 import net.jini.config.ConfigurationException;
59 import net.jini.config.ConfigurationProvider;
60 import net.jini.export.Exporter;
61 import net.jini.export.ProxyAccessor;
62 import net.jini.io.MarshalledInstance;
63 import net.jini.jeri.AtomicILFactory;
64 import net.jini.jeri.BasicJeriExporter;
65 import net.jini.jeri.tcp.TcpServerEndpoint;
66 import net.jini.loader.ClassLoading;
67 import net.jini.security.BasicProxyPreparer;
68 import net.jini.security.ProxyPreparer;
69 import net.jini.security.Security;
70 import net.jini.security.TrustVerifier;
71 import net.jini.security.proxytrust.ServerProxyTrust;
72 import org.apache.river.api.io.AtomicSerial;
73 import org.apache.river.api.io.AtomicSerial.GetArg;
74 import org.apache.river.phoenix.common.AccessAtomicILFactory;
75 import org.apache.river.proxy.BasicProxyTrustVerifier;
76 import org.apache.river.thread.Executor;
77 import org.apache.river.thread.GetThreadPoolAction;
78 import org.apache.river.phoenix.dl.MonitorPermission;
79 import org.apache.river.phoenix.dl.InactiveGroupException;
80 import org.apache.river.phoenix.common.AccessILFactory;
81 import org.apache.river.phoenix.common.ActivationGroupData;
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217 abstract class AbstractActivationGroup extends ActivationGroup
218 implements ServerProxyTrust
219 {
220 private static final long serialVersionUID = 5758693559430427303L;
221
222 private static final String PHOENIX = "org.apache.river.phoenix";
223
224 private static final int UNUSED = 0;
225
226 private static final int CREATING = 1;
227
228 private static final int CREATED = 2;
229
230 private static final int ACTIVE = 3;
231
232 private static final int INACTIVE = 4;
233
234 private final static Class[] paramTypes = {
235 ActivationID.class, MarshalledObject.class
236 };
237
238
239 private static final ObjectStreamField[] serialPersistentFields =
240 ObjectStreamClass.NO_FIELDS;
241
242 private static int state = UNUSED;
243 private static long incarnation;
244
245 private static ActivationGroupID groupID;
246
247
248 private static LoginContext login;
249 private static Exporter exporter;
250
251 private static boolean refuseCalls = false;
252
253 private static ProxyPreparer monPreparer;
254 private static ActivationMonitor monitor;
255
256 private static long unexportTimeout;
257
258 private static long unexportWait;
259
260 private static Map active = new HashMap();
261
262 private static List lockedIDs = new ArrayList();
263
264 private static boolean inheritGroupSubject;
265
266
267 private final static Permission activeObjectPermission =
268 new MonitorPermission(
269 "java.rmi.activation.ActivationMonitor.activeObject");
270
271
272 private static Permission inactiveObjectPermission =
273 new MonitorPermission(
274 "java.rmi.activation.ActivationMonitor.inactiveObject");
275
276
277 private ActivationInstantiator proxy;
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316 public static synchronized
317 java.rmi.activation.ActivationGroup createGroup(
318 final ActivationGroupID id,
319 final ActivationGroupDesc desc,
320 final long incarnation)
321 throws ActivationException
322 {
323 if (state != UNUSED) {
324 throw new ActivationException("group previously created");
325 }
326 try {
327 final Configuration config = getConfiguration(desc.getData());
328 login = (LoginContext) config.getEntry(
329 PHOENIX, "loginContext", LoginContext.class, null);
330 if (login != null) {
331 login.login();
332 }
333
334 inheritGroupSubject =
335 config.getEntry(
336 PHOENIX, "inheritGroupSubject", boolean.class,
337 Boolean.FALSE);
338
339 return (java.rmi.activation.ActivationGroup) doAction(
340 new PrivilegedExceptionAction() {
341 public Object run() throws Exception {
342 ProxyPreparer sysPreparer =
343 getPreparer(config, "systemPreparer");
344 monPreparer = getPreparer(config,
345 "monitorPreparer");
346 TcpServerEndpoint se =
347 TcpServerEndpoint.getInstance(0);
348 Exporter defaultExporter =
349 new BasicJeriExporter(se, new AtomicILFactory(null, null, this.getClass().getClassLoader()));
350 exporter = (Exporter) config.getEntry(
351 PHOENIX, "instantiatorExporter",
352 Exporter.class, defaultExporter);
353 if (exporter == null) {
354 exporter = new AlreadyExportedExporter();
355 }
356 refuseCalls =
357 !(exporter instanceof AlreadyExportedExporter);
358 unexportTimeout = getInt(config, "unexportTimeout",
359 60000);
360 unexportWait = getInt(config, "unexportWait", 10);
361 ActivationSystem sys = (ActivationSystem)
362 sysPreparer.prepareProxy(id.getSystem());
363 AbstractActivationGroup.incarnation = incarnation;
364 groupID = id;
365 state = CREATING;
366 ActivationGroupID gid = (sys == id.getSystem() ?
367 id : new WrappedGID(id, sys));
368 Object group = ActivationGroup.createGroup(
369 gid, desc, incarnation);
370 state = ACTIVE;
371 return group;
372 }
373 });
374 } catch (ActivationException e) {
375 throw e;
376 } catch (Exception e) {
377 throw new ActivationException("creation failed", e);
378 } finally {
379 if (state != ACTIVE) {
380 checkInactiveGroup();
381 }
382 }
383 }
384
385
386
387
388
389 private static Configuration getConfiguration(MarshalledObject mobj)
390 throws ConfigurationException, IOException, ClassNotFoundException
391 {
392
393 ClassLoader ccl = Thread.currentThread().getContextClassLoader();
394 ClassLoader cl = AbstractActivationGroup.class.getClassLoader();
395 Thread.currentThread().setContextClassLoader(cl);
396 ActivationGroupData data = (ActivationGroupData) new MarshalledInstance(mobj).get(false);
397 Thread.currentThread().setContextClassLoader(ccl);
398 if (!covers(cl, ccl)) {
399 cl = ccl;
400 }
401 return ConfigurationProvider.getInstance(data.getConfig(), cl);
402 }
403
404
405
406
407
408
409 private static boolean covers(ClassLoader sub, ClassLoader sup) {
410 if (sup == null) {
411 return true;
412 } else if (sub == null) {
413 return false;
414 }
415 do {
416 if (sub == sup) {
417 return true;
418 }
419 sub = sub.getParent();
420 } while (sub != null);
421 return false;
422 }
423
424
425
426
427 private static ProxyPreparer getPreparer(Configuration config, String name)
428 throws ConfigurationException
429 {
430 return (ProxyPreparer) config.getEntry(PHOENIX, name,
431 ProxyPreparer.class,
432 new BasicProxyPreparer());
433 }
434
435
436
437
438 private static int getInt(Configuration config, String name, int defValue)
439 throws ConfigurationException
440 {
441 return ((Integer) config.getEntry(PHOENIX, name, int.class,
442 Integer.valueOf(defValue))).intValue();
443 }
444 private final ActivationGroupID id;
445
446
447
448
449
450
451 @AtomicSerial
452 private static class WrappedGID extends ActivationGroupID {
453
454 private final ActivationGroupID id;
455
456 private final ActivationSystem sys;
457
458 WrappedGID(ActivationGroupID id, ActivationSystem sys) {
459 super(sys);
460 this.id = id;
461 this.sys = sys;
462 }
463
464 public WrappedGID(GetArg arg) throws IOException {
465 this(arg.get("id", null, ActivationGroupID.class),
466 arg.get("sys", null, ActivationSystem.class));
467 }
468
469
470 public ActivationSystem getSystem() {
471 return sys;
472 }
473
474 private Object writeReplace() {
475 return id;
476 }
477 }
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508 AbstractActivationGroup(ActivationGroupID id, MarshalledObject data)
509 throws ActivationException, RemoteException
510 {
511 super(id);
512 this.id = id;
513 synchronized (AbstractActivationGroup.class) {
514 if (state != CREATING) {
515 throw new ActivationException("not called from createGroup");
516 }
517 }
518
519 }
520
521 void export() throws NoSuchObjectException, ExportException,
522 RemoteException, UnknownGroupException, ActivationException
523 {
524 synchronized (AbstractActivationGroup.class) {
525 if (state != CREATING) {
526 throw new ActivationException("not called from createGroup");
527 }
528 if (refuseCalls) {
529 unexportObject(this, true);
530 refuseCalls = false;
531 }
532 proxy = (ActivationInstantiator) exporter.export(this);
533 try {
534 monitor = (ActivationMonitor) monPreparer.prepareProxy(
535 id.getSystem().activeGroup(id, proxy, incarnation));
536 state = CREATED;
537 } finally {
538 if (state != CREATED) {
539 exporter.unexport(true);
540 }
541 }
542 monPreparer = null;
543 }
544 }
545
546 public TrustVerifier getProxyVerifier() {
547 synchronized (AbstractActivationGroup.class){
548 return new BasicProxyTrustVerifier(proxy);
549 }
550 }
551
552
553
554
555 private static class AlreadyExportedExporter implements Exporter {
556
557
558
559
560 private Remote impl;
561
562 AlreadyExportedExporter() {
563 }
564
565 public synchronized Remote export(Remote impl) throws ExportException {
566 this.impl = impl;
567 try {
568 return RemoteObject.toStub(impl);
569 } catch (NoSuchObjectException e) {
570 throw new ExportException("no stub found", e);
571 }
572 }
573
574 public synchronized boolean unexport(boolean force) {
575 try {
576 if (impl != null &&
577 !UnicastRemoteObject.unexportObject(impl, force))
578 {
579 return false;
580 }
581 } catch (NoSuchObjectException e) {
582 }
583 impl = null;
584 return true;
585 }
586 }
587
588
589
590
591
592
593
594
595 protected Object writeReplace() {
596 synchronized (AbstractActivationGroup.class){
597 return proxy;
598 }
599 }
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617 private void acquireLock(ActivationID id) {
618 while (true) {
619 synchronized (id) {
620 synchronized (lockedIDs) {
621 int index = lockedIDs.indexOf(id);
622 if (index < 0) {
623 lockedIDs.add(id);
624 return;
625 }
626 ActivationID lockedID =
627 (ActivationID) lockedIDs.get(index);
628 if (lockedID != id) {
629
630 id = lockedID;
631 continue;
632 }
633 }
634 try {
635 id.wait();
636 } catch (InterruptedException ignore) {
637 }
638 }
639 }
640 }
641
642
643
644
645
646 private void releaseLock(ActivationID id) {
647 synchronized (lockedIDs) {
648 id = (ActivationID) lockedIDs.remove(lockedIDs.indexOf(id));
649 }
650 synchronized (id) {
651 id.notifyAll();
652 }
653 }
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717 public MarshalledObject newInstance(final ActivationID id,
718 final ActivationDesc desc)
719 throws ActivationException
720 {
721 synchronized (AbstractActivationGroup.class) {
722 if (refuseCalls) {
723 throw new SecurityException("call refused");
724 }
725 }
726
727 acquireLock(id);
728 try {
729 ActiveEntry entry;
730 synchronized (AbstractActivationGroup.class) {
731 if (state != ACTIVE) {
732 throw new InactiveGroupException("group not active");
733 }
734 entry = (ActiveEntry) active.get(id);
735 }
736 if (entry != null) {
737 return entry.mobj;
738 }
739
740 String className = desc.getClassName();
741 final Class cl = ClassLoading.loadClass(desc.getLocation(),
742 className, null, false, null);
743 final Thread t = Thread.currentThread();
744 final ClassLoader savedCcl = t.getContextClassLoader();
745 final ClassLoader ccl =
746 covers(cl.getClassLoader(), savedCcl) ?
747 cl.getClassLoader() : savedCcl;
748
749 Remote impl = null;
750
751
752
753
754
755
756 try {
757 PrivilegedExceptionAction action =
758 new PrivilegedExceptionAction() {
759 public Object run() throws InstantiationException,
760 NoSuchMethodException, IllegalAccessException,
761 InvocationTargetException, ActivationException
762 {
763 Object[] params = new Object[] {id, desc.getData()};
764 Constructor constructor =
765 cl.getDeclaredConstructor(paramTypes);
766 constructor.setAccessible(true);
767 try {
768
769
770
771
772
773
774 t.setContextClassLoader(ccl);
775 return constructor.newInstance(params);
776 } finally {
777 t.setContextClassLoader(savedCcl);
778 }
779 }
780 };
781
782
783
784
785
786
787
788 impl = (Remote) (inheritGroupSubject ?
789 Security.doPrivileged(action) :
790 AccessController.doPrivileged(action));
791
792 } catch (PrivilegedActionException pae) {
793 throw pae.getException();
794 }
795
796 entry = new ActiveEntry(impl);
797 synchronized (AbstractActivationGroup.class) {
798 active.put(id, entry);
799 }
800 return entry.mobj;
801 } catch (NoSuchMethodException e) {
802
803 throw new ActivationException(
804 "activation constructor not defined", e);
805 } catch (NoSuchMethodError e) {
806
807
808
809 throw new ActivationException(
810 "activation constructor not defined", e);
811 } catch (InvocationTargetException e) {
812 throw new ActivationException("exception constructing object",
813 e.getTargetException());
814 } catch (ActivationException e) {
815 throw e;
816 } catch (Exception e) {
817 throw new ActivationException("unable to activate object", e);
818 } finally {
819 releaseLock(id);
820 checkInactiveGroup();
821 }
822 }
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853 @Override
854 public boolean inactiveObject(final ActivationID id)
855 throws ActivationException, RemoteException
856 {
857 SecurityManager security = System.getSecurityManager();
858 if (security != null) {
859 security.checkPermission(inactiveObjectPermission);
860 }
861 acquireLock(id);
862 try {
863 ActiveEntry entry;
864 synchronized (AbstractActivationGroup.class) {
865 if (state != ACTIVE) {
866 throw new InactiveGroupException("group not active");
867 }
868 entry = (ActiveEntry) active.get(id);
869 }
870 if (entry == null) {
871
872 throw new UnknownObjectException("object not active");
873 }
874
875 try {
876 if (!Activatable.unexportObject(entry.impl, false)) {
877 return false;
878 }
879 } catch (NoSuchObjectException allowUnexportedObjects) {
880 }
881
882 try {
883 doAction(new PrivilegedExceptionAction() {
884 public Object run() throws Exception {
885 monitor.inactiveObject(id);
886 return null;
887 }
888 });
889 } catch (UnknownObjectException allowUnregisteredObjects) {
890 }
891
892 synchronized (AbstractActivationGroup.class) {
893 active.remove(id);
894 }
895 } finally {
896 releaseLock(id);
897 checkInactiveGroup();
898 }
899
900 return true;
901 }
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932 public boolean inactiveObject(final ActivationID id, Exporter exporter)
933 throws ActivationException, RemoteException
934 {
935 SecurityManager security = System.getSecurityManager();
936 if (security != null) {
937 security.checkPermission(inactiveObjectPermission);
938 }
939 acquireLock(id);
940 try {
941 ActiveEntry entry;
942 synchronized (AbstractActivationGroup.class) {
943 if (state != ACTIVE) {
944 throw new InactiveGroupException("group not active");
945 }
946 entry = (ActiveEntry) active.get(id);
947 }
948 if (entry == null) {
949
950 throw new UnknownObjectException("object not active");
951 }
952
953 if (!exporter.unexport(false)) {
954 return false;
955 }
956
957 try {
958 doAction(new PrivilegedExceptionAction() {
959 public Object run() throws Exception {
960 monitor.inactiveObject(id);
961 return null;
962 }
963 });
964 } catch (UnknownObjectException allowUnregisteredObjects) {
965 }
966
967 synchronized (AbstractActivationGroup.class) {
968 active.remove(id);
969 }
970 } finally {
971 releaseLock(id);
972 checkInactiveGroup();
973 }
974
975 return true;
976 }
977
978
979
980
981
982 private static void checkInactiveGroup() {
983 synchronized (AbstractActivationGroup.class) {
984 if (state == ACTIVE) {
985 if (!active.isEmpty() || !lockedIDs.isEmpty()) {
986 return;
987 }
988 state = INACTIVE;
989 } else if (state == INACTIVE) {
990 return;
991 } else if (state == CREATED) {
992 state = UNUSED;
993 } else {
994 if (login != null) {
995 try {
996 login.logout();
997 } catch (LoginException e) {
998 }
999 login = null;
1000 }
1001 state = UNUSED;
1002 return;
1003 }
1004 }
1005 try {
1006 doAction(new PrivilegedExceptionAction() {
1007 public Object run() throws Exception {
1008 monitor.inactiveGroup(groupID, incarnation);
1009 return null;
1010 }
1011 });
1012 } catch (Exception ignoreDeactivateFailure) {
1013 }
1014 Runnable action = new Runnable() {
1015 public void run() {
1016 long stop = System.currentTimeMillis() + unexportTimeout;
1017
1018 boolean force = false;
1019 while (!exporter.unexport(force)) {
1020 long rem = stop - System.currentTimeMillis();
1021 if (rem <= 0) {
1022 force = true;
1023 } else {
1024 try {
1025 Thread.sleep(Math.min(rem, unexportWait));
1026 } catch (InterruptedException e) {
1027 }
1028 }
1029 }
1030 if (login != null) {
1031 try {
1032 login.logout();
1033 } catch (LoginException e) {
1034 }
1035 }
1036 }
1037 };
1038 if (state == UNUSED) {
1039 action.run();
1040 } else {
1041 Executor systemThreadPool =
1042 (Executor) AccessController.doPrivileged(
1043 (login == null) ?
1044 (PrivilegedAction) new GetThreadPoolAction(false) :
1045 new PrivilegedAction() {
1046 public Object run() {
1047 return Subject.doAsPrivileged(
1048 login.getSubject(),
1049 new GetThreadPoolAction(false),
1050 null);
1051 }
1052 });
1053 systemThreadPool.execute(action, "UnexportGroup");
1054 }
1055 }
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078 @Override
1079 public void activeObject(final ActivationID id, Remote impl)
1080 throws ActivationException
1081 {
1082 SecurityManager security = System.getSecurityManager();
1083 if (security != null) {
1084 security.checkPermission(activeObjectPermission);
1085 }
1086 final ActiveEntry entry = new ActiveEntry(impl);
1087 acquireLock(id);
1088 try {
1089 synchronized (AbstractActivationGroup.class) {
1090 if (state != ACTIVE) {
1091 throw new InactiveGroupException("group not active");
1092 }
1093 if (active.containsKey(id)) {
1094 return;
1095 }
1096 active.put(id, entry);
1097 }
1098
1099 try {
1100 doAction(new PrivilegedExceptionAction<Object>() {
1101 @Override
1102 public Object run() throws Exception {
1103 monitor.activeObject(id, entry.mobj);
1104 return null;
1105 }
1106 });
1107 } catch (RemoteException ignore) {
1108
1109 }
1110 } finally {
1111 releaseLock(id);
1112 checkInactiveGroup();
1113 }
1114 }
1115
1116
1117
1118
1119
1120 private static Object doAction(final PrivilegedExceptionAction action)
1121 throws ActivationException, RemoteException
1122 {
1123 try {
1124 if (login == null) {
1125 return AccessController.doPrivileged(action);
1126 } else {
1127 return AccessController.doPrivileged(
1128 new PrivilegedExceptionAction<Object>() {
1129 @Override
1130 public Object run() throws Exception {
1131 try {
1132 return Subject.doAsPrivileged(
1133 login.getSubject(), action, null);
1134 } catch (PrivilegedActionException e) {
1135 throw e.getException();
1136 }
1137 }
1138 });
1139 }
1140 } catch (PrivilegedActionException e) {
1141 Exception ex = e.getException();
1142 if (ex instanceof RemoteException) {
1143 throw (RemoteException) ex;
1144 } else if (ex instanceof ActivationException) {
1145 throw (ActivationException) ex;
1146 } else {
1147 throw new ActivationException("unexpected failure", ex);
1148 }
1149 }
1150 }
1151
1152
1153
1154
1155 private static class ActiveEntry {
1156 final Remote impl;
1157 final MarshalledObject mobj;
1158
1159 ActiveEntry(Remote impl) throws ActivationException {
1160 this.impl = impl;
1161 try {
1162 Object proxy ;
1163 if (impl instanceof ProxyAccessor) {
1164 proxy = ((ProxyAccessor) impl).getProxy();
1165 if (proxy == null) {
1166 throw new ActivationException(
1167 "ProxyAccessor.getProxy returned null");
1168 }
1169 } else {
1170 proxy = impl;
1171 }
1172 this.mobj =
1173 new MarshalledInstance(proxy).convertToMarshalledObject();
1174 } catch (IOException e) {
1175 throw new ActivationException(
1176 "failed to marshal remote object", e);
1177 }
1178 }
1179 }
1180 }