1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.river.norm;
19
20 import java.io.IOException;
21 import java.io.InputStream;
22 import java.io.InterruptedIOException;
23 import java.io.ObjectInputStream;
24 import java.io.ObjectOutputStream;
25 import java.io.OutputStream;
26 import java.rmi.MarshalledObject;
27 import java.rmi.NoSuchObjectException;
28 import java.rmi.RemoteException;
29 import java.security.PrivilegedActionException;
30 import java.security.PrivilegedExceptionAction;
31 import java.util.Collection;
32 import java.util.Collections;
33 import java.util.HashMap;
34 import java.util.Iterator;
35 import java.util.List;
36 import java.util.Map;
37 import java.util.Set;
38 import java.util.logging.Level;
39 import java.util.logging.LogRecord;
40 import java.util.logging.Logger;
41
42 import javax.security.auth.Subject;
43 import javax.security.auth.login.LoginContext;
44
45 import net.jini.config.Configuration;
46 import net.jini.config.ConfigurationProvider;
47 import net.jini.core.constraint.RemoteMethodControl;
48 import net.jini.core.discovery.LookupLocator;
49 import net.jini.core.entry.Entry;
50 import net.jini.core.event.EventRegistration;
51 import net.jini.core.event.RemoteEvent;
52 import net.jini.core.event.RemoteEventListener;
53 import net.jini.core.lease.Lease;
54 import net.jini.core.lease.LeaseDeniedException;
55 import net.jini.core.lease.UnknownLeaseException;
56 import net.jini.core.lookup.ServiceID;
57 import net.jini.export.Exporter;
58 import net.jini.export.ProxyAccessor;
59 import net.jini.id.ReferentUuid;
60 import net.jini.id.Uuid;
61 import net.jini.id.UuidFactory;
62 import net.jini.lease.LeaseRenewalEvent;
63 import net.jini.lease.LeaseRenewalManager;
64 import net.jini.lease.LeaseRenewalService;
65 import net.jini.lease.LeaseRenewalSet;
66 import net.jini.lookup.entry.ServiceInfo;
67 import net.jini.security.ProxyPreparer;
68 import net.jini.security.TrustVerifier;
69 import net.jini.security.proxytrust.ServerProxyTrust;
70 import net.jini.security.proxytrust.TrustEquivalence;
71
72 import org.apache.river.constants.ThrowableConstants;
73 import org.apache.river.constants.VersionConstants;
74 import org.apache.river.landlord.Landlord.RenewResults;
75 import org.apache.river.landlord.LandlordUtil;
76 import org.apache.river.landlord.LeaseFactory;
77 import org.apache.river.landlord.LeasePeriodPolicy;
78 import org.apache.river.landlord.LocalLandlord;
79 import org.apache.river.lookup.entry.BasicServiceType;
80 import org.apache.river.norm.event.EventType;
81 import org.apache.river.norm.event.EventTypeGenerator;
82 import org.apache.river.norm.event.SendMonitor;
83 import org.apache.river.norm.lookup.JoinState;
84 import org.apache.river.proxy.ThrowThis;
85 import org.apache.river.start.lifecycle.LifeCycle;
86 import org.apache.river.reliableLog.LogException;
87 import org.apache.river.reliableLog.LogHandler;
88 import org.apache.river.api.util.Startable;
89 import org.apache.river.thread.InterruptedStatusThread;
90 import org.apache.river.norm.proxy.*;
91 import java.security.AccessControlContext;
92 import java.security.AccessController;
93 import net.jini.export.CodebaseAccessor;
94 import net.jini.lookup.ServiceAttributesAccessor;
95 import net.jini.lookup.ServiceIDAccessor;
96 import net.jini.lookup.ServiceProxyAccessor;
97 import net.jini.loader.ClassLoading;
98 import org.apache.river.proxy.CodebaseProvider;
99
100
101
102
103
104
105
106 abstract class NormServerBaseImpl
107 implements NormServer, LocalLandlord, ServerProxyTrust, ProxyAccessor,
108 Startable, ServiceProxyAccessor, ServiceAttributesAccessor,
109 ServiceIDAccessor, CodebaseAccessor
110 {
111
112 private static final int CURRENT_LOG_VERSION = 2;
113
114
115 static final String NORM = "org.apache.river.norm";
116
117
118 static final Logger logger = Logger.getLogger(NORM);
119
120
121 final boolean persistent;
122
123
124 final LoginContext loginContext;
125
126
127 final String persistenceDirectory;
128
129
130 final private ProxyPreparer leasePreparer;
131
132
133
134
135
136 final private ProxyPreparer recoveredLeasePreparer;
137
138
139 final private ProxyPreparer listenerPreparer;
140
141
142
143
144
145 final private ProxyPreparer recoveredListenerPreparer;
146
147
148
149
150
151 final private ProxyPreparer locatorPreparer;
152
153
154
155
156
157 final private ProxyPreparer recoveredLocatorPreparer;
158
159
160 final Exporter exporter;
161
162
163 final private LifeCycle lifeCycle;
164
165
166 volatile private Uuid serverUuid;
167
168
169 volatile private JoinState joinState;
170
171
172 final private Map<Uuid,LeaseSet> setTable = Collections.synchronizedMap(new HashMap<Uuid,LeaseSet>());
173
174
175 final private LeaseRenewalManager lrm;
176
177
178 final private LeaseExpirationMgr expMgr;
179
180
181 volatile private LeaseFactory leaseFactory;
182
183
184 final private LeasePeriodPolicy setLeasePolicy;
185
186
187
188
189
190 final private boolean isolateSets;
191
192
193 volatile private PersistentStore store;
194
195
196 final private UIDGenerator idGen = new UIDGenerator() ;
197
198
199 final private List renewedList;
200
201
202
203
204
205 final private RenewLogThread renewLogger;
206
207
208 volatile private EventTypeGenerator generator;
209
210
211
212
213
214 final private LRMEventListener lrmEventListener;
215
216
217 final private int logToSnapshotThresh;
218
219
220 final private float snapshotWt;
221
222
223 volatile NormServer serverProxy = null;
224
225
226 volatile LeaseRenewalService normProxy = null;
227
228
229 volatile private AdminProxy adminProxy;
230
231
232 volatile private SnapshotThread snapshotter;
233
234
235 private final ReadyState ready = new ReadyState();
236
237
238 private final CountLeases countLeases = new CountLeases();
239
240
241
242 private final AccessControlContext context;
243 private Configuration config;
244
245 private boolean started;
246 private String certFactoryType;
247 private String certPathEncoding;
248 private byte[] encodedCerts;
249 private String codebase;
250
251
252
253
254
255 public void renewFor(Uuid id, Lease leaseToRenew,
256 long membershipDuration, long renewDuration)
257 throws RemoteException, ThrowThis
258 {
259 ready.check();
260
261
262 final LeaseSet set = getSet(id);
263
264 if (leaseToRenew == null) {
265 throw new NullPointerException("LeaseRenewalSet.renewFor:Must " +
266 "pass a non-null lease");
267 }
268
269 if ((membershipDuration != Lease.FOREVER) &&
270 (renewDuration == Lease.ANY))
271 {
272 throw new IllegalArgumentException(
273 "LeaseRenewalSet.renewFor:renewDuration can only be " +
274 "Lease.ANY if membershipDuration is Lease.FOREVER");
275 }
276
277 if (!(renewDuration == Lease.ANY || renewDuration == Lease.FOREVER ||
278 renewDuration > 0))
279 {
280 throw new IllegalArgumentException(
281 "LeaseRenewalSet.renewFor:renewDuration can only be " +
282 "Lease.ANY, Lease.FOREVER, or positive");
283 }
284
285 leaseToRenew = (Lease) leasePreparer.prepareProxy(leaseToRenew);
286
287
288 if (leaseToRenew instanceof ReferentUuid) {
289 Uuid cookie = ((ReferentUuid) leaseToRenew).getReferentUuid();
290 LeaseSet setForLease = (LeaseSet) setTable.get(cookie);
291 if (setForLease != null) {
292 synchronized (setForLease) {
293 if (isCurrent(setForLease)) {
294 throw new IllegalArgumentException(
295 "Cannot add leases granted by a " +
296 "LeaseRenewalService to a set created by " +
297 "that service");
298 }
299 }
300 }
301 }
302
303
304 if (logger.isLoggable(Level.FINE)) {
305 final Class lc = leaseToRenew.getClass();
306 logger.log(Level.FINE,
307 "Adding lease of class {0} with annotation {1}",
308 new Object[] {
309 leaseToRenew.getClass(),
310 ClassLoading.getClassAnnotation(lc) });
311 }
312
313
314 add(set, leaseToRenew, membershipDuration, renewDuration);
315 }
316
317 @Override
318 public ServiceID serviceID() throws IOException {
319 return new ServiceID(serverUuid.getMostSignificantBits(),
320 serverUuid.getLeastSignificantBits());
321 }
322
323 @Override
324 public Entry[] getServiceAttributes() throws IOException {
325 return getLookupAttributes();
326 }
327
328 @Override
329 public String getClassAnnotation() throws IOException {
330 return "".equals(codebase) ?
331 CodebaseProvider.getClassAnnotation(NormServer.class)
332 : codebase;
333 }
334
335 @Override
336 public String getCertFactoryType() throws IOException {
337 return certFactoryType;
338 }
339
340 @Override
341 public String getCertPathEncoding() throws IOException {
342 return certPathEncoding;
343 }
344
345 @Override
346 public byte[] getEncodedCerts() throws IOException {
347 return encodedCerts.clone();
348 }
349
350
351
352
353
354
355
356
357 private static final class ReadyState {
358 private static final int INITIALIZE = 0;
359 private static final int READY = 1;
360 private static final int SHUTDOWN = 2;
361 private int state = INITIALIZE;
362
363
364
365
366
367
368 synchronized void check() {
369 while (true) {
370 switch (state) {
371 case INITIALIZE:
372 try {
373 wait();
374 } catch (InterruptedException e) {
375 }
376 break;
377 case READY:
378 return;
379 default:
380 throw new IllegalStateException(
381 "Norm service is unavailable");
382 }
383 }
384 }
385
386
387
388
389
390 synchronized void ready() {
391 switch (state) {
392 case INITIALIZE:
393 state = READY;
394 notifyAll();
395 break;
396 case READY:
397 break;
398 default:
399 throw new IllegalStateException("Norm service is unavailable");
400 }
401 }
402
403
404
405
406
407 synchronized void shutdown() {
408 check();
409 state = SHUTDOWN;
410 notifyAll();
411 }
412 }
413
414
415 private static class CountLeases {
416 private int count;
417
418 private synchronized void updateCount(int change) {
419 count += change;
420 assert count >= 0;
421 }
422
423 private synchronized int getCount() {
424 return count;
425 }
426 }
427
428
429 void updateLeaseCount(int change) {
430 countLeases.updateCount(change);
431 }
432
433
434
435
436
437
438
439
440
441
442
443
444 private void add(LeaseSet set, Lease leaseToRenew,
445 long membershipDuration, long renewDuration)
446 throws ThrowThis
447 {
448 try {
449 store.acquireMutatorLock();
450 synchronized (set) {
451 ensureCurrent(set);
452
453
454 final long now = System.currentTimeMillis();
455 ClientLeaseWrapper clw =
456 set.getClientLeaseWrapper(leaseToRenew);
457 if (clw == null) {
458
459 try {
460 clw = new ClientLeaseWrapper(
461 leaseToRenew, idGen.newID(), renewedList, set,
462 membershipDuration, renewDuration, now);
463 } catch (IOException e) {
464 throw new IllegalArgumentException(
465 "NormServerBaseImpl.renewFor:Handed lease " +
466 "that can't be marshalled");
467 }
468 } else {
469
470 clw.update(membershipDuration, renewDuration, now);
471 }
472
473 set.update(clw);
474 lrm.renewUntil(clw, clw.getMembershipExpiration(),
475 clw.getRenewDuration(), lrmEventListener);
476
477
478
479
480
481
482
483 }
484 } finally {
485 store.releaseMutatorLock();
486 }
487 }
488
489
490
491 public Lease remove(Uuid id, Lease leaseToRemove)
492 throws RemoteException, ThrowThis
493 {
494 ready.check();
495 final LeaseSet set = getSet(id);
496
497 if (leaseToRemove == null) {
498 throw new NullPointerException("LeaseRenewalSet.remove:Must " +
499 "pass a non-null lease");
500 }
501
502 leaseToRemove = (Lease) leasePreparer.prepareProxy(leaseToRemove);
503 logger.log(Level.FINE, "Removing lease {0}", leaseToRemove);
504
505
506 Lease rslt = null;
507 try {
508 store.acquireMutatorLock();
509 synchronized (set) {
510 ensureCurrent(set);
511
512 final ClientLeaseWrapper clw
513 = set.getClientLeaseWrapper(leaseToRemove);
514
515 if (clw == null) {
516
517 return null;
518 }
519
520 try {
521 lrm.remove(clw);
522 } catch (UnknownLeaseException e) {
523 logger.log(Level.FINE,
524 "Exception thrown {0} while trying to remove lease {1}",
525 new Object[]{e, leaseToRemove}
526 );
527
528
529
530
531 }
532
533 final boolean present = set.remove(clw);
534
535
536
537 if (present) {
538
539
540 rslt = clw.getClientLease();
541 }
542 }
543 } finally {
544 store.releaseMutatorLock();
545 }
546
547 if (rslt == null)
548 return null;
549
550
551
552
553
554
555 rslt.setSerialFormat(Lease.DURATION);
556 return rslt;
557 }
558
559
560 public GetLeasesResult getLeases(Uuid id) throws ThrowThis {
561 ready.check();
562 final LeaseSet set = getSet(id);
563
564
565
566
567
568 synchronized (set) {
569 ensureCurrent(set);
570 return new GetLeasesResult(set.getLeases());
571 }
572 }
573
574
575
576 public EventRegistration setExpirationWarningListener(
577 Uuid id,
578 RemoteEventListener listener,
579 long minWarning,
580 MarshalledObject handback)
581 throws RemoteException, ThrowThis
582 {
583 ready.check();
584 final LeaseSet set = getSet(id);
585
586 if (listener == null) {
587 minWarning = NO_LISTENER;
588 handback = null;
589 } else if (minWarning < 0) {
590 throw new IllegalArgumentException(
591 "LeaseRenewalSet.setExpirationWarningListener:minWarning " +
592 "must be positive");
593 } else {
594 listener = (RemoteEventListener) listenerPreparer.prepareProxy(
595 listener);
596 }
597
598 try {
599 store.acquireMutatorLock();
600 synchronized (set) {
601 ensureCurrent(set);
602
603 try {
604 final boolean haveBefore = set.haveWarningRegistration();
605 final EventRegistration rslt =
606 set.setExpirationWarningListener(
607 listener, minWarning, handback);
608 final boolean haveAfter = set.haveWarningRegistration();
609
610 if (haveAfter || (haveBefore != haveAfter)) {
611
612
613
614
615
616
617
618
619 expMgr.reschedule(set);
620 }
621
622 return rslt;
623 } catch (IOException e) {
624
625
626 throw new IllegalArgumentException("Passed a listener " +
627 "that could not be serialized");
628 }
629 }
630 } finally {
631 store.releaseMutatorLock();
632 }
633 }
634
635
636
637
638 void expireIfTime(LeaseSet set) {
639 try {
640 store.acquireMutatorLock();
641
642 synchronized (set) {
643 if (isCurrent(set)) {
644
645 return;
646 }
647
648 removeSet(set);
649 }
650 } finally {
651 store.releaseMutatorLock();
652 }
653 }
654
655
656
657
658
659
660 void sendWarningEvent(LeaseSet set) {
661
662
663
664
665 synchronized (set) {
666 if (!isCurrent(set)) {
667
668 return;
669 }
670
671 set.sendWarningEvent();
672 }
673 }
674
675
676 public EventRegistration setRenewalFailureListener(
677 Uuid id,
678 RemoteEventListener listener,
679 MarshalledObject handback)
680 throws RemoteException, ThrowThis
681 {
682 ready.check();
683 final LeaseSet set = getSet(id);
684
685 if (listener == null) {
686 handback = null;
687 } else {
688 listener = (RemoteEventListener) listenerPreparer.prepareProxy(
689 listener);
690 }
691
692 try {
693 store.acquireMutatorLock();
694 synchronized (set) {
695 ensureCurrent(set);
696
697 try {
698 return set.setRenewalFailureListener(
699 listener, handback);
700 } catch (IOException e) {
701
702
703 throw new IllegalArgumentException("Passed a listener " +
704 "that could not be serialized");
705 }
706 }
707 } finally {
708 store.releaseMutatorLock();
709 }
710 }
711
712
713
714
715
716
717
718
719 void renewalFailure(ClientLeaseWrapper clw) {
720 final LeaseSet set = clw.getLeaseSet();
721 if (set == null) {
722
723
724 return;
725 }
726
727 try {
728 store.acquireMutatorLock();
729
730 synchronized (set) {
731 logger.log(Level.INFO, "Lease renewal failed for {0}", clw);
732
733 if (!isCurrent(set)) {
734
735
736 return;
737 }
738
739 set.renewalFailure(clw);
740
741
742
743
744
745
746
747 try {
748 lrm.remove(clw);
749 } catch (UnknownLeaseException e) {
750
751 }
752 }
753 } finally {
754 store.releaseMutatorLock();
755 }
756 }
757
758
759
760
761
762
763 void desiredExpirationReached(ClientLeaseWrapper clw) {
764 final LeaseSet set = clw.getLeaseSet();
765 if (set == null) {
766
767
768 return;
769 }
770
771 try {
772 store.acquireMutatorLock();
773
774 synchronized (set) {
775 if (!isCurrent(set)) {
776
777
778 return;
779 }
780
781
782
783 if (!set.doesContainWrapper(clw)) {
784
785
786 return;
787 }
788
789
790
791
792
793 final long desiredExpiration = clw.getMembershipExpiration();
794 if (desiredExpiration > System.currentTimeMillis()) {
795
796
797 lrm.renewUntil(clw, clw.getMembershipExpiration(),
798 clw.getRenewDuration(), lrmEventListener);
799 return;
800 }
801
802
803
804
805
806 if (clw.getExpiration() < desiredExpiration) {
807
808
809
810
811
812 return;
813 }
814
815
816 logger.log(Level.FINE,
817 "Reached desired expiration for lease {0}",
818 clw);
819
820 set.remove(clw);
821
822
823
824
825
826
827
828 try {
829 lrm.remove(clw);
830 } catch (UnknownLeaseException e) {
831
832 }
833 }
834 } finally {
835 store.releaseMutatorLock();
836 }
837 }
838
839
840
841
842
843 private class SendMonitorImpl implements SendMonitor {
844
845 final private LeaseSet set;
846
847
848
849
850
851 private SendMonitorImpl(LeaseSet set) {
852 this.set = set;
853 }
854
855
856
857
858 public void definiteException(EventType type,
859 RemoteEvent ev,
860 long registrationNumber,
861 Throwable t)
862 {
863
864
865
866
867
868 try {
869 store.acquireMutatorLock();
870
871 if (!NormServerBaseImpl.isCurrent(set)) {
872
873 return;
874 }
875
876 synchronized (set) {
877 set.definiteException(type, ev, registrationNumber);
878 }
879 } finally {
880 store.releaseMutatorLock();
881 }
882 }
883
884
885 public boolean isCurrent() {
886 synchronized (set) {
887 return NormServerBaseImpl.isCurrent(set);
888 }
889 }
890 }
891
892
893
894
895
896
897
898
899 private void removeClientLeases(Iterator deadLeases) {
900 while(deadLeases.hasNext()) {
901 ClientLeaseWrapper clw = (ClientLeaseWrapper) deadLeases.next();
902
903
904 try {
905 lrm.remove(clw);
906 } catch (UnknownLeaseException e) {
907
908
909
910 }
911 }
912 }
913
914
915
916
917
918 private static void ensureCurrent(LeaseSet set) throws ThrowThis {
919 if (!isCurrent(set)) {
920 throw new ThrowThis(new NoSuchObjectException("Set has expired"));
921 }
922 }
923
924
925
926
927
928 private static boolean isCurrent(LeaseSet set) {
929 return set.getExpiration() > System.currentTimeMillis();
930 }
931
932
933
934
935
936 private LeaseSet getSet(Uuid id) throws ThrowThis {
937 final LeaseSet rslt = (LeaseSet) setTable.get(id);
938 if (rslt == null)
939 throw new ThrowThis(new NoSuchObjectException("Can't find set"));
940 return rslt;
941 }
942
943
944
945
946
947
948 public LeaseRenewalSet createLeaseRenewalSet(long leaseDuration) {
949 ready.check();
950 final Uuid newID = UuidFactory.generate();
951 final LeaseSet newSet = new LeaseSet(newID, generator, store, this, context);
952
953 LeasePeriodPolicy.Result leasePeriod;
954 try {
955 leasePeriod = setLeasePolicy.grant(newSet, leaseDuration);
956 } catch (LeaseDeniedException e) {
957
958
959
960 logger.log(Level.WARNING,
961 "Got LeaseDeniedException creating lease -- " +
962 "this should not happen!",
963 e);
964 throw new InternalNormException("Error creating lease", e);
965 }
966
967 Lease newLease = leaseFactory.newLease(newID, leasePeriod.expiration);
968 newSet.setExpiration(leasePeriod.expiration);
969 try {
970 store.acquireMutatorLock();
971 final Object u = new CreateLeaseSet(newSet);
972 store.update(u);
973 expMgr.register(newSet);
974 setTable.put(newID, newSet);
975 } finally {
976 store.releaseMutatorLock();
977 }
978
979 LeaseRenewalSet result = SetProxy.create(serverProxy, newID, newLease);
980 logger.log(Level.FINE, "Created lease renewal set {0}", result);
981 return result;
982 }
983
984
985
986
987
988
989
990
991
992 SetProxy newSetProxy(LeaseSet set) {
993 Lease l = leaseFactory.newLease(set.getUuid(), set.getExpiration());
994 return SetProxy.create(serverProxy, set.getUuid(), l);
995 }
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007 SendMonitor newSendMonitor(LeaseSet set) {
1008 return new SendMonitorImpl(set);
1009 }
1010
1011
1012
1013
1014
1015
1016
1017
1018 public TrustVerifier getProxyVerifier() {
1019 return new ProxyVerifier(serverProxy, serverUuid);
1020 }
1021
1022
1023
1024 static class RenewLogThread extends InterruptedStatusThread {
1025 private PersistentStore store;
1026 private final List renewedList;
1027
1028 RenewLogThread(List renewedList) {
1029 super("log renewals thread");
1030 setDaemon(false);
1031 this.renewedList = renewedList;
1032
1033 }
1034
1035 private void setStore(PersistentStore store){
1036 synchronized (this){
1037 if (this.store == null) this.store = store;
1038 }
1039 }
1040
1041 public void run() {
1042 while (!hasBeenInterrupted()) {
1043 try {
1044 ClientLeaseWrapper clw;
1045 PersistentStore store;
1046 synchronized (this){
1047 store = this.store;
1048 }
1049 synchronized (renewedList) {
1050
1051
1052 if (renewedList.isEmpty()) {
1053 try {
1054 renewedList.wait();
1055 continue;
1056 } catch (InterruptedException e) {
1057
1058
1059 Thread.currentThread().interrupt();
1060 return;
1061 }
1062 } else {
1063 clw = (ClientLeaseWrapper) renewedList.remove(0);
1064 }
1065 }
1066
1067 if (logger.isLoggable(Level.FINER)) {
1068 logger.log(Level.FINER,
1069 "Attempting to renew lease {0} at {1}",
1070 new Object[] {
1071 clw,
1072 Long.valueOf(System.currentTimeMillis()) });
1073 }
1074
1075
1076 final LeaseSet set = clw.getLeaseSet();
1077 if (set == null) {
1078
1079
1080 continue;
1081 }
1082
1083 try {
1084 store.acquireMutatorLock();
1085 synchronized (set) {
1086 if (!isCurrent(set)) {
1087
1088
1089 continue;
1090 }
1091
1092 clw.clearRenewed();
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103 set.logRenewal(clw);
1104 }
1105 } finally {
1106 store.releaseMutatorLock();
1107 }
1108 try {
1109
1110 Thread.sleep(100L);
1111
1112 } catch (InterruptedException ex) {
1113
1114 Thread.currentThread().interrupt();
1115 }
1116 } catch (RuntimeException e) {
1117 logger.log(
1118 Level.INFO,
1119 "Runtime exception in RenewLogThread -- restarting",
1120 e);
1121 }
1122 }
1123 }
1124 }
1125
1126
1127
1128
1129
1130
1131 public long renew(Uuid cookie, long extension)
1132 throws UnknownLeaseException, LeaseDeniedException
1133 {
1134 ready.check();
1135 final LeaseSet set = (LeaseSet) setTable.get(cookie);
1136 if (set == null)
1137 throw new UnknownLeaseException("No lease for cookie:" + cookie);
1138 try {
1139 store.acquireMutatorLock();
1140
1141 synchronized (set) {
1142 if (!isCurrent(set)) {
1143
1144 throw new UnknownLeaseException(
1145 "Lease has already expired");
1146 }
1147
1148
1149
1150 LeasePeriodPolicy.Result leasePeriod =
1151 setLeasePolicy.renew(set, extension);
1152
1153
1154 final Object u = new LeaseSet.ChangeSetExpiration(
1155 set, leasePeriod.expiration);
1156 store.update(u);
1157
1158 set.setExpiration(leasePeriod.expiration);
1159 expMgr.reschedule(set);
1160 return leasePeriod.duration;
1161 }
1162 } finally {
1163 store.releaseMutatorLock();
1164 }
1165 }
1166
1167
1168 public void cancel(Uuid cookie) throws UnknownLeaseException {
1169 ready.check();
1170 final LeaseSet set = (LeaseSet) setTable.get(cookie);
1171 if (set == null)
1172 throw new UnknownLeaseException("No lease for cookie:" + cookie);
1173
1174 try {
1175 store.acquireMutatorLock();
1176
1177 synchronized (set) {
1178 if (!isCurrent(set)) {
1179
1180 return;
1181 }
1182
1183 removeSet(set);
1184 }
1185 } finally {
1186 store.releaseMutatorLock();
1187 }
1188 }
1189
1190
1191
1192
1193
1194 private void removeSet(LeaseSet set) {
1195
1196 if (setTable.remove(set.getUuid()) != null) {
1197
1198
1199
1200
1201
1202 final Set leases = set.destroy();
1203 removeClientLeases(leases.iterator());
1204 }
1205 }
1206
1207
1208 public RenewResults renewAll(Uuid[] cookies, long[] extensions) {
1209 ready.check();
1210
1211 return LandlordUtil.renewAll(this, cookies, extensions);
1212 }
1213
1214
1215 public Map cancelAll(Uuid[] cookies) {
1216 ready.check();
1217
1218 return LandlordUtil.cancelAll(this, cookies);
1219 }
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229 void updatePerformed(int updateCount) {
1230
1231
1232
1233
1234 if (updateCount >= logToSnapshotThresh) {
1235
1236 final int snapshotSize = setTable.size() + countLeases.getCount();
1237 if ((float) updateCount >= snapshotWt*((float) snapshotSize)) {
1238
1239 snapshotter.takeSnapshot();
1240 }
1241 }
1242 }
1243
1244
1245
1246
1247
1248
1249 void restoreTransientState() {
1250 final long now = System.currentTimeMillis();
1251
1252 for (Iterator i = setTable.values().iterator(); i.hasNext(); ) {
1253
1254 final LeaseSet set = (LeaseSet) i.next();
1255
1256
1257 if (now > set.getExpiration()) {
1258
1259 i.remove();
1260
1261
1262 continue;
1263 }
1264
1265 final Iterator leases = set.restoreTransientState(generator, store, this, recoveredListenerPreparer, context);
1266
1267
1268
1269 while (leases.hasNext()) {
1270
1271
1272
1273 ClientLeaseWrapper clw;
1274 synchronized (this) {
1275 clw = (ClientLeaseWrapper) leases.next();
1276
1277
1278 clw.recoverTransient(
1279 renewedList, idGen, set, recoveredLeasePreparer);
1280 }
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299 final Throwable lt = clw.getLastFailure();
1300
1301 if ((lt == null) ||
1302 (ThrowableConstants.retryable(lt) ==
1303 ThrowableConstants.INDEFINITE))
1304 {
1305 lrm.renewUntil(clw, clw.getMembershipExpiration(),
1306 clw.getRenewDuration(), lrmEventListener);
1307 } else {
1308
1309
1310
1311
1312 lrmEventListener.notify(new LeaseRenewalEvent(lrm,
1313 clw, clw.getMembershipExpiration(), lt));
1314 }
1315 }
1316 }
1317 }
1318
1319
1320
1321
1322 private class OurLogHandler extends LogHandler {
1323
1324
1325
1326
1327
1328
1329
1330 public void snapshot(OutputStream out) throws Exception {
1331 final ObjectOutputStream oostream = new ObjectOutputStream(out);
1332
1333 oostream.writeInt(CURRENT_LOG_VERSION);
1334 oostream.writeObject(serverUuid);
1335 oostream.writeObject(generator);
1336 oostream.writeInt(setTable.size());
1337 final Collection sets = setTable.values();
1338 for (Iterator i = sets.iterator(); i.hasNext();) {
1339 final LeaseSet set = (LeaseSet) i.next();
1340
1341
1342
1343 synchronized (set) {
1344
1345
1346
1347
1348 oostream.writeObject(set);
1349 }
1350 }
1351 oostream.flush();
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362 }
1363
1364
1365 public void recover(InputStream in) throws Exception {
1366 final ObjectInputStream oistream = new ObjectInputStream(in);
1367
1368 int version;
1369 version = oistream.readInt();
1370
1371 if (version != CURRENT_LOG_VERSION) {
1372 throw new CorruptedStoreException("Incompatible version " +
1373 "ID in log, looking for " + CURRENT_LOG_VERSION +
1374 ", got " + version);
1375
1376 }
1377
1378 serverUuid = (Uuid) oistream.readObject();
1379 generator = (EventTypeGenerator) oistream.readObject();
1380 final int size = oistream.readInt();
1381 setTable.clear();
1382 for (int i = 0; i < size; i++) {
1383 final LeaseSet set = (LeaseSet) oistream.readObject();
1384 setTable.put(set.getUuid(), set);
1385 }
1386 }
1387
1388
1389 public void applyUpdate(Object update) throws Exception {
1390 final LoggedOperation op = (LoggedOperation) update;
1391 op.apply(setTable);
1392 }
1393 }
1394
1395
1396
1397
1398 private String inventory() {
1399 return countLeases.getCount() + " client leases, " +
1400 setTable.size() + " sets.";
1401 }
1402
1403
1404
1405
1406
1407 class SnapshotThread extends InterruptedStatusThread {
1408 private final PersistentStore store;
1409
1410 SnapshotThread(PersistentStore store) {
1411 super("snapshot thread");
1412 setDaemon(false);
1413 this.store = store;
1414 }
1415
1416
1417 private synchronized void takeSnapshot() {
1418 notifyAll();
1419 }
1420
1421 public void run() {
1422 while (!hasBeenInterrupted()) {
1423 synchronized (this) {
1424 try {
1425 wait();
1426 } catch (InterruptedException e) {
1427 return;
1428 }
1429 }
1430
1431 try {
1432 if (logger.isLoggable(Level.FINER)) {
1433 logger.log(
1434 Level.FINER, "Taking snapshot: {0}", inventory());
1435 }
1436
1437 store.snapshot();
1438
1439 } catch (InterruptedIOException e) {
1440
1441 return;
1442 } catch (Exception e) {
1443 if (e instanceof LogException &&
1444 ((LogException) e).detail instanceof
1445 InterruptedIOException)
1446 {
1447 return;
1448 }
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458 logger.log(Level.WARNING, "Snapshot failed", e);
1459 }
1460 }
1461 }
1462 }
1463
1464
1465
1466
1467
1468 public Object getAdmin() {
1469 ready.check();
1470 return adminProxy;
1471 }
1472
1473
1474
1475
1476
1477 public Entry[] getLookupAttributes() {
1478 ready.check();
1479 return joinState.getAttributes();
1480 }
1481
1482
1483 public void addLookupAttributes(Entry[] attrSets) {
1484 ready.check();
1485 joinState.addAttributes(attrSets, true);
1486 logger.log(Level.CONFIG, "Added attributes");
1487 }
1488
1489
1490 public void modifyLookupAttributes(Entry[] attrSetTemplates,
1491 Entry[] attrSets)
1492 {
1493 ready.check();
1494 joinState.modifyAttributes(attrSetTemplates, attrSets, true);
1495 logger.log(Level.CONFIG, "Modified attributes");
1496 }
1497
1498
1499 public String[] getLookupGroups() {
1500 ready.check();
1501 return joinState.getGroups();
1502 }
1503
1504
1505 public void addLookupGroups(String[] groups) {
1506 ready.check();
1507 joinState.addGroups(groups);
1508 if (logger.isLoggable(Level.CONFIG)) {
1509 logger.log(Level.CONFIG, "Added lookup groups: {0}",
1510 toString(groups));
1511 }
1512 }
1513
1514
1515 public void removeLookupGroups(String[] groups) {
1516 ready.check();
1517 joinState.removeGroups(groups);
1518 if (logger.isLoggable(Level.CONFIG)) {
1519 logger.log(Level.CONFIG, "Removed lookup groups: {0}",
1520 toString(groups));
1521 }
1522 }
1523
1524
1525 public void setLookupGroups(String[] groups) {
1526 ready.check();
1527 joinState.setGroups(groups);
1528 if (logger.isLoggable(Level.CONFIG)) {
1529 logger.log(Level.CONFIG, "Set lookup groups: {0}",
1530 toString(groups));
1531 }
1532 }
1533
1534
1535 public LookupLocator[] getLookupLocators() {
1536 ready.check();
1537 return joinState.getLocators();
1538 }
1539
1540
1541 public void addLookupLocators(LookupLocator[] locators)
1542 throws RemoteException
1543 {
1544 ready.check();
1545 for (int i = locators.length; --i >= 0; ) {
1546 locators[i] = (LookupLocator) locatorPreparer.prepareProxy(
1547 locators[i]);
1548 }
1549 joinState.addLocators(locators);
1550 if (logger.isLoggable(Level.CONFIG)) {
1551 logger.log(Level.CONFIG, "Added lookup locators: {0}",
1552 toString(locators));
1553 }
1554 }
1555
1556
1557 public void removeLookupLocators(LookupLocator[] locators)
1558 throws RemoteException
1559 {
1560 ready.check();
1561 for (int i = locators.length; --i >= 0; ) {
1562 locators[i] = (LookupLocator) locatorPreparer.prepareProxy(
1563 locators[i]);
1564 }
1565 joinState.removeLocators(locators);
1566 if (logger.isLoggable(Level.CONFIG)) {
1567 logger.log(Level.CONFIG, "Removed lookup locators: {0}",
1568 toString(locators));
1569 }
1570 }
1571
1572
1573 public void setLookupLocators(LookupLocator[] locators)
1574 throws RemoteException
1575 {
1576 ready.check();
1577 for (int i = locators.length; --i >= 0; ) {
1578 locators[i] = (LookupLocator) locatorPreparer.prepareProxy(
1579 locators[i]);
1580 }
1581 joinState.setLocators(locators);
1582 if (logger.isLoggable(Level.CONFIG)) {
1583 logger.log(Level.CONFIG, "Set lookup locators: {0}",
1584 toString(locators));
1585 }
1586 }
1587
1588
1589 private static String toString(Object[] array) {
1590 if (array == null) {
1591 return "null";
1592 }
1593 StringBuffer sb = new StringBuffer(String.valueOf(array[0]));
1594 for (int i = 1; i < array.length; i++) {
1595 sb.append(", ").append(array[i]);
1596 }
1597 return sb.toString();
1598 }
1599
1600
1601
1602
1603
1604 public void destroy() throws RemoteException {
1605 ready.shutdown();
1606 logger.log(Level.INFO, "Destroying Norm service");
1607
1608 joinState.terminateJoin();
1609 lrmEventListener.interrupt();
1610 renewLogger.interrupt();
1611 snapshotter.interrupt();
1612 expMgr.terminate();
1613 generator.terminate();
1614 lrm.clear();
1615 lrm.close();
1616
1617 logger.log(Level.FINEST, "Independent threads interrupted");
1618
1619 new DestroyThread().start();
1620 logger.log(Level.FINEST, "Destroy thread started");
1621 }
1622
1623
1624
1625
1626
1627
1628 boolean unexport(boolean force) throws NoSuchObjectException {
1629 return exporter.unexport(force);
1630 }
1631
1632
1633
1634
1635
1636 void postDestroy() {
1637 }
1638
1639
1640
1641
1642
1643
1644 private class DestroyThread extends Thread {
1645
1646 private static final long MAX_DELAY = 2 * 60 * 1000;
1647
1648
1649 private DestroyThread() {
1650 super("DestroyThread");
1651
1652 setDaemon(false);
1653 }
1654
1655 public void run() {
1656 logger.log(Level.FINEST, "DestroyThread running");
1657
1658
1659
1660
1661
1662 final long end_time = System.currentTimeMillis() + MAX_DELAY;
1663 boolean unexported = false;
1664
1665 try {
1666 while ((!unexported) &&
1667 (System.currentTimeMillis() < end_time))
1668 {
1669
1670 logger.log(Level.FINEST,
1671 "Calling unexport (force=false)...");
1672
1673 unexported = unexport(false);
1674
1675 logger.log(Level.FINEST, "...rslt = " + unexported);
1676
1677 if (!unexported) {
1678
1679 try {
1680 Thread.sleep(100L);
1681 } catch (InterruptedException e){
1682
1683 Thread.currentThread().interrupt();
1684 }
1685 }
1686 }
1687 } catch (NoSuchObjectException e) {
1688 logger.log(Level.FINEST, "...rslt = NoSuchObjectException");
1689
1690 unexported = true;
1691 } catch (Throwable t) {
1692 logger.log(Level.FINEST, "...rslt = ", t);
1693 }
1694
1695 if (!unexported) {
1696
1697 try {
1698 logger.log(Level.FINEST, "Calling unexport (force=true)");
1699
1700 unexport(true);
1701 } catch (NoSuchObjectException e) {
1702
1703 }
1704 }
1705
1706
1707 try {
1708 logger.log(Level.FINEST, "Joining independent threads");
1709
1710 lrmEventListener.join(MAX_DELAY);
1711 renewLogger.join(MAX_DELAY);
1712 snapshotter.join(MAX_DELAY);
1713 } catch (InterruptedException e) {
1714
1715 }
1716
1717 try {
1718 logger.log(Level.FINEST, "Destroying store");
1719
1720 store.destroy();
1721 } catch (Exception t) {
1722 logger.log(Level.INFO,
1723 "While destroying persistent store -- " +
1724 "destroy continuing",
1725 t);
1726 }
1727
1728 if (lifeCycle != null) {
1729
1730 lifeCycle.unregister(this);
1731 }
1732
1733 logger.log(Level.FINEST, "Calling postDestroy");
1734
1735 postDestroy();
1736
1737 if (loginContext != null) {
1738 try {
1739 logger.log(Level.FINEST, "Logging out");
1740 loginContext.logout();
1741 } catch (Exception e) {
1742 logger.log(
1743 Level.INFO, "Exception while logging out", e);
1744 }
1745 }
1746
1747 logger.log(Level.FINEST, "Ending DestroyThread");
1748 }
1749 }
1750
1751
1752
1753
1754 public Object getServiceProxy() {
1755 ready.check();
1756 return normProxy;
1757 }
1758
1759
1760
1761
1762 public Object getProxy() {
1763
1764 return serverProxy;
1765 }
1766
1767
1768
1769
1770
1771 public String toString() {
1772 String className = getClass().getName();
1773 className = className.substring(className.lastIndexOf('.') + 1);
1774 return className + "[" + serverUuid + "]";
1775 }
1776
1777
1778
1779
1780
1781 static class InitException extends Exception {
1782 private static final long serialVersionUID = 1;
1783 private InitException(String message, Throwable nested) {
1784 super(message, nested);
1785 }
1786 }
1787
1788
1789
1790
1791
1792
1793 static NormServerInitializer init(String[] configOptions, final NormServerInitializer init)
1794 throws Exception
1795 {
1796 try {
1797 final Configuration config = ConfigurationProvider.getInstance(
1798 configOptions, NormServerBaseImpl.class.getClassLoader());
1799 init.loginContext = (LoginContext) config.getEntry(
1800 NORM, "loginContext", LoginContext.class, null);
1801 if (init.loginContext == null) {
1802 init.initAsSubject(config);
1803 } else {
1804 init.loginContext.login();
1805 try {
1806 Subject.doAsPrivileged(
1807 init.loginContext.getSubject(),
1808 new PrivilegedExceptionAction() {
1809 public Object run() throws Exception {
1810 init.initAsSubject(config);
1811 return null;
1812 }
1813 },
1814 null);
1815 } catch (PrivilegedActionException e) {
1816 throw e.getCause();
1817 }
1818 }
1819 } catch (Throwable e) {
1820 initFailed(e);
1821 }
1822 return init;
1823 }
1824
1825
1826
1827
1828
1829
1830
1831 static void initFailed(Throwable e) throws Exception {
1832 String message = null;
1833 if (e instanceof InitException) {
1834 message = e.getMessage();
1835 e = e.getCause();
1836 }
1837 if (logger.isLoggable(Level.SEVERE)) {
1838 if (message != null) {
1839 logThrow(Level.SEVERE, "initFailed",
1840 "Unable to start Norm service: {0}",
1841 new Object[] { message }, e);
1842 } else {
1843 logger.log(Level.SEVERE, "Unable to start Norm service", e);
1844 }
1845 }
1846 if (e instanceof Exception) {
1847 throw (Exception) e;
1848 } else if (e instanceof Error) {
1849 throw (Error) e;
1850 } else {
1851 throw new IllegalStateException(e);
1852 }
1853 }
1854
1855
1856 private static void logThrow(Level level, String method,
1857 String msg, Object[] msgParams, Throwable t)
1858 {
1859 LogRecord r = new LogRecord(level, msg);
1860 r.setLoggerName(logger.getName());
1861 r.setSourceClassName(NormServerBaseImpl.class.getName());
1862 r.setSourceMethodName(method);
1863 r.setParameters(msgParams);
1864 r.setThrown(t);
1865 logger.log(r);
1866 }
1867
1868 public void start() throws Exception {
1869 synchronized (this){
1870 if (started) return;
1871 started = true;
1872 }
1873 try {
1874 AccessController.doPrivileged(new PrivilegedExceptionAction(){
1875
1876 @Override
1877 public Object run() throws Exception {
1878 serverProxy = (NormServer) exporter.export(NormServerBaseImpl.this);
1879
1880 boolean done = false;
1881 try {
1882
1883 expMgr.setServer(NormServerBaseImpl.this);
1884 lrmEventListener.setServer(NormServerBaseImpl.this);
1885
1886 try {
1887 store = new PersistentStore(
1888 persistenceDirectory, new OurLogHandler(), NormServerBaseImpl.this);
1889
1890
1891
1892 restoreTransientState();
1893 if (logger.isLoggable(Level.FINER)) {
1894 logger.log(Level.FINER, "Log recovered: {0}",
1895 inventory());
1896 }
1897
1898 } catch (CorruptedStoreException e) {
1899 throw new InitException("Log corrupted, can't recover ", e);
1900 } catch (StoreException e) {
1901 throw new InitException("Can't recover log", e);
1902 }
1903
1904 renewLogger.setStore(store);
1905 snapshotter = new SnapshotThread(store);
1906
1907 if (serverUuid == null) {
1908 serverUuid = UuidFactory.generate();
1909 }
1910 normProxy = NormProxy.create(serverProxy, serverUuid);
1911 adminProxy = AdminProxy.create(serverProxy, serverUuid);
1912
1913
1914 try {
1915 store.snapshot();
1916 if (logger.isLoggable(Level.FINER)) {
1917 logger.log(
1918 Level.FINER, "Completed new baseline snapshot: {0}",
1919 inventory());
1920 }
1921 } catch (IOException e) {
1922 throw new InitException(
1923 "Can't create new baseline snapshot", e);
1924 }
1925
1926 Entry[] serviceAttributes = {
1927 new ServiceInfo(
1928 "Lease Renewal Service",
1929 "Sun Microsystems, Inc.",
1930 "Sun Microsystems, Inc.",
1931 VersionConstants.SERVER_VERSION,
1932 "",
1933 ""),
1934 new BasicServiceType("Lease Renewal Service")
1935 };
1936 try {
1937 JoinState joinState = new JoinState(
1938 normProxy, lrm, config, serviceAttributes,
1939 recoveredLocatorPreparer,
1940 new ServiceID(serverUuid.getMostSignificantBits(),
1941 serverUuid.getLeastSignificantBits()));
1942 store.addSubStore(joinState);
1943
1944
1945 NormServerBaseImpl.this.joinState = joinState;
1946 } catch (StoreException e) {
1947 throw new InitException("Can't create JoinState", e);
1948 }
1949
1950 leaseFactory = new LeaseFactory(serverProxy, serverUuid);
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969 expMgr.start();
1970 for (Iterator i = setTable.values().iterator(); i.hasNext(); ) {
1971 final LeaseSet set = (LeaseSet) i.next();
1972 synchronized (set) {
1973 expMgr.schedule(set);
1974 }
1975 }
1976
1977 lrmEventListener.start();
1978 renewLogger.start();
1979 snapshotter.start();
1980 done = true;
1981 } finally {
1982 if (!done) {
1983 try {
1984 unexport(true);
1985 } catch (Exception e) {
1986 logger.log(
1987 Level.INFO,
1988 "Unable to unexport after failure during startup",
1989 e);
1990 }
1991 }
1992 }
1993 return null;
1994 }
1995
1996 }, context);
1997 ready.ready();
1998 logger.log(Level.INFO, "Norm service started: {0}", this);
1999 } catch (PrivilegedActionException e){
2000 initFailed(e.getException());
2001 } catch (Throwable e) {
2002 initFailed(e);
2003 } finally {
2004 config = null;
2005 }
2006 }
2007
2008
2009 boolean isolateSets() {
2010 return isolateSets;
2011 }
2012
2013
2014
2015
2016 NormServerBaseImpl(NormServerInitializer init){
2017 persistent = init.persistent;
2018 lifeCycle = init.lifeCycle;
2019 loginContext = init.loginContext;
2020 persistenceDirectory = init.persistenceDirectory;
2021 renewedList = init.renewedList;
2022 snapshotWt = init.snapshotWt;
2023 logToSnapshotThresh = init.logToSnapshotThresh;
2024 leasePreparer = init.leasePreparer;
2025 listenerPreparer = init.listenerPreparer;
2026 locatorPreparer = init.locatorPreparer;
2027 recoveredLeasePreparer = init.recoveredLeasePreparer;
2028 recoveredListenerPreparer = init.recoveredListenerPreparer;
2029 recoveredLocatorPreparer = init.recoveredLocatorPreparer;
2030 setLeasePolicy = init.setLeasePolicy;
2031 isolateSets = init.isolateSets;
2032 lrm = init.lrm;
2033 exporter = init.exporter;
2034 expMgr = init.expMgr;
2035 generator = init.generator;
2036 lrmEventListener = init.lrmEventListener;
2037 renewLogger = init.renewLogger;
2038 context = init.context;
2039 config = init.config;
2040 this.codebase = init.codebase;
2041 this.certFactoryType = init.certFactoryType;
2042 this.certPathEncoding = init.certPathEncoding;
2043 this.encodedCerts = init.encodedCerts.clone();
2044 }
2045 }