comparison src/org/dancres/blitz/remote/BlitzServiceImpl.java @ 0:3dc0c5604566

Initial checkin of blitz 2.0 fcs - no installer yet.
author Dan Creswell <dan.creswell@gmail.com>
date Sat, 21 Mar 2009 11:00:06 +0000
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:3dc0c5604566
1 package org.dancres.blitz.remote;
2
3 import java.io.IOException;
4
5 import java.rmi.RemoteException;
6 import java.rmi.MarshalledObject;
7 import java.rmi.RMISecurityManager;
8 import java.rmi.NoSuchObjectException;
9
10 import java.rmi.activation.ActivationID;
11 import java.rmi.activation.ActivationException;
12 import java.rmi.activation.ActivationSystem;
13 import java.rmi.activation.Activatable;
14
15 import java.util.ArrayList;
16 import java.util.List;
17
18 import java.util.logging.Logger;
19 import java.util.logging.Level;
20
21 import java.security.PrivilegedExceptionAction;
22 import java.security.PrivilegedActionException;
23 import java.net.InetSocketAddress;
24
25 import javax.security.auth.Subject;
26 import javax.security.auth.login.LoginContext;
27 import javax.security.auth.login.LoginException;
28
29 import net.jini.security.ProxyPreparer;
30 import net.jini.security.TrustVerifier;
31
32 import net.jini.security.proxytrust.ServerProxyTrust;
33
34 import net.jini.lookup.JoinManager;
35
36 import net.jini.config.ConfigurationException;
37 import net.jini.config.Configuration;
38
39 import net.jini.export.ProxyAccessor;
40 import net.jini.export.Exporter;
41
42 import net.jini.activation.ActivationExporter;
43 import net.jini.activation.ActivationGroup;
44
45 import net.jini.jeri.BasicILFactory;
46 import net.jini.jeri.BasicJeriExporter;
47
48 import net.jini.jeri.tcp.TcpServerEndpoint;
49
50 import net.jini.core.transaction.Transaction;
51 import net.jini.core.transaction.UnknownTransactionException;
52 import net.jini.core.transaction.TransactionException;
53
54 import net.jini.core.transaction.server.TransactionManager;
55
56 import net.jini.core.event.RemoteEventListener;
57 import net.jini.core.event.EventRegistration;
58
59 import net.jini.core.lease.Lease;
60 import net.jini.core.lease.UnknownLeaseException;
61 import net.jini.core.lease.LeaseDeniedException;
62
63 import net.jini.core.discovery.LookupLocator;
64
65 import net.jini.core.entry.Entry;
66
67 import net.jini.discovery.DiscoveryLocatorManagement;
68 import net.jini.discovery.DiscoveryGroupManagement;
69 import net.jini.discovery.DiscoveryManagement;
70
71 import net.jini.space.JavaSpace;
72
73 import com.sun.jini.start.LifeCycle;
74
75 import org.dancres.blitz.mangler.MangledEntry;
76
77 import org.dancres.blitz.lease.SpaceUID;
78 import org.dancres.blitz.lease.LeaseBounds;
79
80 import org.dancres.blitz.config.ConfigurationFactory;
81
82 import org.dancres.blitz.notify.RemoteEventDispatcher;
83
84 import org.dancres.blitz.Logging;
85 import org.dancres.blitz.SpaceImpl;
86 import org.dancres.blitz.RegTicket;
87 import org.dancres.blitz.WriteTicket;
88 import org.dancres.blitz.EntryChit;
89 import org.dancres.blitz.EntryView;
90
91 import org.dancres.blitz.txn.StoragePersonalityFactory;
92 import org.dancres.blitz.txn.StoragePersonality;
93
94 import org.dancres.blitz.stats.Stat;
95 import org.dancres.blitz.stats.Switch;
96 import org.dancres.blitz.stats.StatsBoard;
97 import org.dancres.blitz.stats.SwitchSettings;
98
99 import org.dancres.blitz.remote.view.EntryViewFactory;
100 import org.dancres.blitz.remote.view.ViewRegistration;
101 import org.dancres.blitz.remote.view.EntryViewUID;
102 import org.dancres.blitz.remote.txn.TransactionManagerImpl;
103 import org.dancres.blitz.remote.user.ColocatedAgent;
104
105 /**
106 <p> The remote layer implementation for Blitz supporting both transient and
107 activatable modes of operation. Needs to implement ProxyAccessor to
108 provide a means of accessing it's core remote ref for the purposes of
109 converting this remote service implementation to a stub at appropriate
110 moments in the activation process </p>.
111
112 <p> We need to publish a proxy for the Javaspace itself. If we implement
113 Administrable, this proxy should call back to the server's getAdmin() to
114 recovery an admin proxy which contains a remote stub to the admin methods.
115 The final proxy, for transactionparticipant can actually be a naked ref,
116 not even a proxy but this would allow immediate access to the other
117 interfaces of the stub which could be bad. </p>
118
119 <p> JoinAdmin should be implemented by the admin proxy and the server
120 back end. Storage/manipulation of the JoinManager should be delegated to
121 a descendent of the JINIExporter LookupStorage code which should store
122 it's data in a Blitz meta registry. This means no configuration required
123 and keeps all the meta data in one neat place.</p>
124 */
125 public class BlitzServiceImpl implements ServerProxyTrust,
126 ProxyAccessor, BlitzServer {
127
128 static final Logger theLogger =
129 Logging.newLogger("org.dancres.blitz.remote", Level.INFO);
130
131 private static BlitzServiceImpl theServiceImpl;
132
133 private ActivationID theActivationID;
134 private ActivationSystem theActivationSystem;
135
136 private LookupStorage theLookupStore;
137
138 private Exporter theExporter;
139
140 private BlitzServer theStub;
141
142 private BlitzProxy theSpaceProxy;
143
144 private JoinManager theJoinManager;
145
146 private TxnGatewayImpl theTxnGate;
147
148 private SpaceImpl theSpace;
149
150 private AdminProxy theAdminProxy;
151
152 private TxnParticipantProxy theTxnProxy;
153
154 private LifeCycle theLifecycle;
155
156 private boolean isStopped = false;
157
158 private LoginContext theLoginContext;
159
160 private boolean doCompatDestroy = false;
161
162 private TransactionManagerImpl theLoopbackTxnMgr;
163
164 /**
165 This constructor is required to use
166 com.sun.jini.start.NonActivatableServiceDescriptor.
167 */
168 public BlitzServiceImpl(String [] anArgs, LifeCycle aLifeCycle)
169 throws RemoteException, ConfigurationException {
170
171 try {
172 theLifecycle = aLifeCycle;
173 init(anArgs, true);
174 } catch (ConfigurationException aCE) {
175 destroyImpl(false);
176 throw aCE;
177 } catch (RemoteException anRE) {
178 destroyImpl(false);
179 throw anRE;
180 }
181
182 /*
183 Keep a static reference to ourselves in order to avoid premature
184 GC
185 */
186 theServiceImpl = this;
187 }
188
189 /**
190 This constructor is required to use
191 com.sun.jini.start.SharedActivatableServiceDescriptor which invokes
192 on ActivateWrapper which will call this constructor.
193 SharedActivatabkeServiceDescriptor's serverConfigArgs are wrapped
194 into a MarshalledObject and pass in with the ActivationID.
195 */
196 public BlitzServiceImpl(ActivationID anActivationID,
197 MarshalledObject aData)
198 throws RemoteException, ConfigurationException {
199
200 theActivationID = anActivationID;
201
202 String[] myArgs = null;
203
204 try {
205 myArgs = (String[]) aData.get();
206 } catch (Exception anE) {
207 theLogger.log(Level.SEVERE, "Failed to unpacked marshalled args",
208 anE);
209 throw new RemoteException("Failed to unpack marshalled args");
210 }
211
212 try {
213 init(myArgs, true);
214 } catch (ConfigurationException aCE) {
215 destroyImpl(false);
216 throw aCE;
217 } catch (RemoteException anRE) {
218 destroyImpl(false);
219 throw anRE;
220 }
221
222 theServiceImpl = this;
223 }
224
225 /**
226 * Use this to construct a local instance of blitz. When you have
227 * completed your usage of this local instance invoke either:
228 *
229 * <ul>
230 * <li>Shutdown - which will cleanly shutdown the instance retaining state
231 * (assuming you're running blitz in persistent mode).</li>
232 * <li>Destroy - which will cleanly shutdown the instance whilst discarding
233 * state as defined in the Jini DestroyAdmin specifications (note you can
234 * cause destroy to behave similarly to shutdown via appropriate
235 * configuration.</li>
236 * </ul>
237 */
238 public BlitzServiceImpl() throws RemoteException, ConfigurationException {
239 init(new String[] {}, false);
240 }
241
242 private void init(String[] anArgs, boolean doExport)
243 throws ConfigurationException, RemoteException {
244
245 if (doExport) {
246 if (System.getSecurityManager() == null)
247 System.setSecurityManager(new RMISecurityManager());
248 }
249
250 if ((anArgs != null) && (anArgs.length > 0)) {
251 ConfigurationFactory.setup(anArgs);
252 }
253
254 try {
255 doCompatDestroy =
256 ((Boolean) ConfigurationFactory.getEntry("compliantDestroy",
257 Boolean.class,
258 new Boolean(false))).booleanValue();
259
260 theLoginContext = (LoginContext)
261 ConfigurationFactory.getEntry("loginContext",
262 LoginContext.class, null);
263
264 if (theLoginContext != null) {
265 try {
266 theLoginContext.login();
267 } catch (LoginException aLE) {
268 theLogger.log(Level.SEVERE, "Couldn't login", aLE);
269 throw new ConfigurationException("Login invalid", aLE);
270 }
271 }
272
273 doPriv(new PrivilegedInitImpl(doExport));
274 } catch (Exception anE) {
275 theLogger.log(Level.SEVERE, "Oops privilege problem?", anE);
276 throw new ConfigurationException("loginContext has insufficient privileges", anE);
277 }
278 }
279
280 private Object doPriv(PrivilegedExceptionAction aPAE)
281 throws Exception {
282
283 if (theLoginContext != null) {
284 return Subject.doAsPrivileged(theLoginContext.getSubject(),
285 aPAE, null);
286 } else
287 return aPAE.run();
288 }
289
290 private class PrivilegedInitImpl implements PrivilegedExceptionAction {
291 private boolean doExport;
292
293 PrivilegedInitImpl(boolean shouldExport) {
294 doExport = shouldExport;
295 }
296
297 public Object run() throws Exception {
298 try {
299 initImpl(doExport);
300 } catch (Exception anE) {
301 theLogger.log(Level.SEVERE, "Could init with subject", anE);
302 throw anE;
303 }
304 return null;
305 }
306 }
307
308 private void initImpl(boolean doExport)
309 throws ConfigurationException, RemoteException {
310
311 /*
312 Create space with a TxnGatewayImpl
313 Once we've got as far as export'ing, invoke setParticipantStub
314 on TxnGatewayImpl so it can bundle things up appropriately.
315 */
316
317 // Make sure storage is able to initialize before we do anything
318 //
319 StoragePersonalityFactory.getPersonality();
320
321 theLookupStore = new LookupStorage();
322 theLookupStore.init(ConfigurationFactory.getConfig());
323
324 Configuration myConfig = ConfigurationFactory.getConfig();
325
326 Exporter myDefaultExporter =
327 new BasicJeriExporter(TcpServerEndpoint.getInstance(0),
328 new BasicILFactory(), false, true);
329
330 if (theActivationID == null) {
331 theExporter =
332 (Exporter) ConfigurationFactory.getEntry("serverExporter",
333 Exporter.class,
334 myDefaultExporter);
335 } else {
336 ProxyPreparer myIDPreparer =
337 ConfigurationFactory.getPreparer("activationIdPreparer");
338
339 ProxyPreparer mySysPreparer =
340 ConfigurationFactory.getPreparer("activationSysPreparer");
341
342 theActivationID =
343 (ActivationID) myIDPreparer.prepareProxy(theActivationID);
344
345 try {
346 theActivationSystem =
347 (ActivationSystem) mySysPreparer.prepareProxy(ActivationGroup.getSystem());
348 } catch (ActivationException anAE) {
349 throw new RemoteException("Unable to locate ActivationSystem");
350 }
351
352 ActivationExporter myDefActExp =
353 new ActivationExporter(theActivationID, myDefaultExporter);
354
355 theExporter =
356 (Exporter) ConfigurationFactory.getEntry("serverExporter",
357 Exporter.class,
358 myDefActExp,
359 theActivationID);
360 }
361
362 if (theExporter == null) {
363 throw new ConfigurationException("serverExporter must be non-null if it's specified");
364 }
365
366 theLogger.log(Level.INFO, "Using exporter: " + theExporter);
367
368 if (doExport)
369 theStub = (BlitzServer) theExporter.export(this);
370 else {
371 // Don't need this - so clear it down....
372 //
373 theExporter = null;
374
375 theStub = this;
376 }
377
378 Class[] myInterfaces = theStub.getClass().getInterfaces();
379
380 for (int i = 0; i < myInterfaces.length; i++) {
381 theLogger.log(Level.INFO,
382 "Stub supports: " + myInterfaces[i].getName());
383 }
384
385 theAdminProxy =
386 ProxyFactory.newAdminProxy(theStub, theLookupStore.getUuid());
387
388 theSpaceProxy =
389 ProxyFactory.newBlitzProxy(theStub, theLookupStore.getUuid());
390
391 theTxnProxy =
392 ProxyFactory.newTxnParticipantProxy(theStub,
393 theLookupStore.getUuid());
394 theTxnGate =
395 new TxnGatewayImpl(theTxnProxy);
396
397 RemoteEventDispatcher.setSource(theSpaceProxy);
398
399 try {
400 theSpace = new SpaceImpl(theTxnGate);
401
402 // Now run the user initializers
403 //
404 ColocatedAgent[] myInitializers =
405 (ColocatedAgent[])
406 ConfigurationFactory.getEntry(
407 "agents", ColocatedAgent[].class,
408 new ColocatedAgent[0]);
409
410 for (int i = 0; i < myInitializers.length; i++) {
411 myInitializers[i].init(theSpaceProxy);
412 }
413
414 } catch (Exception anE) {
415 theLogger.log(Level.SEVERE, "Failed to start space", anE);
416 throw new RemoteException("Failed to start space", anE);
417 }
418
419 if (doExport) {
420 theLogger.log(Level.INFO, "Space core is up, starting JoinManager");
421
422 try {
423 theJoinManager = new JoinManager(theSpaceProxy,
424 theLookupStore.getAttributes(),
425 theLookupStore.getServiceID(),
426 theLookupStore.getDiscMgt(),
427 null,
428 myConfig);
429 } catch (IOException anIOE) {
430 theLogger.log(Level.SEVERE, "Failed to init JoinManager",
431 anIOE);
432
433 throw new RemoteException("Failed to init JoinManager",
434 anIOE);
435 }
436 }
437
438 try {
439 theLoopbackTxnMgr =
440 new TransactionManagerImpl(theStub, theLookupStore.getUuid());
441 } catch (IOException anIOE) {
442 throw new RemoteException("Failed to init loopback txn manager",
443 anIOE);
444 }
445 }
446
447 public JavaSpace getSpaceProxy() {
448 return theSpaceProxy;
449 }
450
451 public SpaceImpl getSpace() {
452 return theSpace;
453 }
454
455 public LeaseImpl write(MangledEntry anEntry, Transaction aTxn,
456 long aLeaseTime)
457 throws RemoteException, TransactionException {
458
459 stopBarrier();
460
461 try {
462 WriteTicket myTicket = theSpace.write(anEntry, aTxn, aLeaseTime);
463
464 return
465 ProxyFactory.newEntryLeaseImpl(theStub, theLookupStore.getUuid(),
466 myTicket.getUID(),
467 myTicket.getExpirationTime());
468 } catch (IOException anIOE) {
469 theLogger.log(Level.SEVERE, "SpaceImpl has disk problems", anIOE);
470 throw new RemoteException("Space has disk problems", anIOE);
471 }
472 }
473
474 public MangledEntry take(MangledEntry anEntry, Transaction aTxn,
475 long aWaitTime)
476 throws RemoteException, TransactionException {
477
478 stopBarrier();
479
480 try {
481 return theSpace.take(anEntry, aTxn, aWaitTime);
482 } catch (IOException anIOE) {
483 theLogger.log(Level.SEVERE, "SpaceImpl has disk problems", anIOE);
484 throw new RemoteException("Space has disk problems", anIOE);
485 }
486 }
487
488 public MangledEntry read(MangledEntry anEntry, Transaction aTxn,
489 long aWaitTime)
490 throws RemoteException, TransactionException {
491
492 stopBarrier();
493
494 try {
495 return theSpace.read(anEntry, aTxn, aWaitTime);
496 } catch (IOException anIOE) {
497 theLogger.log(Level.SEVERE, "SpaceImpl has disk problems", anIOE);
498 throw new RemoteException("Space has disk problems", anIOE);
499 }
500 }
501
502 public MangledEntry takeIfExists(MangledEntry anEntry, Transaction aTxn,
503 long aWaitTime)
504 throws RemoteException, TransactionException {
505
506 stopBarrier();
507
508 try {
509 return theSpace.takeIfExists(anEntry, aTxn, aWaitTime);
510 } catch (IOException anIOE) {
511 theLogger.log(Level.SEVERE, "SpaceImpl has disk problems", anIOE);
512 throw new RemoteException("Space has disk problems", anIOE);
513 }
514 }
515
516 public MangledEntry readIfExists(MangledEntry anEntry, Transaction aTxn,
517 long aWaitTime)
518 throws RemoteException, TransactionException {
519
520 stopBarrier();
521
522 try {
523 return theSpace.readIfExists(anEntry, aTxn, aWaitTime);
524 } catch (IOException anIOE) {
525 theLogger.log(Level.SEVERE, "SpaceImpl has disk problems", anIOE);
526 throw new RemoteException("Space has disk problems", anIOE);
527 }
528 }
529
530 public EventRegistration notify(MangledEntry anEntry, Transaction aTxn,
531 RemoteEventListener aListener,
532 long aLeaseTime,
533 MarshalledObject aHandback)
534 throws RemoteException, TransactionException {
535
536 stopBarrier();
537
538 try {
539 RegTicket myTicket =
540 theSpace.notify(anEntry, aTxn, aListener, aLeaseTime,
541 aHandback);
542
543 LeaseImpl myLease =
544 ProxyFactory.newLeaseImpl(theStub, theLookupStore.getUuid(),
545 myTicket.getUID(),
546 myTicket.getExpirationTime());
547
548 return new EventRegistration(myTicket.getSourceId(), theSpaceProxy,
549 myLease, myTicket.getSeqNum());
550 } catch (IOException anIOE) {
551 theLogger.log(Level.SEVERE, "SpaceImpl has disk problems", anIOE);
552 throw new RemoteException("Space has disk problems", anIOE);
553 }
554 }
555
556 /* *********************************************************************
557 * ProxyAccessor stuff
558 ******************************************************************** */
559
560 public Object getProxy() {
561 return theStub;
562 }
563
564 /* *********************************************************************
565 * ServerProxyTrust stuff
566 ******************************************************************** */
567
568 /**
569 <p> Blitz can be run as a secure service, in which case, it exports
570 various ConstrainedProxy instances which support RemoteMethodControl.
571 Such proxy instances are exported only when the original stub supports
572 RemoteMethodControl. </p>
573
574 <p> As Blitz uses custom proxies as opposed to JERI stubs, we must
575 do some additional work to support TrustVerification. Assuming the
576 stub has been generated using ProxyTrustILFactory it supports the
577 bootstrap step. For bootstrap to work, the remote server must support
578 ServerProxyTrust which will be invoked as part of the bootstrap process
579 supported in the stub. </p>
580 */
581 public TrustVerifier getProxyVerifier() throws RemoteException {
582 stopBarrier();
583
584 return new ProxyVerifier(theStub, theLookupStore.getUuid());
585 }
586
587 /* *********************************************************************
588 * Transaction participant stuff
589 ******************************************************************** */
590
591 public int prepare(TransactionManager mgr, long id)
592 throws UnknownTransactionException, RemoteException {
593
594 stopBarrier();
595
596 return theSpace.getTxnControl().prepare(mgr, id);
597 }
598
599 public void commit(TransactionManager mgr, long id)
600 throws UnknownTransactionException, RemoteException {
601
602 stopBarrier();
603
604 theSpace.getTxnControl().commit(mgr, id);
605 }
606
607 public void abort(TransactionManager mgr, long id)
608 throws UnknownTransactionException, RemoteException {
609
610 stopBarrier();
611
612 theSpace.getTxnControl().abort(mgr, id);
613 }
614
615 public int prepareAndCommit(TransactionManager mgr, long id)
616 throws UnknownTransactionException, RemoteException {
617
618 stopBarrier();
619
620 return theSpace.getTxnControl().prepareAndCommit(mgr, id);
621 }
622
623 /* *********************************************************************
624 * Landlord
625 ******************************************************************** */
626 public long renew(SpaceUID aUID, long aDuration)
627 throws UnknownLeaseException, LeaseDeniedException, RemoteException {
628
629 // System.out.println("Renew: " + aUID + ", " + aDuration);
630
631 stopBarrier();
632
633 try {
634 long myResult = theSpace.getLeaseControl().renew(aUID, aDuration);
635
636 // System.out.println("Renew: " + myResult);
637
638 return myResult;
639 } catch (IOException anIOE) {
640 theLogger.log(Level.SEVERE, "Space has disk problems", anIOE);
641 throw new RemoteException("Space has disk problems", anIOE);
642 }
643 }
644
645 public void cancel(SpaceUID aUID)
646 throws UnknownLeaseException, RemoteException {
647
648 stopBarrier();
649
650 try {
651 theSpace.getLeaseControl().cancel(aUID);
652 } catch (IOException anIOE) {
653 theLogger.log(Level.SEVERE, "Space has disk problems", anIOE);
654 throw new RemoteException("Space has disk problems", anIOE);
655 }
656 }
657
658 public LeaseResults renew(SpaceUID[] aLeases, long[] aDurations)
659 throws RemoteException {
660
661 stopBarrier();
662
663 long[] myNewDurations = new long[aLeases.length];
664 Exception[] myFails = null;
665
666 for (int i = 0; i < aLeases.length; i++) {
667 try {
668 myNewDurations[i] =
669 theSpace.getLeaseControl().renew(aLeases[i],
670 aDurations[i]);
671 } catch (LeaseDeniedException anLDE) {
672 if (myFails == null)
673 myFails = initFails(aLeases.length, i);
674
675 myNewDurations[i] = -1;
676 myFails[i] = anLDE;
677 } catch (UnknownLeaseException anULE) {
678 if (myFails == null)
679 myFails = initFails(aLeases.length, i);
680
681 myNewDurations[i] = -1;
682 myFails[i] = anULE;
683 } catch (IOException anIOE) {
684 theLogger.log(Level.SEVERE, "Space has disk problems", anIOE);
685 throw new RemoteException("Space has disk problems", anIOE);
686 }
687 }
688
689 return new LeaseResults(myNewDurations, myFails);
690 }
691
692 public LeaseResults cancel(SpaceUID[] aLeases)
693 throws RemoteException {
694
695 stopBarrier();
696
697 Exception[] myFails = null;
698
699 for (int i = 0; i < aLeases.length; i++) {
700 try {
701 theSpace.getLeaseControl().cancel(aLeases[i]);
702 } catch (UnknownLeaseException aULE) {
703 if (myFails == null)
704 myFails = initFails(aLeases.length, i);
705
706 myFails[i] = aULE;
707 } catch (IOException anIOE) {
708 theLogger.log(Level.SEVERE, "Space has disk problems", anIOE);
709 throw new RemoteException("Space has disk problems", anIOE);
710 }
711 }
712
713 if (myFails != null)
714 return new LeaseResults(null, myFails);
715 else
716 return null;
717 }
718
719 private Exception[] initFails(int aLength, int anOffset) {
720 return new Exception[aLength];
721 }
722
723 /* *********************************************************************
724 * ServiceProxyAccessor
725 ******************************************************************** */
726
727 public Object getServiceProxy() throws RemoteException {
728 stopBarrier();
729
730 return theSpaceProxy;
731 }
732
733 /* *********************************************************************
734 * Administrable::getAdmin support
735 ******************************************************************** */
736
737 public Object getAdmin() throws RemoteException {
738 stopBarrier();
739
740 return theAdminProxy;
741 }
742
743 /* *********************************************************************
744 * JoinAdmin
745 ******************************************************************** */
746 /**
747 * Get the current attribute sets for the service.
748 *
749 * @return the current attribute sets for the service
750 * @throws java.rmi.RemoteException
751 */
752 public Entry[] getLookupAttributes() throws RemoteException {
753 stopBarrier();
754
755 return theJoinManager.getAttributes();
756 }
757
758 /**
759 * Add attribute sets for the service. The resulting set will be used
760 * for all future joins. The attribute sets are also added to all
761 * currently-joined lookup services.
762 *
763 * @param attrSets the attribute sets to add
764 * @throws java.rmi.RemoteException
765 */
766 public void addLookupAttributes(Entry[] attrSets) throws RemoteException {
767 stopBarrier();
768
769 theJoinManager.addAttributes(attrSets);
770 syncStore();
771 }
772
773 /**
774 * Modify the current attribute sets, using the same semantics as
775 * ServiceRegistration.modifyAttributes. The resulting set will be used
776 * for all future joins. The same modifications are also made to all
777 * currently-joined lookup services.
778 *
779 * @param attrSetTemplates the templates for matching attribute sets
780 * @param attrSets the modifications to make to matching sets
781 * @throws java.rmi.RemoteException
782 *
783 * @see net.jini.core.lookup.ServiceRegistration#modifyAttributes
784 */
785 public void modifyLookupAttributes(Entry[] attrSetTemplates,
786 Entry[] attrSets)
787 throws RemoteException {
788 stopBarrier();
789
790 theJoinManager.modifyAttributes(attrSetTemplates, attrSets);
791 syncStore();
792 }
793
794 private DiscoveryGroupManagement getDGM() {
795 return (DiscoveryGroupManagement) theJoinManager.getDiscoveryManager();
796 }
797
798 /**
799 * Get the list of groups to join. An empty array means the service
800 * joins no groups (as opposed to "all" groups).
801 *
802 * @return an array of groups to join. An empty array means the service
803 * joins no groups (as opposed to "all" groups).
804 * @throws java.rmi.RemoteException
805 * @see #setLookupGroups
806 */
807 public String[] getLookupGroups() throws RemoteException {
808 stopBarrier();
809
810 return getDGM().getGroups();
811 }
812
813 /**
814 * Add new groups to the set to join. Lookup services in the new
815 * groups will be discovered and joined.
816 *
817 * @param groups groups to join
818 * @throws java.rmi.RemoteException
819 * @see #removeLookupGroups
820 */
821 public void addLookupGroups(String[] groups) throws RemoteException {
822 stopBarrier();
823
824 try {
825 getDGM().addGroups(groups);
826 } catch (IOException anIOE) {
827 throw new RemoteException("Got IOE changing groups", anIOE);
828 }
829 syncStore();
830 }
831
832 /**
833 * Remove groups from the set to join. Leases are cancelled at lookup
834 * services that are not members of any of the remaining groups.
835 *
836 * @param groups groups to leave
837 * @throws java.rmi.RemoteException
838 * @see #addLookupGroups
839 */
840 public void removeLookupGroups(String[] groups) throws RemoteException {
841 stopBarrier();
842
843 getDGM().removeGroups(groups);
844 syncStore();
845 }
846
847 /**
848 * Replace the list of groups to join with a new list. Leases are
849 * cancelled at lookup services that are not members of any of the
850 * new groups. Lookup services in the new groups will be discovered
851 * and joined.
852 *
853 * @param groups groups to join
854 * @throws java.rmi.RemoteException
855 * @see #getLookupGroups
856 */
857 public void setLookupGroups(String[] groups) throws RemoteException {
858 stopBarrier();
859
860 try {
861 getDGM().setGroups(groups);
862 } catch (IOException anIOE) {
863 throw new RemoteException("Got IOE changing groups", anIOE);
864 }
865 syncStore();
866 }
867
868 private DiscoveryLocatorManagement getDLM() {
869 return (DiscoveryLocatorManagement)
870 theJoinManager.getDiscoveryManager();
871 }
872
873 /**
874 *Get the list of locators of specific lookup services to join.
875 *
876 * @return the list of locators of specific lookup services to join
877 * @throws java.rmi.RemoteException
878 * @see #setLookupLocators
879 */
880 public LookupLocator[] getLookupLocators() throws RemoteException {
881 stopBarrier();
882
883 return getDLM().getLocators();
884 }
885
886 /**
887 * Add locators for specific new lookup services to join. The new
888 * lookup services will be discovered and joined.
889 *
890 * @param locators locators of specific lookup services to join
891 * @throws java.rmi.RemoteException
892 * @see #removeLookupLocators
893 */
894 public void addLookupLocators(LookupLocator[] locators)
895 throws RemoteException {
896 stopBarrier();
897
898 getDLM().addLocators(locators);
899 syncStore();
900 }
901
902 /**
903 * Remove locators for specific lookup services from the set to join.
904 * Any leases held at the lookup services are cancelled.
905 *
906 * @param locators locators of specific lookup services to leave
907 * @throws java.rmi.RemoteException
908 * @see #addLookupLocators
909 */
910 public void removeLookupLocators(LookupLocator[] locators)
911 throws RemoteException {
912 stopBarrier();
913
914 getDLM().removeLocators(locators);
915 syncStore();
916 }
917
918 /**
919 * Replace the list of locators of specific lookup services to join
920 * with a new list. Leases are cancelled at lookup services that were
921 * in the old list but are not in the new list. Any new lookup services
922 * will be discovered and joined.
923 *
924 * @param locators locators of specific lookup services to join
925 * @throws java.rmi.RemoteException
926 * @see #getLookupLocators
927 */
928 public void setLookupLocators(LookupLocator[] locators)
929 throws RemoteException {
930 stopBarrier();
931
932 getDLM().setLocators(locators);
933 syncStore();
934 }
935
936 private void syncStore() throws RemoteException {
937 try {
938 theLookupStore.sync(theJoinManager);
939 } catch (IOException anIOE) {
940 throw new RemoteException("Couldn't update saved state", anIOE);
941 }
942 }
943
944
945 /* *********************************************************************
946 * DestroyAdmin
947 ******************************************************************** */
948
949 public void destroy() throws RemoteException {
950 destroyImpl(doCompatDestroy);
951 }
952
953 private void destroyImpl(boolean doCleanup) throws RemoteException {
954 stopBarrier();
955
956 blockCalls();
957
958 // Load cleanup variable from config and construct accordingly
959 Thread myDestroyer = new DestroyThread(doCleanup);
960 myDestroyer.setDaemon(false);
961 myDestroyer.start();
962 }
963
964 private void blockCalls() {
965 synchronized(this) {
966 isStopped = true;
967 }
968 }
969
970 private void unblockCalls() {
971 synchronized(this) {
972 isStopped = false;
973 }
974 }
975
976 /**
977 Used to check whether calls are blocked and, if they are, throws
978 a RemoteException back to the client.
979 */
980 private void stopBarrier() throws RemoteException {
981 synchronized(this) {
982 if (isStopped)
983 throw new RemoteException("Remote calls not permitted");
984 }
985 }
986
987 private class DestroyThread extends Thread {
988 private boolean doClean;
989
990 private DestroyThread(boolean shouldClean) {
991 super("DestroyThread");
992 doClean = shouldClean;
993 }
994
995 public void run() {
996 theLogger.log(Level.SEVERE, "Shutdown in progress");
997
998 if (theLoopbackTxnMgr != null) {
999 theLogger.log(Level.SEVERE, "Stop LoopbackTxnMgr");
1000 theLoopbackTxnMgr.terminate();
1001 }
1002
1003 if (theJoinManager != null) {
1004 theLogger.log(Level.SEVERE, "Stop JoinManager");
1005 DiscoveryManagement myDGM = theJoinManager.getDiscoveryManager();
1006
1007 theJoinManager.terminate();
1008 myDGM.terminate();
1009 }
1010
1011 if (theActivationID != null) {
1012 theLogger.log(Level.SEVERE,
1013 "De-registering from ActivationSystem");
1014
1015 try {
1016 theActivationSystem.unregisterObject(theActivationID);
1017 } catch (Exception anAE) {
1018 theLogger.log(Level.SEVERE, "Activation unregister failed",
1019 anAE);
1020 }
1021 }
1022
1023 if ((theStub != null) && (theExporter != null)) {
1024 theLogger.log(Level.SEVERE, "Unexport - forced");
1025 theExporter.unexport(true);
1026 }
1027
1028 if (theSpace != null) {
1029 try {
1030 theLogger.log(Level.SEVERE, "Stopping space");
1031 theSpace.stop();
1032 } catch (Exception anE) {
1033 theLogger.log(Level.SEVERE, "Space failed to shutdown cleanly",
1034 anE);
1035 }
1036 }
1037
1038 if (theActivationID != null) {
1039 theLogger.log(Level.SEVERE, "Notifying ActivationGroup");
1040
1041 try {
1042 Activatable.inactive(theActivationID);
1043 } catch (Exception anE) {
1044 theLogger.log(Level.SEVERE, "ActivationGroup complained",
1045 anE);
1046 }
1047 }
1048
1049 if (theLifecycle != null) {
1050 theLogger.log(Level.SEVERE, "Lifecycle::unregister");
1051 theLifecycle.unregister(theServiceImpl);
1052 }
1053
1054 if (theLoginContext != null) {
1055 try {
1056 theLogger.log(Level.SEVERE, "Logout");
1057 theLoginContext.logout();
1058 } catch (LoginException aLE) {
1059 theLogger.log(Level.SEVERE, "Couldn't logout", aLE);
1060 }
1061 }
1062
1063 theLogger.log(Level.SEVERE, "Shutdown complete");
1064
1065 /*
1066 Check config and optionally invoke Disk::clear on
1067 appropriate directories
1068 */
1069 if (doClean) {
1070 StoragePersonality myPersonality =
1071 StoragePersonalityFactory.getPersonality();
1072
1073 /*
1074 It's possible that config is broken and thus we are
1075 performing destroy. If config *is* broken, we may not
1076 be able to create a personality.....
1077 */
1078 if (myPersonality != null) {
1079 theLogger.log(Level.SEVERE, "Erasing disk state");
1080
1081 myPersonality.destroy();
1082 }
1083 }
1084 }
1085 }
1086
1087 /* *********************************************************************
1088 * StatsAdmin
1089 ******************************************************************** */
1090
1091 public Stat[] getStats() throws RemoteException {
1092 stopBarrier();
1093
1094 return StatsBoard.get().getStats();
1095 }
1096
1097 public void setSwitches(Switch[] aListOfSwitches) throws RemoteException {
1098 stopBarrier();
1099
1100 SwitchSettings.get().update(aListOfSwitches);
1101 }
1102
1103 /* *********************************************************************
1104 * EntryViewAdmin
1105 ******************************************************************** */
1106 public JavaSpace getJavaSpaceProxy() throws RemoteException {
1107 return theSpaceProxy;
1108 }
1109
1110 public ViewResult newView(MangledEntry[] aTemplates, Transaction aTxn,
1111 long aLeaseDuration, boolean isJavaSpace05,
1112 long aLimit, int anInitialChunk)
1113 throws RemoteException, TransactionException {
1114
1115 stopBarrier();
1116
1117 try {
1118 long myDuration = aLeaseDuration;
1119
1120 /*
1121 Bound the lease if we're instructed to do so - we may not
1122 be required to if this is an emulation of the old
1123 JavaSpaceAdmin::contents call
1124 */
1125 if (isJavaSpace05)
1126 myDuration = LeaseBounds.boundView(aLeaseDuration);
1127
1128 /*
1129 * JavaSpace05 holds locks only for a non-null transaction.
1130 * JavaSpaceAdmin never holds locks but uses the transaction to
1131 * test visibility
1132 */
1133 boolean holdLocks =
1134 (isJavaSpace05) ? (aTxn != null) : false;
1135
1136 /*
1137 If we're being asked to do JavaSpace05, we're performing the new contents
1138 operation which means we should pass true for holdlocks, false otherwise
1139 */
1140 ViewRegistration myReg =
1141 EntryViewFactory.get().newView(aTemplates, aTxn, holdLocks,
1142 myDuration, aLimit, theSpace);
1143
1144 /*
1145 Okay, got a view, now we need an initial batch
1146 */
1147 EntryChit[] myInitialBatch = getNext(myReg.getUID(), anInitialChunk);
1148
1149 return new ViewResult(
1150 ProxyFactory.newLeaseImpl(theStub, theLookupStore.getUuid(),
1151 myReg.getUID(),
1152 myReg.getExpiry()),
1153 myInitialBatch);
1154 } catch (IOException anIOE) {
1155 throw new RemoteException("Failed to create view", anIOE);
1156 }
1157 }
1158
1159 public EntryChit[] getNext(EntryViewUID aUid, int aChunkSize)
1160 throws RemoteException {
1161
1162 stopBarrier();
1163
1164 ArrayList myNext = new ArrayList();
1165
1166 EntryView myView = EntryViewFactory.get().getView(aUid);
1167
1168 /*
1169 View could have expired or been otherwise lost
1170 */
1171 if (myView == null)
1172 throw new NoSuchObjectException("View has been lost");
1173
1174 try {
1175 for (int i = 0; i < aChunkSize; i++) {
1176 EntryChit myChit = myView.next();
1177
1178 if (myChit == null)
1179 break;
1180 else
1181 myNext.add(myChit);
1182 }
1183 } catch (TransactionException aTE) {
1184 throw new RemoteException("View was prematurely destroyed - was a transaction ended?", aTE);
1185 } catch (IOException anIOE) {
1186 throw new RemoteException("Couldn't recover an Entry", anIOE);
1187 }
1188
1189 if (myNext.size() == 0)
1190 return null;
1191
1192 EntryChit[] myChits = new EntryChit[myNext.size()];
1193 myChits = (EntryChit[]) myNext.toArray(myChits);
1194
1195 return myChits;
1196 }
1197
1198 /**
1199 Deletes a specific entity returned from an
1200 <code>EntryView</code> via an <code>EntryChit</code>
1201 */
1202 public void delete(Object aCookie) throws RemoteException {
1203 stopBarrier();
1204
1205 try {
1206 theSpace.getLeaseControl().cancel((SpaceUID) aCookie);
1207 } catch (IOException anIOE) {
1208 theLogger.log(Level.SEVERE, "Space has disk problems", anIOE);
1209 throw new RemoteException("Space has disk problems", anIOE);
1210 } catch (UnknownLeaseException aULE) {
1211 // It's gone already, fail silently
1212 }
1213 }
1214
1215 public void close(EntryViewUID aUid) throws RemoteException {
1216 stopBarrier();
1217
1218 EntryViewFactory.get().delete(aUid);
1219 }
1220
1221 /* *********************************************************************
1222 * JavaSpace05
1223 ******************************************************************** */
1224
1225 public List write(List aMangledEntries, Transaction aTxn, List aLeaseTimes)
1226 throws RemoteException, TransactionException {
1227
1228 stopBarrier();
1229
1230 try {
1231 List myTickets = theSpace.write(aMangledEntries, aTxn, aLeaseTimes);
1232
1233 for (int i = 0; i < myTickets.size(); i++) {
1234 WriteTicket myTicket = (WriteTicket) myTickets.get(i);
1235
1236 Lease myLease =
1237 ProxyFactory.newEntryLeaseImpl(theStub, theLookupStore.getUuid(),
1238 myTicket.getUID(),
1239 myTicket.getExpirationTime());
1240
1241 myTickets.set(i, myLease);
1242 }
1243
1244 return myTickets;
1245 } catch (IOException anIOE) {
1246 theLogger.log(Level.SEVERE, "SpaceImpl has disk problems", anIOE);
1247 throw new RemoteException("Space has disk problems", anIOE);
1248 }
1249 }
1250
1251 public List take(MangledEntry[] aTemplates, Transaction aTxn,
1252 long aWaitTime, long aLimit)
1253 throws RemoteException, TransactionException {
1254
1255 stopBarrier();
1256
1257 try {
1258 return theSpace.take(aTemplates, aTxn, aWaitTime, aLimit);
1259 } catch (IOException anIOE) {
1260 theLogger.log(Level.SEVERE, "SpaceImpl has disk problems", anIOE);
1261 throw new RemoteException("Space has disk problems", anIOE);
1262 }
1263 }
1264
1265 public EventRegistration
1266 registerForVisibility(MangledEntry[] aTemplates, Transaction aTxn,
1267 RemoteEventListener aListener, long aLeaseTime,
1268 MarshalledObject aHandback,
1269 boolean visibilityOnly)
1270 throws RemoteException, TransactionException {
1271
1272 stopBarrier();
1273
1274 try {
1275 RegTicket myTicket =
1276 theSpace.visibility(aTemplates, aTxn, aListener, aLeaseTime,
1277 aHandback, visibilityOnly);
1278
1279 LeaseImpl myLease =
1280 ProxyFactory.newLeaseImpl(theStub, theLookupStore.getUuid(),
1281 myTicket.getUID(),
1282 myTicket.getExpirationTime());
1283
1284 return new EventRegistration(myTicket.getSourceId(), theSpaceProxy,
1285 myLease, myTicket.getSeqNum());
1286 } catch (IOException anIOE) {
1287 theLogger.log(Level.SEVERE, "SpaceImpl has disk problems", anIOE);
1288 throw new RemoteException("Space has disk problems", anIOE);
1289 }
1290 }
1291
1292 /* *********************************************************************
1293 * BlitzAdmin
1294 ******************************************************************** */
1295 public void requestSnapshot() throws RemoteException,
1296 TransactionException, IOException {
1297 stopBarrier();
1298 theSpace.getTxnControl().requestSnapshot();
1299 }
1300
1301 public void shutdown() throws RemoteException {
1302 // stopBarrier is donw in destroyImpl
1303 destroyImpl(false);
1304 }
1305
1306 public void backup(String aDir) throws RemoteException, IOException {
1307 stopBarrier();
1308 theSpace.getTxnControl().backup(aDir);
1309 }
1310
1311 public void clean() throws RemoteException, IOException {
1312 stopBarrier();
1313
1314 blockCalls();
1315
1316 try {
1317 theSpace.empty();
1318 } finally {
1319 unblockCalls();
1320 }
1321 }
1322
1323 public void reap() throws RemoteException {
1324 theSpace.reap();
1325 }
1326 }