Sounds like a good proposal, River 3.0.

Thoughts?

Peter.


----- Original message -----
> My "startnow" project on java.net, has always provide a "separation" of
> construction and start of the service export.  However, the usage of that API 
> is
> supposed to be something like the following.
>
> public class MyService extends PersistentJiniService {
>     public static void main( String args[] ) {
>         MyService svc = new MyService(args);
>         svc.start();
>     }
>     private MyService( String args[] ) {
>         super( args );    // creates the Configuration instance etc.
>     }
> }
>
> However, because of the use of the ServiceStarter framework, I typically 
> instead
> have service startup happen as show below,
>
> public class MyService extends PersistentJiniService {
>     public MyService( String args[], Lifecycle life ) {
>         super(args);
>         start();
>     }
> }
>
> because ServiceStarter has no other means for starting services.  With the 
> work
> that you've done to provide that API in ServiceStarter, I'd say that we need 
> to
> make an API change and a major version rev to demand that there actually be an
> interface implemented by classes provided to ServiceStarter, in all cases.
>
> For some number of years, I've tried to encourage everyone providing a 
> platform
> for service startup/registration, to agree on a common base API that would
> provide portability between containers at some level, which would allow 
> everyone
> to try the various containers, and then perhaps we'd be able to really explore
> the features that each provides.
>
> Gregg Wonderly
>
> On May 23, 2013, at 2:40 AM, Peter Firmstone <j...@zeus.net.au> wrote:
>
> > No really, don't.
> >
> > The test failure on arm that has been really driving me nuts for the last
> > month is finally solved, guess what was the cause of the problem?
> >
> > That's right unsafe publication.
> >
> > The "this" reference was published to JERI's ObjectTable prior to 
> > construction
> > completing, other threads could see the object in a partially constructed
> > state.
> >
> > This caused problems with synchronization and a lost notifyAll() while 
> > another
> > thread was in a call wait().  notifyAll() was being called every 7ms so it 
> > was
> > really being tested.
> >
> > For more info, see River-420 on Jira.
> >
> > This goes against a lot of books and literature on how to program Jini, many
> > examples (including our own) export during construction.  This is no longer
> > how we should create proxy's, we need to get the message out there.  I'm a
> > little short on time for the next few weeks, is anyone able to publish
> > something on our website?
> >
> > The good news is I have fixes for all occurrences of exports duing
> > construction in the main src directory, the bad news is there are a number 
> > of
> > instances in the qa suite still to be fixed, although these can be fixed
> > relatively easily because they're not public api.  The really bad news is
> > there's going to be a heap of client code out there that has this issue.
> >
> > The other good news is the qa refacting build is starting to look very solid
> > indeed.  The last test failure on Arm was actually a segfault in the JVM in 
> > an
> > unrelated test, not our problem, unfortunately I didn't find a log file or
> > core dump.
> >
> > Regards,
> >
> > Peter.
> >
> >
> > This is what the code looks like now it's fixed, previously the proxy was
> > created during construction:
> >
> > /**
> > * Listener that calls notifyAll on itself
> > */
> > public class LeasedSpaceListener
> >      implements RemoteEventListener, ServerProxyTrust, Serializable
> > {
> >      private static Logger logger = 
> >Logger.getLogger("com.sun.jini.qa.harness");
> >      private boolean received = false;
> >      private Object proxy;
> >      private final Exporter exporter;
> >      private final AccessControlContext context;
> >
> >      public LeasedSpaceListener(Configuration c) throws RemoteException {
> >      try {
> >              Exporter exporter = QAConfig.getDefaultExporter();
> >              if (c instanceof com.sun.jini.qa.harness.QAConfiguration) {
> >              exporter =
> >              (Exporter) c.getEntry("test",
> >                                          "outriggerListenerExporter",
> >                                          Exporter.class);
> >              }
> >                      this.exporter = exporter;
> >                      context = AccessController.getContext();
> >              // Proxy was originally exported here, allowing "this" to 
> >escape.
> >      } catch (ConfigurationException e) {
> >              throw new RemoteException("Bad configuration", e);
> >      }
> >      }
> >
> >      private synchronized Object getProxy(){
> >              if (proxy == null) {
> >                      proxy = AccessController.doPrivileged(new
> > PrivilegedAction<Object>(){
> >
> >                              @Override
> >                              public Object run() {
> >                                      try {
> >                                              return 
> >exporter.export(LeasedSpaceListener.this);
> >                                      } catch (ExportException ex) {
> >                                              String message = "Proxy export 
> >failed for
> > LeaseListener";                                              
> > logger.log(Level.WARNING, message , ex);
> >                                              return null;
> >                                      }
> >                              }
> >
> >                      }, context);
> >              }
> >              return proxy;
> >      }
> >
> >      public Object writeReplace() throws ObjectStreamException {
> >              return getProxy();
> >      }
> >
> >      public TrustVerifier getProxyVerifier() {
> >      return new BasicProxyTrustVerifier(getProxy());
> >      }
> >
> >      public void notify(RemoteEvent theEvent)
> >                      throws UnknownEventException, RemoteException {
> >              // Perform logging outside the synchronized block so we don't 
> >affect
> >              // timing.
> >              java.util.Date date = new java.util.Date();
> >              synchronized (this){
> >                      received = true;
> >                      this.notifyAll();
> >              }
> >              logger.log(Level.INFO, "notify called at {0}", date.getTime());
> >      }
> >
> >      /**
> >        * @return the received
> >        */
> >      public synchronized boolean isReceived() {
> >              return received;
> >      }
> >
> >      /**
> >        * @param received the received to set
> >        */
> >      public synchronized void setReceived(boolean received) {
> >              this.received = received;
> >      }
> > }
> >
>

Reply via email to