You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@river.apache.org by ni...@apache.org on 2008/12/10 06:11:41 UTC

svn commit: r724975 [4/7] - in /incubator/river/jtsk/skunk/niclas1/services/norm: ./ src/ src/main/ src/main/java/ src/main/java/com/ src/main/java/com/sun/ src/main/java/com/sun/jini/ src/main/java/com/sun/jini/norm/ src/main/java/com/sun/jini/norm/ev...

Added: incubator/river/jtsk/skunk/niclas1/services/norm/src/main/java/com/sun/jini/norm/PersistentStore.java
URL: http://svn.apache.org/viewvc/incubator/river/jtsk/skunk/niclas1/services/norm/src/main/java/com/sun/jini/norm/PersistentStore.java?rev=724975&view=auto
==============================================================================
--- incubator/river/jtsk/skunk/niclas1/services/norm/src/main/java/com/sun/jini/norm/PersistentStore.java (added)
+++ incubator/river/jtsk/skunk/niclas1/services/norm/src/main/java/com/sun/jini/norm/PersistentStore.java Tue Dec  9 21:11:39 2008
@@ -0,0 +1,346 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.sun.jini.norm;
+
+import com.sun.jini.norm.lookup.SubStore;
+import com.sun.jini.reliableLog.LogHandler;
+import com.sun.jini.reliableLog.ReliableLog;
+import com.sun.jini.system.FileSystem;
+import com.sun.jini.thread.ReadersWriter;
+import java.io.File;
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import net.jini.config.ConfigurationException;
+
+/**
+ * Class that actually stores a Norm server's state to disk.  Basically
+ * a wrapper around ReliableLog with the addition of lock management.
+ *
+ * @author Sun Microsystems, Inc.
+ */
+class PersistentStore
+{
+    /**
+     * Logger for logging messages for this class
+     */
+    private static final Logger logger = Logger.getLogger( "com.sun.jini.norm" );
+
+    /**
+     * Object we use to reliably and persistently log updates to our
+     * state, or null if not persistent.
+     */
+    private ReliableLog log;
+
+    /**
+     * No mutation of persistent state can occur during a snapshot,
+     * however, we can have multiple mutators, use
+     * <code>ReadersWriter</code> object to manage this invariant.  Note
+     * as far as the lock is concerned the mutators are the readers and
+     * snapshot thread the writer since for us mutation is the
+     * non-exclusive operation.
+     */
+    final private ReadersWriter mutatorLock = new ReadersWriter();
+
+    /**
+     * Thread local that tracks if (and how many times) the current thread
+     * has acquired a non-exclusive mutator lock.
+     */
+    final static private ThreadLocal lockState = new ThreadLocal();
+
+    /**
+     * Cache a <code>Long</code> object with a zero value
+     */
+    final static private Long zero = new Long( 0 );
+
+    /**
+     * Location of the persistent store, or null if not persistent
+     */
+    final private File storeLocation;
+
+    /**
+     * Object that handles the recovery of logs, or null if not persistent
+     */
+    final private LogHandler logHandler;
+
+    /**
+     * The NormServer we are part of
+     */
+    final private NormServerBaseImpl server;
+
+    /**
+     * Number of updates since last snapshot
+     */
+    private int updateCount;
+
+    /**
+     * A list of all of the sub-stores
+     */
+    private List subStores = new LinkedList();
+
+    /**
+     * Construct a store that will persist its data to the specified
+     * directory.
+     *
+     * @param logDir     directory where the store should persist its data,
+     *                   which must exist, unless it is <code>null</code>, in which case
+     *                   there is no persistence
+     * @param logHandler object that will process the log and last
+     *                   snapshot to recover the server's state
+     * @param server     the server is called back after an update so it can
+     *                   decide whether or not to do a snapshot
+     * @throws StoreException if there is a problem setting up the store
+     */
+    PersistentStore( String logDir, LogHandler logHandler,
+                     NormServerBaseImpl server )
+        throws StoreException
+    {
+        this.logHandler = logHandler;
+        this.server = server;
+        if( logDir == null )
+        {
+            storeLocation = null;
+        }
+        else
+        {
+            storeLocation = new File( logDir );
+            try
+            {
+                log = new ReliableLog(
+                    storeLocation.getCanonicalPath(), logHandler );
+            }
+            catch( IOException e )
+            {
+                throw new CorruptedStoreException(
+                    "Failure creating reliable log", e );
+            }
+
+            try
+            {
+                log.recover();
+            }
+            catch( IOException e )
+            {
+                throw new CorruptedStoreException(
+                    "Failure recovering reliable log", e );
+            }
+        }
+    }
+
+    /**
+     * Destroy the store.
+     *
+     * @throws IOException if it has difficulty removing the log files
+     */
+    void destroy() throws IOException
+    {
+        // Prep all the sub-stores to be destroyed
+        for( Iterator i = subStores.iterator(); i.hasNext(); )
+        {
+            SubStore subStore = (SubStore) i.next();
+            subStore.prepareDestroy();
+        }
+        if( log != null )
+        {
+            log.deletePersistentStore();
+            FileSystem.destroy( storeLocation, true );
+        }
+    }
+
+    /**
+     * Inform the store of a sub-store
+     */
+    void addSubStore( SubStore subStore ) throws StoreException
+    {
+        try
+        {
+            if( log == null )
+            {
+                subStore.setDirectory( null );
+            }
+            else
+            {
+                final String subDir = subStore.subDirectory();
+
+                if( subDir == null )
+                {
+                    subStore.setDirectory( storeLocation );
+                }
+                else
+                {
+                    subStore.setDirectory( new File( storeLocation, subDir ) );
+                }
+            }
+
+            subStores.add( subStore );
+        }
+        catch( IOException e )
+        {
+            throw new StoreException( "Failure adding substore " + subStore,
+                                      e );
+        }
+        catch( ConfigurationException e )
+        {
+            throw new StoreException( "Failure adding substore " + subStore,
+                                      e );
+        }
+    }
+
+
+    /////////////////////////////////////////////////////////////////
+    // Methods for obtaining and releasing the locks on the store
+
+    /**
+     * Block until we can acquire a non-exclusive mutator lock on the
+     * server's persistent state.  This lock should be acquired in a
+     * <code>try</code> block and a <code>releaseMutatorLock</code> call
+     * should be placed in a <code>finally</code> block.
+     */
+    void acquireMutatorLock()
+    {
+        // Do we already hold a lock?
+
+        Long lockStateVal = (Long) lockState.get();
+        if( lockStateVal == null )
+        {
+            lockStateVal = zero;
+        }
+
+        final long longVal = lockStateVal.longValue();
+
+        if( longVal == 0 )
+        {
+            // No, this thread currently does not hold a lock,
+            // grab non-exclusive lock (which for mutatorLock is a
+            // read lock)
+            mutatorLock.readLock();
+        }
+
+        // Either way, bump the lock count and update our thread state
+        lockState.set( new Long( longVal + 1 ) );
+    }
+
+    /**
+     * Release one level of mutator locks if this thread holds at least one.
+     */
+    void releaseMutatorLock()
+    {
+        Long lockStateVal = (Long) lockState.get();
+        if( lockStateVal == null )
+        {
+            lockStateVal = zero;
+        }
+
+        final long longVal = lockStateVal.longValue();
+
+        if( longVal == 0 )
+        {
+            // No lock to release, return
+            return;
+        }
+
+        if( longVal == 1 )
+        {
+            // Last one on stack release lock
+            // Using read lock because we want a non-exclusive lock
+            mutatorLock.readUnlock();
+            lockStateVal = zero;
+        }
+        else
+        {
+            lockStateVal = new Long( longVal - 1 );
+        }
+
+        lockState.set( lockStateVal );
+    }
+
+    //////////////////////////////////////////////////////////////////
+    // Methods for writing records to the log and taking and
+    // coordinating snapshots
+
+    /**
+     * Log an update. Will flush to disk before returning.
+     *
+     * @throws IllegalStateException if the current thread does not hold
+     *                               a non-exclusive mutator lock
+     * @throws IOException
+     * @see ReliableLog#update
+     */
+    void update( Object o )
+    {
+        if( log == null )
+        {
+            return;
+        }
+        final Long lockStateVal = (Long) lockState.get();
+        if( lockStateVal == null || lockStateVal.longValue() == 0 )
+        {
+            throw new IllegalStateException( "PersistentStore.update:" +
+                                             "Must acquire mutator lock before calling update()" );
+        }
+
+        synchronized( this )
+        {
+            try
+            {
+                log.update( o, true );
+                updateCount++;
+                server.updatePerformed( updateCount );
+            }
+            catch( IOException e )
+            {
+                // $$$ should probably be propagating this exception
+                logger.log( Level.WARNING, "IOException while updating log", e );
+            }
+        }
+    }
+
+    /**
+     * Generate a snapshot, will perform the necessary locking to ensure no
+     * threads are mutating the state of the server before creating the
+     * snapshot.
+     *
+     * @throws IOException
+     * @see ReliableLog#snapshot
+     */
+    void snapshot() throws IOException
+    {
+        if( log == null )
+        {
+            return;
+        }
+        try
+        {
+            // Using write lock because we want an exclusive lock
+            mutatorLock.writeLock();
+            updateCount = 0;
+
+            // Don't need to sync on this because
+            // mutatorLock.writeLock() gives us an exclusive lock
+            log.snapshot();
+        }
+        finally
+        {
+            // Using write lock because we want an exclusive lock
+            mutatorLock.writeUnlock();
+        }
+    }
+}

Added: incubator/river/jtsk/skunk/niclas1/services/norm/src/main/java/com/sun/jini/norm/ProxyVerifier.java
URL: http://svn.apache.org/viewvc/incubator/river/jtsk/skunk/niclas1/services/norm/src/main/java/com/sun/jini/norm/ProxyVerifier.java?rev=724975&view=auto
==============================================================================
--- incubator/river/jtsk/skunk/niclas1/services/norm/src/main/java/com/sun/jini/norm/ProxyVerifier.java (added)
+++ incubator/river/jtsk/skunk/niclas1/services/norm/src/main/java/com/sun/jini/norm/ProxyVerifier.java Tue Dec  9 21:11:39 2008
@@ -0,0 +1,145 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.sun.jini.norm;
+
+import com.sun.jini.landlord.ConstrainableLandlordLease;
+import com.sun.jini.landlord.Landlord;
+import com.sun.jini.landlord.LandlordProxyVerifier;
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.ObjectInputStream;
+import java.io.Serializable;
+import java.rmi.RemoteException;
+import net.jini.core.constraint.MethodConstraints;
+import net.jini.core.constraint.RemoteMethodControl;
+import net.jini.export.proxytrust.TrustEquivalence;
+import net.jini.id.Uuid;
+import net.jini.security.TrustVerifier;
+
+/**
+ * Defines a trust verifier for the smart proxies of a Norm server.
+ */
+final class ProxyVerifier implements Serializable, TrustVerifier
+{
+    private static final long serialVersionUID = 2;
+
+    /**
+     * The Norm server proxy.
+     *
+     * @serial
+     */
+    private final RemoteMethodControl serverProxy;
+
+    /**
+     * The unique ID for the Norm server.
+     *
+     * @serial
+     */
+    private final Uuid serverUuid;
+
+    /**
+     * Returns a verifier for the smart proxies of a Norm server with the
+     * specified proxy and unique ID.
+     *
+     * @param serverProxy the Norm server proxy
+     * @param serverUuid  the unique ID for the Norm server
+     * @throws UnsupportedOperationException if <code>serverProxy</code> does
+     *                                       not implement both {@link RemoteMethodControl} and {@link
+     *                                       TrustEquivalence}
+     */
+    ProxyVerifier( NormServer serverProxy, Uuid serverUuid )
+    {
+        if( !( serverProxy instanceof RemoteMethodControl ) )
+        {
+            throw new UnsupportedOperationException(
+                "Verifier requires service proxy to implement " +
+                "RemoteMethodControl" );
+        }
+        else if( !( serverProxy instanceof TrustEquivalence ) )
+        {
+            throw new UnsupportedOperationException(
+                "Verifier requires service proxy to implement " +
+                "TrustEquivalence" );
+        }
+        this.serverProxy = (RemoteMethodControl) serverProxy;
+        this.serverUuid = serverUuid;
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public boolean isTrustedObject( Object obj, TrustVerifier.Context ctx )
+        throws RemoteException
+    {
+        if( obj == null || ctx == null )
+        {
+            throw new NullPointerException( "Arguments must not be null" );
+        }
+        else if( obj instanceof ConstrainableLandlordLease )
+        {
+            return new LandlordProxyVerifier(
+                (Landlord) serverProxy, serverUuid ).isTrustedObject( obj, ctx );
+        }
+        RemoteMethodControl otherServerProxy;
+        if( obj instanceof SetProxy.ConstrainableSetProxy )
+        {
+            if( !isTrustedObject( ( (SetProxy) obj ).getRenewalSetLease(), ctx ) )
+            {
+                return false;
+            }
+            otherServerProxy =
+                (RemoteMethodControl) ( (AbstractProxy) obj ).server;
+        }
+        else if( obj instanceof AdminProxy.ConstrainableAdminProxy ||
+                 obj instanceof NormProxy.ConstrainableNormProxy )
+        {
+            if( !serverUuid.equals( ( (AbstractProxy) obj ).uuid ) )
+            {
+                return false;
+            }
+            otherServerProxy =
+                (RemoteMethodControl) ( (AbstractProxy) obj ).server;
+        }
+        else if( obj instanceof RemoteMethodControl )
+        {
+            otherServerProxy = (RemoteMethodControl) obj;
+        }
+        else
+        {
+            return false;
+        }
+        MethodConstraints mc = otherServerProxy.getConstraints();
+        TrustEquivalence trusted =
+            (TrustEquivalence) serverProxy.setConstraints( mc );
+        return trusted.checkTrustEquivalence( otherServerProxy );
+    }
+
+    /**
+     * Require server proxy to implement TrustEquivalence.
+     */
+    private void readObject( ObjectInputStream in )
+        throws IOException, ClassNotFoundException
+    {
+        in.defaultReadObject();
+        if( !( serverProxy instanceof TrustEquivalence ) )
+        {
+            throw new InvalidObjectException(
+                "serverProxy must implement TrustEquivalence" );
+        }
+    }
+}

Added: incubator/river/jtsk/skunk/niclas1/services/norm/src/main/java/com/sun/jini/norm/Queue.java
URL: http://svn.apache.org/viewvc/incubator/river/jtsk/skunk/niclas1/services/norm/src/main/java/com/sun/jini/norm/Queue.java?rev=724975&view=auto
==============================================================================
--- incubator/river/jtsk/skunk/niclas1/services/norm/src/main/java/com/sun/jini/norm/Queue.java (added)
+++ incubator/river/jtsk/skunk/niclas1/services/norm/src/main/java/com/sun/jini/norm/Queue.java Tue Dec  9 21:11:39 2008
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.sun.jini.norm;
+
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Simple thread-safe FIFO sequence.
+ *
+ * @author Sun Microsystems, Inc.
+ */
+class Queue
+{
+    /**
+     * List we actually store stuff in
+     */
+    final private List lst = Collections.synchronizedList( new LinkedList() );
+
+    /**
+     * Enqueue an item.
+     */
+    synchronized void enqueue( Object o )
+    {
+        lst.add( o );
+        notifyAll();
+    }
+
+    /**
+     * Block until the queue is non-empty and return the first item.
+     *
+     * @throws InterruptedException if the current thread is interrupted
+     *                              while the queue is waiting for an item to appear
+     */
+    synchronized Object dequeue() throws InterruptedException
+    {
+        while( lst.isEmpty() )
+        {
+            wait();
+        }
+
+        return lst.remove( 0 );
+    }
+}

Added: incubator/river/jtsk/skunk/niclas1/services/norm/src/main/java/com/sun/jini/norm/SetProxy.java
URL: http://svn.apache.org/viewvc/incubator/river/jtsk/skunk/niclas1/services/norm/src/main/java/com/sun/jini/norm/SetProxy.java?rev=724975&view=auto
==============================================================================
--- incubator/river/jtsk/skunk/niclas1/services/norm/src/main/java/com/sun/jini/norm/SetProxy.java (added)
+++ incubator/river/jtsk/skunk/niclas1/services/norm/src/main/java/com/sun/jini/norm/SetProxy.java Tue Dec  9 21:11:39 2008
@@ -0,0 +1,541 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.sun.jini.norm;
+
+import com.sun.jini.landlord.ConstrainableLandlordLease;
+import com.sun.jini.proxy.ConstrainableProxyUtil;
+import com.sun.jini.proxy.ThrowThis;
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.ObjectInputStream;
+import java.lang.reflect.Method;
+import java.rmi.MarshalledObject;
+import java.rmi.RemoteException;
+import java.util.LinkedList;
+import java.util.List;
+import net.jini.core.constraint.MethodConstraints;
+import net.jini.core.constraint.RemoteMethodControl;
+import net.jini.core.event.EventRegistration;
+import net.jini.core.event.RemoteEventListener;
+import net.jini.core.lease.Lease;
+import net.jini.export.proxytrust.ProxyTrustIterator;
+import net.jini.export.proxytrust.SingletonProxyTrustIterator;
+import net.jini.id.Uuid;
+import net.jini.io.MarshalledInstance;
+import net.jini.lease.LeaseRenewalSet;
+import net.jini.lease.LeaseUnmarshalException;
+
+/**
+ * Client side proxy for Norm's lease renewal sets.  Uses an object of
+ * type NormServer to communicate back to server.
+ *
+ * @author Sun Microsystems, Inc.
+ */
+class SetProxy extends AbstractProxy implements LeaseRenewalSet
+{
+    private static final long serialVersionUID = 2;
+
+    /**
+     * Lease for this set.
+     *
+     * @serial
+     */
+    final Lease ourLease;
+
+    /**
+     * Creates a lease set proxy, returning an instance that implements
+     * RemoteMethodControl if the server does.
+     *
+     * @param server the server proxy
+     * @param id     the ID of the lease set
+     * @param lease  the lease set's lease
+     */
+    static SetProxy create( NormServer server, Uuid id, Lease lease )
+    {
+        if( server instanceof RemoteMethodControl )
+        {
+            return new ConstrainableSetProxy( server, id, lease, null );
+        }
+        else
+        {
+            return new SetProxy( server, id, lease );
+        }
+    }
+
+    /**
+     * Simple constructor.
+     */
+    private SetProxy( NormServer server, Uuid id, Lease lease )
+    {
+        super( server, id );
+        if( lease == null )
+        {
+            throw new NullPointerException( "lease cannot be null" );
+        }
+        ourLease = lease;
+    }
+
+    /**
+     * Require fields to be non-null.
+     */
+    private void readObjectNoData() throws InvalidObjectException
+    {
+        throw new InvalidObjectException(
+            "server, uuid, and ourLease must be non-null" );
+    }
+
+    /**
+     * Require lease to be non-null.
+     */
+    private void readObject( ObjectInputStream in )
+        throws IOException, ClassNotFoundException
+    {
+        in.defaultReadObject();
+        if( ourLease == null )
+        {
+            throw new InvalidObjectException( "ourLease cannot be null" );
+        }
+    }
+
+    /* -- Implement LeaseRenewalSet -- */
+
+    // Inherit java doc from super type
+
+    public void renewFor( Lease leaseToRenew, long membershipDuration )
+        throws RemoteException
+    {
+        try
+        {
+            server2().renewFor( uuid, leaseToRenew, membershipDuration,
+                                Lease.FOREVER );
+        }
+        catch( ThrowThis e )
+        {
+            // The server wants to throw some remote exception
+            e.throwRemoteException();
+        }
+    }
+
+    // Inherit java doc from super type
+    public void renewFor( Lease leaseToRenew, long membershipDuration,
+                          long renewDuration )
+        throws RemoteException
+    {
+        try
+        {
+            server.renewFor( uuid, leaseToRenew, membershipDuration,
+                             renewDuration );
+        }
+        catch( ThrowThis e )
+        {
+            // The server wants to throw some remote exception
+            e.throwRemoteException();
+        }
+    }
+
+    // Inherit java doc from super type
+    public Lease remove( Lease leaseToRemove ) throws RemoteException
+    {
+        try
+        {
+            return server.remove( uuid, leaseToRemove );
+        }
+        catch( ThrowThis e )
+        {
+            // The server wants to throw some remote exception
+            e.throwRemoteException();
+            // Need this because compiler does not know that
+            // throwRemoteException is not going to return
+            return null;
+        }
+    }
+
+    // Inherit java doc from super type
+    public Lease[] getLeases() throws LeaseUnmarshalException, RemoteException
+    {
+        try
+        {
+            GetLeasesResult result = server.getLeases( uuid );
+            MarshalledInstance mls[] = result.marshalledLeases;
+
+            if( mls == null || mls.length == 0 )
+            {
+                return new Lease[0];
+            }
+
+            final List leases = new LinkedList();
+            final List problems = new LinkedList();
+            final List exceptions = new LinkedList();
+            for( int i = 0; i < mls.length; i++ )
+            {
+                Lease l;
+                final MarshalledInstance ml = mls[ i ];
+                try
+                {
+                    l = (Lease) ml.get( result.verifyCodebaseIntegrity() );
+                    leases.add( l );
+                }
+                catch( Throwable t )
+                {
+                    problems.add( ml.convertToMarshalledObject() );
+                    exceptions.add( t );
+                }
+            }
+
+            final Lease[] rslt =
+                (Lease[]) leases.toArray( new Lease[leases.size()] );
+
+            if( problems.isEmpty() )
+            {
+                return rslt;
+            }
+
+            final MarshalledObject sml[] =
+                (MarshalledObject[]) problems.toArray(
+                    new MarshalledObject[problems.size()] );
+            final Throwable es[] =
+                (Throwable[]) exceptions.toArray(
+                    new Throwable[exceptions.size()] );
+
+            throw new LeaseUnmarshalException( "Problem unmarshalling lease(s)",
+                                               rslt, sml, es );
+
+        }
+        catch( ThrowThis e )
+        {
+            // The server wants to throw some remote exception
+            e.throwRemoteException();
+            // Need this because compiler does not know that
+            // throwRemoteException is not going to return
+            return null;
+        }
+    }
+
+    // Inherit java doc from super type
+    public EventRegistration setExpirationWarningListener(
+        RemoteEventListener listener,
+        long minWarning,
+        MarshalledObject handback )
+        throws RemoteException
+    {
+        // Do some client side error checking
+        if( listener == null )
+        {
+            throw new NullPointerException(
+                "LeaseRenewalSet.setExpirationWarningListener:Must " +
+                "pass a non-null listener" );
+        }
+
+        try
+        {
+            return server.setExpirationWarningListener( uuid,
+                                                        listener, minWarning, handback );
+        }
+        catch( ThrowThis e )
+        {
+            // The server wants to throw some remote exception
+            e.throwRemoteException();
+            // Need this because compiler does not know that
+            // throwRemoteException is not going to return
+            return null;
+        }
+    }
+
+    // Inherit java doc from super type
+    public void clearExpirationWarningListener() throws RemoteException
+    {
+        try
+        {
+            server2().setExpirationWarningListener(
+                uuid, null, NormServer.NO_LISTENER, null );
+        }
+        catch( ThrowThis e )
+        {
+            // The server wants to throw some remote exception
+            e.throwRemoteException();
+        }
+    }
+
+    // Inherit java doc from super type
+    public EventRegistration setRenewalFailureListener(
+        RemoteEventListener listener,
+        MarshalledObject handback )
+        throws RemoteException
+    {
+        // Do some client side error checking
+        if( listener == null )
+        {
+            throw new NullPointerException(
+                "LeaseRenewalSet.setRenewalFailureListener:Must " +
+                "pass a non-null listener" );
+        }
+
+        try
+        {
+            return server.setRenewalFailureListener( uuid, listener, handback );
+        }
+        catch( ThrowThis e )
+        {
+            // The server wants to throw some remote exception
+            e.throwRemoteException();
+            // Need this because compiler does not know that
+            // throwRemoteException is not going to return
+            return null;
+        }
+    }
+
+
+    // Inherit java doc from super type
+    public void clearRenewalFailureListener() throws RemoteException
+    {
+        try
+        {
+            server2().setRenewalFailureListener( uuid, null, null );
+        }
+        catch( ThrowThis e )
+        {
+            // The server wants to throw some remote exception
+            e.throwRemoteException();
+        }
+    }
+
+    /**
+     * Returns a second server proxy for use by methods that represent a second
+     * client-side method for a single server-side method.  The distinction
+     * only matters for the constrainable subclass, where the different server
+     * proxies need different client constraints.
+     */
+    NormServer server2()
+    {
+        return server;
+    }
+
+    // Inherit java doc from super type
+    public Lease getRenewalSetLease()
+    {
+        return ourLease;
+    }
+
+    /**
+     * Defines a subclass of SetProxy that implements RemoteMethodControl.
+     */
+    static final class ConstrainableSetProxy extends SetProxy
+        implements RemoteMethodControl
+    {
+        private static final long serialVersionUID = 1;
+
+        /**
+         * Mappings from client to server methods, using the client method with
+         * more arguments for each server method when more than one client
+         * method maps to a single server method.
+         */
+        private static final Method[] methodMap1;
+
+        static
+        {
+            try
+            {
+                methodMap1 = new Method[]{
+                    LeaseRenewalSet.class.getMethod(
+                        "renewFor",
+                        new Class[]{ Lease.class, long.class, long.class } ),
+                    NormServer.class.getMethod(
+                        "renewFor",
+                        new Class[]{ Uuid.class, Lease.class, long.class,
+                                     long.class } ),
+                    LeaseRenewalSet.class.getMethod(
+                        "remove", new Class[]{ Lease.class } ),
+                    NormServer.class.getMethod(
+                        "remove",
+                        new Class[]{ Uuid.class, Lease.class } ),
+                    LeaseRenewalSet.class.getMethod(
+                        "getLeases", new Class[]{ } ),
+                    NormServer.class.getMethod(
+                        "getLeases", new Class[]{ Uuid.class } ),
+                    LeaseRenewalSet.class.getMethod(
+                        "setExpirationWarningListener",
+                        new Class[]{ RemoteEventListener.class,
+                                     long.class, MarshalledObject.class } ),
+                    NormServer.class.getMethod(
+                        "setExpirationWarningListener",
+                        new Class[]{ Uuid.class, RemoteEventListener.class,
+                                     long.class, MarshalledObject.class } ),
+                    LeaseRenewalSet.class.getMethod(
+                        "setRenewalFailureListener",
+                        new Class[]{ RemoteEventListener.class,
+                                     MarshalledObject.class } ),
+                    NormServer.class.getMethod(
+                        "setRenewalFailureListener",
+                        new Class[]{ Uuid.class, RemoteEventListener.class,
+                                     MarshalledObject.class } )
+                };
+            }
+            catch( NoSuchMethodException e )
+            {
+                throw new NoSuchMethodError( e.getMessage() );
+            }
+        }
+
+        /**
+         * Second set of mappings from client to server method names, for
+         * server methods with a second associated client method.
+         */
+        private static final Method[] methodMap2;
+
+        static
+        {
+            try
+            {
+                methodMap2 = new Method[]{
+                    LeaseRenewalSet.class.getMethod(
+                        "renewFor",
+                        new Class[]{ Lease.class, long.class } ),
+                    NormServer.class.getMethod(
+                        "renewFor",
+                        new Class[]{ Uuid.class, Lease.class, long.class,
+                                     long.class } ),
+                    LeaseRenewalSet.class.getMethod(
+                        "clearExpirationWarningListener", new Class[]{ } ),
+                    NormServer.class.getMethod(
+                        "setExpirationWarningListener",
+                        new Class[]{ Uuid.class, RemoteEventListener.class,
+                                     long.class, MarshalledObject.class } ),
+                    LeaseRenewalSet.class.getMethod(
+                        "clearRenewalFailureListener", new Class[]{ } ),
+                    NormServer.class.getMethod(
+                        "setRenewalFailureListener",
+                        new Class[]{ Uuid.class, RemoteEventListener.class,
+                                     MarshalledObject.class } )
+                };
+            }
+            catch( NoSuchMethodException e )
+            {
+                throw new NoSuchMethodError( e.getMessage() );
+            }
+        }
+
+        /**
+         * The client constraints placed on this proxy or <code>null</code>.
+         *
+         * @serial
+         */
+        private MethodConstraints methodConstraints;
+
+        /**
+         * A second inner proxy to use when the client constraints for
+         * different smart proxy methods implemented by the same inner proxy
+         * methods have different constraints.  This proxy is used for the
+         * renewFor(Lease, long), clearExpirationWarningListener, and
+         * clearRenewalFailureListener methods.
+         */
+        private transient NormServer server2;
+
+        /**
+         * Creates an instance of this class.
+         */
+        ConstrainableSetProxy( NormServer server,
+                               Uuid id,
+                               Lease lease,
+                               MethodConstraints methodConstraints )
+        {
+            super( constrainServer( server, methodConstraints, methodMap1 ),
+                   id, lease );
+            if( !( lease instanceof ConstrainableLandlordLease ) )
+            {
+                throw new IllegalArgumentException(
+                    "lease must be a ConstrainableLandlordLease" );
+            }
+            this.methodConstraints = methodConstraints;
+            server2 = constrainServer( server, methodConstraints, methodMap2 );
+        }
+
+        /**
+         * Verifies that ourLease is a ConstrainableLandlordLease, and that
+         * server implements RemoteMethodControl and has the appropriate method
+         * constraints.  Also sets the server2 field.
+         */
+        private void readObject( ObjectInputStream s )
+            throws IOException, ClassNotFoundException
+        {
+            s.defaultReadObject();
+            if( !( server instanceof RemoteMethodControl ) )
+            {
+                throw new InvalidObjectException(
+                    "server does not implement RemoteMethodControl" );
+            }
+            else if( !( ourLease instanceof ConstrainableLandlordLease ) )
+            {
+                throw new InvalidObjectException(
+                    "ourLease is not a ConstrainableLandlordLease" );
+            }
+            ConstrainableProxyUtil.verifyConsistentConstraints(
+                methodConstraints, server, methodMap1 );
+            server2 = constrainServer( server, methodConstraints, methodMap2 );
+        }
+
+
+        /**
+         * Returns a copy of the server proxy with the specified client
+         * constraints and methods mapping.
+         */
+        private static NormServer constrainServer(
+            NormServer server,
+            MethodConstraints methodConstraints,
+            Method[] mappings )
+        {
+            return (NormServer) ( (RemoteMethodControl) server ).setConstraints(
+                ConstrainableProxyUtil.translateConstraints(
+                    methodConstraints, mappings ) );
+        }
+
+        /**
+         * inherit javadoc
+         */
+        public RemoteMethodControl setConstraints(
+            MethodConstraints constraints )
+        {
+            return new ConstrainableSetProxy(
+                server, uuid, ourLease, constraints );
+        }
+
+        /**
+         * inherit javadoc
+         */
+        public MethodConstraints getConstraints()
+        {
+            return methodConstraints;
+        }
+
+        /**
+         * Returns the second server proxy.
+         */
+        NormServer server2()
+        {
+            return server2;
+        }
+
+        /**
+         * Returns a proxy trust iterator that supplies the server, for use by
+         * ProxyTrustVerifier.
+         */
+        private ProxyTrustIterator getProxyTrustIterator()
+        {
+            return new SingletonProxyTrustIterator(server);
+	}
+    }
+}

Added: incubator/river/jtsk/skunk/niclas1/services/norm/src/main/java/com/sun/jini/norm/StoreException.java
URL: http://svn.apache.org/viewvc/incubator/river/jtsk/skunk/niclas1/services/norm/src/main/java/com/sun/jini/norm/StoreException.java?rev=724975&view=auto
==============================================================================
--- incubator/river/jtsk/skunk/niclas1/services/norm/src/main/java/com/sun/jini/norm/StoreException.java (added)
+++ incubator/river/jtsk/skunk/niclas1/services/norm/src/main/java/com/sun/jini/norm/StoreException.java Tue Dec  9 21:11:39 2008
@@ -0,0 +1,102 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.sun.jini.norm;
+
+import java.io.PrintStream;
+import java.io.PrintWriter;
+
+/**
+ * Base class for exceptions thrown by PersistantStore.
+ *
+ * @author Sun Microsystems, Inc.
+ */
+class StoreException extends Exception
+{
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * The exception (if any) that triggered the store exception.  This
+     * may be <code>null</code>.
+     *
+     * @serial
+     */
+    final Throwable nestedException;
+
+    /**
+     * Create a store exception, forwarding a string to the superclass
+     * constructor.
+     *
+     * @param str a detailed message for the exception
+     */
+    StoreException( String str )
+    {
+        super( str );
+        nestedException = null;
+    }
+
+    /**
+     * Create an exception, forwarding a string to the
+     * superclass constructor.
+     *
+     * @param str a detailed message for the exception
+     * @param ex  root cause for the exception, may be <code>null</code>
+     */
+    StoreException( String str, Throwable ex )
+    {
+        super( str );
+        nestedException = ex;
+    }
+
+    /**
+     * Print the stack trace of this exception, plus that of the nested
+     * exception, if any.
+     */
+    public void printStackTrace()
+    {
+        printStackTrace( System.err );
+    }
+
+    /**
+     * Print the stack trace of this exception, plus that of the nested
+     * exception, if any.
+     */
+    public void printStackTrace( PrintStream out )
+    {
+        super.printStackTrace( out );
+        if( nestedException != null )
+        {
+            out.println( "nested exception:" );
+            nestedException.printStackTrace( out );
+        }
+    }
+
+    /**
+     * Print the stack trace of this exception, plus that of the nested
+     * exception, if any.
+     */
+    public void printStackTrace( PrintWriter out )
+    {
+        super.printStackTrace( out );
+        if( nestedException != null )
+        {
+            out.println( "nested exception:" );
+            nestedException.printStackTrace( out );
+        }
+    }
+}
+

Added: incubator/river/jtsk/skunk/niclas1/services/norm/src/main/java/com/sun/jini/norm/TransientNormServerImpl.java
URL: http://svn.apache.org/viewvc/incubator/river/jtsk/skunk/niclas1/services/norm/src/main/java/com/sun/jini/norm/TransientNormServerImpl.java?rev=724975&view=auto
==============================================================================
--- incubator/river/jtsk/skunk/niclas1/services/norm/src/main/java/com/sun/jini/norm/TransientNormServerImpl.java (added)
+++ incubator/river/jtsk/skunk/niclas1/services/norm/src/main/java/com/sun/jini/norm/TransientNormServerImpl.java Tue Dec  9 21:11:39 2008
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.sun.jini.norm;
+
+import com.sun.jini.start.LifeCycle;
+import com.sun.jini.start.ServiceStarter;
+
+/**
+ * Provides a transient implementation of NormServer.
+ *
+ * @author Sun Microsystems, Inc.
+ * @since 2.0
+ */
+class TransientNormServerImpl extends NormServerBaseImpl
+{
+
+    /**
+     * Provides a constructor for a transient implementation of NormServer
+     * suitable for use with {@link ServiceStarter}.
+     *
+     * @param configOptions the arguments to use when creating the
+     *                      configuration for the server
+     * @param lifeCycle     object to notify when this service is destroyed, or
+     *                      <code>null</code>
+     * @throws Exception if there is a problem creating the server
+     */
+    TransientNormServerImpl( String[] configOptions, LifeCycle lifeCycle )
+        throws Exception
+    {
+        super( false /* persistent */ );
+        init( configOptions, lifeCycle );
+    }
+}

Added: incubator/river/jtsk/skunk/niclas1/services/norm/src/main/java/com/sun/jini/norm/UIDGenerator.java
URL: http://svn.apache.org/viewvc/incubator/river/jtsk/skunk/niclas1/services/norm/src/main/java/com/sun/jini/norm/UIDGenerator.java?rev=724975&view=auto
==============================================================================
--- incubator/river/jtsk/skunk/niclas1/services/norm/src/main/java/com/sun/jini/norm/UIDGenerator.java (added)
+++ incubator/river/jtsk/skunk/niclas1/services/norm/src/main/java/com/sun/jini/norm/UIDGenerator.java Tue Dec  9 21:11:39 2008
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.sun.jini.norm;
+
+/**
+ * Utility class for generating locally unique IDs.
+ *
+ * @author Sun Microsystems, Inc.
+ */
+class UIDGenerator
+{
+    /**
+     * Value of the next ID
+     */
+    private long nextID = 0;
+
+    /**
+     * Generate ID, this method performs appropriate locking to
+     * ensure the returned ID is unique.
+     */
+    synchronized long newID()
+    {
+        return nextID++;
+    }
+
+    /**
+     * Used during log recovery to update the generator that a given ID
+     * is in use.  This method performs no locking.
+     *
+     * @param ID ID that is in use
+     */
+    void inUse( long ID )
+    {
+        if( ID >= nextID )
+        {
+            nextID = ID + 1;
+        }
+    }
+}

Added: incubator/river/jtsk/skunk/niclas1/services/norm/src/main/java/com/sun/jini/norm/build.xml
URL: http://svn.apache.org/viewvc/incubator/river/jtsk/skunk/niclas1/services/norm/src/main/java/com/sun/jini/norm/build.xml?rev=724975&view=auto
==============================================================================
--- incubator/river/jtsk/skunk/niclas1/services/norm/src/main/java/com/sun/jini/norm/build.xml (added)
+++ incubator/river/jtsk/skunk/niclas1/services/norm/src/main/java/com/sun/jini/norm/build.xml Tue Dec  9 21:11:39 2008
@@ -0,0 +1,258 @@
+<!--
+ ! Licensed to the Apache Software Foundation (ASF) under one
+ ! or more contributor license agreements.  See the NOTICE file
+ ! distributed with this work for additional information
+ ! regarding copyright ownership. The ASF licenses this file
+ ! to you under the Apache License, Version 2.0 (the
+ ! "License"); you may not use this file except in compliance
+ ! with the License. You may obtain a copy of the License at
+ ! 
+ !      http://www.apache.org/licenses/LICENSE-2.0
+ ! 
+ ! Unless required by applicable law or agreed to in writing, software
+ ! distributed under the License is distributed on an "AS IS" BASIS,
+ ! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ! See the License for the specific language governing permissions and
+ ! limitations under the License.
+ !-->
+
+<project name="norm" basedir="." default="all">
+
+  <!-- ################################################################ -->
+  <!-- ##								-->
+  <!-- ## ENVIRONMENT SETTINGS						-->
+  <!-- ##								-->
+  <!-- ################################################################ -->
+
+  <property name="top" location="../../../../.."/>
+
+  <property name="pkg-path" value="com/sun/jini/${ant.project.name}"/>
+
+  <!-- ##								-->
+  <!-- ## Set java-source for use with the javac task:			-->
+  <!-- ##								-->
+
+  <property name="java-source" value="${pkg-path}/**/*.java"/>
+
+  <import file="${top}/build_common.xml"/>
+
+
+  <!-- ################################################################ -->
+  <!-- ##								-->
+  <!-- ## TARGET: all							-->
+  <!-- ##								-->
+  <!-- ################################################################ -->
+
+  <target name="all"
+          description=""
+          depends="compile,
+		   this.stubs">
+
+  </target>
+
+
+  <!-- ################################################################ -->
+  <!-- ##                                                               -->
+  <!-- ## TARGET: clean                                                 -->
+  <!-- ##                                                               -->
+  <!-- ################################################################ -->
+
+  <target name="clean"
+          description="Removes all files and dirs created by the build."
+          depends="clean.jre.ext">
+
+    <delete dir="${build.classes}/${pkg-path}" quiet="true"/>
+
+  </target>
+
+
+  <!-- ################################################################ -->
+  <!-- ##								-->
+  <!-- ## TARGET: this.jars						-->
+  <!-- ##								-->
+  <!-- ################################################################ -->
+
+  <target name="this.jars"
+          description=""
+          depends="norm.jar,
+		   norm-dl.jar">
+
+  </target>
+
+
+  <!-- ################################################################ -->
+  <!-- ##								-->
+  <!-- ## TARGET: norm.jar						-->
+  <!-- ##								-->
+  <!-- ################################################################ -->
+
+  <target name="norm.jar"
+          depends="tools">
+
+    <property name="norm.deps" location="${build.deps}/norm.deps"/>
+
+    <!-- ##								-->
+    <!-- ## Run ClassDep.						-->
+    <!-- ##								-->
+
+    <java classname="com.sun.jini.tool.ClassDep"
+          failonerror="true"
+          output="${norm.deps}">
+
+      <classpath refid="path.classdep"/>
+      <arg value="-cp"/>
+      <arg path="${build.classes}"/>
+      <arg value="-files"/>
+      <arg line="${jskprivate.include}"/>
+
+      <arg line="-in com.sun.jini.norm"/>
+
+      <arg value="com.sun.jini.norm.ActivatableNormServerImpl"/>
+      <arg value="com.sun.jini.norm.NormPermission"/>
+      <arg value="com.sun.jini.norm.NormServerBaseImpl_Stub"/>
+      <arg value="com.sun.jini.norm.PersistentNormServerImpl"/>
+      <arg value="com.sun.jini.norm.TransientNormServerImpl"/>
+      <arg value="com.sun.jini.reliableLog.LogException"/>
+
+    </java>
+
+    <!-- ##								-->
+    <!-- ## Generate the jar file.					-->
+    <!-- ##								-->
+
+    <delete file="${build.lib}/norm.jar" quiet="true"/>
+
+    <jar destfile="${build.lib}/norm.jar"
+         index="false"
+         manifest="${src.jini.manifest}/norm.mf">
+
+      <fileset dir="${build.classes}" includesfile="${norm.deps}"/>
+
+    </jar>
+
+    <!-- ##								-->
+    <!-- ## Generate the Preferred List					-->
+    <!-- ##								-->
+
+    <preferredlistgen>
+
+      <plg-elements>
+
+        <arg line="-cp"/>
+        <arg path="${build.classes}"/>
+
+        <arg line="-jar"/>
+        <arg path="${build.lib}/norm.jar"/>
+
+        <arg line="-default true"/>
+
+      </plg-elements>
+
+    </preferredlistgen>
+
+  </target>
+
+
+  <!-- ################################################################ -->
+  <!-- ##								-->
+  <!-- ## TARGET: norm-dl.jar						-->
+  <!-- ##								-->
+  <!-- ################################################################ -->
+
+  <target name="norm-dl.jar"
+          depends="tools">
+
+
+    <property name="norm-dl.deps" location="${build.deps}/norm-dl.deps"/>
+
+    <!-- ##								-->
+    <!-- ## Run ClassDep.						-->
+    <!-- ##								-->
+
+    <java classname="com.sun.jini.tool.ClassDep"
+          failonerror="true"
+          output="${norm-dl.deps}">
+
+      <classpath refid="path.classdep"/>
+      <arg value="-cp"/>
+      <arg path="${build.classes}"/>
+      <arg value="-files"/>
+      <arg line="${jskprivate.include}"/>
+
+      <arg line="-in com.sun.jini.norm"/>
+
+      <arg value="com.sun.jini.lease.BasicRenewalFailureEvent"/>
+      <arg value="com.sun.jini.lookup.entry.BasicServiceType"/>
+      <arg value="com.sun.jini.norm.CorruptedStoreException"/>
+      <arg value="com.sun.jini.norm.InternalNormException"/>
+      <arg value="com.sun.jini.norm.NormPermission"/>
+      <arg value="com.sun.jini.norm.NormServerBaseImpl_Stub"/>
+      <arg value="com.sun.jini.norm.ProxyVerifier"/>
+      <arg value="com.sun.jini.reliableLog.LogException"/>
+      <arg value="com.sun.jini.start.ServiceProxyAccessor"/>
+      <arg value="net.jini.lookup.entry.ServiceInfo"/>
+
+    </java>
+
+    <!-- ##								-->
+    <!-- ## Generate the jar file.					-->
+    <!-- ##								-->
+
+    <delete file="${build.lib-dl}/norm-dl.jar" quiet="true"/>
+
+    <jar destfile="${build.lib-dl}/norm-dl.jar" index="false">
+
+      <fileset dir="${build.classes}" includesfile="${norm-dl.deps}"/>
+
+    </jar>
+
+    <!-- ##								-->
+    <!-- ## Generate the Preferred List					-->
+    <!-- ##								-->
+
+    <preferredlistgen>
+
+      <plg-elements>
+
+        <arg line="-cp"/>
+        <arg path="${build.lib}/jsk-platform.jar"/>
+
+        <arg line="-jar"/>
+        <arg path="${build.lib-dl}/norm-dl.jar"/>
+
+        <arg line="-jar"/>
+        <arg path="${build.lib-dl}/jsk-dl.jar"/>
+
+        <arg line="-proxy com.sun.jini.norm.AbstractProxy"/>
+        <arg line="-proxy com.sun.jini.norm.AdminProxy"/>
+        <arg line="-proxy com.sun.jini.norm.NormProxy"/>
+        <arg line="-proxy com.sun.jini.norm.SetProxy"/>
+
+      </plg-elements>
+
+    </preferredlistgen>
+
+  </target>
+
+
+  <!-- ################################################################ -->
+  <!-- ##								-->
+  <!-- ## TARGET: this.stubs						-->
+  <!-- ##								-->
+  <!-- ################################################################ -->
+
+  <target name="this.stubs"
+          description="Builds the RMI stubs for ${ant.project.name}."
+          depends="compile">
+
+    <rmic base="${build.classes}" stubversion="1.2">
+
+      <classpath refid="path.jini"/>
+      <include name="com/sun/jini/norm/NormServerBaseImpl.class"/>
+
+    </rmic>
+
+  </target>
+
+</project>
+

Added: incubator/river/jtsk/skunk/niclas1/services/norm/src/main/java/com/sun/jini/norm/event/EventFactory.java
URL: http://svn.apache.org/viewvc/incubator/river/jtsk/skunk/niclas1/services/norm/src/main/java/com/sun/jini/norm/event/EventFactory.java?rev=724975&view=auto
==============================================================================
--- incubator/river/jtsk/skunk/niclas1/services/norm/src/main/java/com/sun/jini/norm/event/EventFactory.java (added)
+++ incubator/river/jtsk/skunk/niclas1/services/norm/src/main/java/com/sun/jini/norm/event/EventFactory.java Tue Dec  9 21:11:39 2008
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.sun.jini.norm.event;
+
+import java.rmi.MarshalledObject;
+import net.jini.core.event.RemoteEvent;
+
+/**
+ * Factory interface for creating
+ * <code>net.jini.core.event.RemoteEvent</code>.  An object of this
+ * type is passed to each call of <code>EventType.sendEvent</code> and
+ * is used by the <code>EventType</code> object to generate the
+ * concrete <code>RemoteEvent</code> associated with a given event
+ * occurrence on demand.  Providing a factory to <code>sendEvent</code>
+ * instead of an actual <code>RemoteEvent</code> object allows
+ * <code>eventType</code> object to send an event originally
+ * intended for one listener to another.
+ *
+ * @author Sun Microsystems, Inc.
+ * @see EventType
+ * @see EventType#sendEvent
+ */
+public interface EventFactory
+{
+    /**
+     * Create the concrete <code>RemoteEvent</code> for the associated
+     * event occurrence.  Implementations should allow for the
+     * possibility of being called with the same argument more that
+     * once, especially the same eventID and seqNum.  The factory
+     * should not mutate the event after it returns it.
+     * <p>
+     * The caller will own no locks when calling this method.
+     *
+     * @param eventID  the event ID the new event should have
+     * @param seqNum   the sequence number the new event object should have
+     * @param handback the handback the new event object should have
+     * @return the new event object
+     */
+    public RemoteEvent createEvent( long eventID,
+                                    long seqNum,
+                                    MarshalledObject handback );
+}

Added: incubator/river/jtsk/skunk/niclas1/services/norm/src/main/java/com/sun/jini/norm/event/EventType.java
URL: http://svn.apache.org/viewvc/incubator/river/jtsk/skunk/niclas1/services/norm/src/main/java/com/sun/jini/norm/event/EventType.java?rev=724975&view=auto
==============================================================================
--- incubator/river/jtsk/skunk/niclas1/services/norm/src/main/java/com/sun/jini/norm/event/EventType.java (added)
+++ incubator/river/jtsk/skunk/niclas1/services/norm/src/main/java/com/sun/jini/norm/event/EventType.java Tue Dec  9 21:11:39 2008
@@ -0,0 +1,575 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.sun.jini.norm.event;
+
+import com.sun.jini.constants.ThrowableConstants;
+import com.sun.jini.logging.Levels;
+import com.sun.jini.thread.RetryTask;
+import com.sun.jini.thread.TaskManager;
+import com.sun.jini.thread.WakeupManager;
+import java.io.IOException;
+import java.io.Serializable;
+import java.rmi.MarshalledObject;
+import java.rmi.RemoteException;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import net.jini.core.event.RemoteEvent;
+import net.jini.core.event.RemoteEventListener;
+import net.jini.security.ProxyPreparer;
+
+/**
+ * Representation of an event type the supports a single registrant.
+ * The registrant, event ID, and event sequence number information
+ * portions of this object are preserved when serialized.  The send
+ * monitor, and currently scheduled event sends are not.
+ *
+ * @author Sun Microsystems, Inc.
+ */
+// $$$ I am not sure if this class does too much locking, or too little.
+// It does too little in that it does not do any locking during serialization
+// It does too much in that Norm's current locking discipline means that for
+// the most part this class does not have to worry about multiple threads
+// of control entering at one time.
+// Before we make this a general utility we have to re-think the locking
+// strategy.
+public class EventType implements Serializable
+{
+    private static final long serialVersionUID = 2;
+
+    /**
+     * Logger for logging messages for this class
+     */
+    private static final Logger logger = Logger.getLogger( "com.sun.jini.norm" );
+
+    /**
+     * Listener registered for events of this type.  Stored in
+     * marshalled form so object the <code>EventType</code> object can
+     * be recovered even if the listener's codebase is not available.
+     * If this field is <code>null</code>, <code>listener</code> and
+     * <code>handback</code> will be also.
+     *
+     * @serial
+     */
+    private MarshalledObject marshalledListener;
+
+    /**
+     * Transient cache of listener in unmarshalled form
+     */
+    private transient RemoteEventListener listener;
+
+    /**
+     * The proxy preparer to use to prepare a newly unmarshalled listener, or
+     * null if this instance was created using an already prepared listener,
+     * which is how instances are created initially.
+     */
+    private transient ProxyPreparer recoveredListenerPreparer;
+
+    /**
+     * Handback object associated with current listener.
+     *
+     * @serial
+     */
+    private MarshalledObject handback;
+
+    /**
+     * Sequence number of the current listener/handback pair, incremented
+     * every time a new listener is set (even if the objects
+     * are equivalent)
+     *
+     * @serial
+     */
+    private long registrationNumber;
+
+    /**
+     * Last event sequence number we used
+     *
+     * @serial
+     */
+    private long lastSeqNum;
+
+    /**
+     * Our event ID
+     *
+     * @serial
+     */
+    private long evID;
+
+    /**
+     * Object we check with to ensure leases have not expired and notify
+     * when we get a definite exception during an event send attempt.
+     * If this field is <code>null</code> generator will be also.
+     */
+    private transient SendMonitor monitor;
+
+    /**
+     * Event type generator that created us. If this field is
+     * <code>null</code> monitor will be also.
+     */
+    private transient EventTypeGenerator generator;
+
+    /**
+     * Simple constructor.  Initially the last sequence number is set to 0.
+     *
+     * @param generator EventTypeGenerator that is creating this event type
+     * @param monitor   Object which is to monitor the sending of events
+     *                  of this type
+     * @param evID      event ID of this event type
+     * @param listener  the listener events of this type should go to
+     * @param handback  the object that should be passed to listener
+     *                  as part of the event
+     * @throws IOException if the listener cannot be serialized
+     */
+    EventType( EventTypeGenerator generator, SendMonitor monitor, long evID,
+               RemoteEventListener listener, MarshalledObject handback )
+        throws IOException
+    {
+        if( generator == null )
+        {
+            throw new NullPointerException( "EventType(): Must create event " +
+                                            "type objects with a non-null generator" );
+        }
+
+        if( monitor == null )
+        {
+            throw new NullPointerException( "EventType(): Must create event " +
+                                            "type objects with a non-null monitor" );
+        }
+
+        this.generator = generator;
+        this.monitor = monitor;
+        this.evID = evID;
+        setLastSequenceNumber( 0 );
+        setListener( listener, handback );
+    }
+
+    /**
+     * Utility method to null out listener
+     */
+    private void clearListener()
+    {
+        listener = null;
+        handback = null;
+        marshalledListener = null;
+    }
+
+    /**
+     * (Re)set the listener for this type of event.  Any pending
+     * events that have not yet been sent will be sent to the new
+     * listener, passing the new handback.  Setting the listener to
+     * <code>null</code> will cancel the sending of all pending
+     * events.
+     *
+     * @param listener the listener events of this type should go to
+     * @param handback the object that should be passed to listener
+     *                 as part of the event
+     * @throws IOException if listener cannot be serialized
+     */
+    public synchronized void setListener( RemoteEventListener listener,
+                                          MarshalledObject handback )
+        throws IOException
+    {
+        registrationNumber++;
+
+        if( listener == null )
+        {
+            clearListener();
+        }
+        else
+        {
+            marshalledListener = new MarshalledObject( listener );
+            this.listener = listener;
+            this.handback = handback;
+        }
+    }
+
+    /**
+     * Returns <code>true</code> if there is a listener registered for this
+     * event type.
+     */
+    public boolean haveListener()
+    {
+        return marshalledListener != null;
+    }
+
+    /**
+     * Convince method to get the listener.
+     *
+     * @return the listener, or <code>null</code> if the listener can't be
+     *         unpacked or prepared, or there is no listener
+     */
+    private RemoteEventListener getListener()
+    {
+        if( !haveListener() )
+        {
+            return null;
+        }
+
+        if( listener != null )
+        {
+            return listener;
+        }
+
+        // There is a listener, but it is not unpacked yet, try to unpack
+        RemoteEventListener unpreparedListener = null;
+        try
+        {
+            unpreparedListener =
+                (RemoteEventListener) marshalledListener.get();
+        }
+        catch( IOException e )
+        {
+            logger.log( Levels.HANDLED,
+                        "Problem unmarshalling listener -- will retry later",
+                        e );
+            // $$$ is this really the right thing to do?
+            // we probably really have a corrupted marshalledListener here
+        }
+        catch( ClassNotFoundException e )
+        {
+            logger.log( Levels.HANDLED,
+                        "Problem unmarshalling listener -- will retry later",
+                        e );
+        }
+
+        if( unpreparedListener != null )
+        {
+            // Prepare the listener
+            try
+            {
+                listener = (RemoteEventListener)
+                    recoveredListenerPreparer.prepareProxy( unpreparedListener );
+            }
+            catch( RemoteException e )
+            {
+                logger.log( Levels.HANDLED,
+                            "Problem preparing listener -- will retry later",
+                            e );
+            }
+            catch( SecurityException e )
+            {
+                logger.log( Levels.HANDLED,
+                            "Problem preparing listener -- will retry later",
+                            e );
+            }
+        }
+
+        return listener;
+    }
+
+    /**
+     * Atomically clear the current registration if its sequence
+     * number matches the passed in sequence number.  If the
+     * replacement occurs it will have the same effect as calling
+     * <code>setListener(null, null)</code>.
+     * <p>
+     * Can be used by code that needs to remove event registrations in
+     * response to exceptions thrown during event delivery without
+     * risking clobbering new registrations.
+     *
+     * @param oldSequenceNumber sequence number of the
+     *                          registration that had a problem
+     * @return <code>true</code> if the state of the object was
+     *         changed and <code>false</code> otherwise
+     * @see EventType#setListener
+     */
+    public synchronized boolean clearListenerIfSequenceMatch(
+        long oldSequenceNumber )
+    {
+        if( oldSequenceNumber == registrationNumber )
+        {
+            clearListener();
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * Set the object's notion of the last sequence number.  The next event
+     * scheduled to be sent will have a sequence number one greater than
+     * the value past to this call.
+     * <p>
+     * Note: this method is not synchronized.
+     *
+     * @param seqNum value for the last sequence number
+     */
+    public void setLastSequenceNumber( long seqNum )
+    {
+        lastSeqNum = seqNum;
+    }
+
+    /**
+     * Return the sequence number of the last event that was scheduled
+     * to be sent.  Intended primarily for creating
+     * <code>EventRegistration</code> objects and the like.
+     */
+    public synchronized long getLastSequenceNumber()
+    {
+        return lastSeqNum;
+    }
+
+    /**
+     * Return the <code>long</code> that was uniquely associated with this
+     * object when it was created.
+     */
+    public long getEventID()
+    {
+        return evID;
+    }
+
+    /**
+     * Schedule the sending of an event.  This event will be sent to
+     * the currently registered listener.  If the listener changes
+     * before the the event is successfully sent the event will be sent
+     * to the new listener.  If the current listener is
+     * <code>null</code> this call will have no affect aside from
+     * incrementing the sequence number.
+     *
+     * @param factory an object that will be used to create the
+     *                <code>Event</code> object when necessary
+     * @return the sequence number assigned to the event
+     * @throws IllegalStateException if this method is called
+     *                               after the object has be deserialized and before
+     *                               <code>restoreTransientState</code> has been called
+     * @see EventType#restoreTransientState
+     */
+    public synchronized long sendEvent( EventFactory factory )
+    {
+        if( generator == null )
+        {
+            // Have not had our state restored, complain
+            throw new IllegalStateException( "EventType.sendEvent:" +
+                                             "called before state was fully restored" );
+        }
+
+        // Even if there is no listener, an event has occurred, so
+        // increment the sequence number (note this a stronger
+        // guarantee that the Jini Distributed Event Specification,
+        // but one that is required by the LRS spec).
+        lastSeqNum++;
+
+        // If we don't have a listener we don't need do anything else
+        if( !haveListener() )
+        {
+            return lastSeqNum;
+        }
+
+        final TaskManager mgr = generator.getTaskManager();
+        final WakeupManager wMgr = generator.getWakeupManager();
+        mgr.add( new SendTask( mgr, wMgr, factory, lastSeqNum ) );
+
+        return lastSeqNum;
+    }
+
+    /**
+     * Increment the sequence number and return the result. This
+     * method is useful if an event occurs that needs to be noted
+     * but from some reason it is impossible to deliver the event.
+     *
+     * @return the new value for the sequence number
+     */
+    public synchronized long bumpSequenceNumber()
+    {
+        return ++lastSeqNum;
+    }
+
+    /**
+     * Restore the transient state of this object after recovering it
+     * from a serialization stream.  None of the arguments can be
+     * <code>null</code>.
+     * <p>
+     * Note: this method is not synchronized.
+     *
+     * @param generator                 the <code>EventTypeGenerator</code> that was used
+     *                                  to create this EventType object originally
+     * @param monitor                   the object that monitors the progress of events
+     *                                  set by this object
+     * @param recoveredListenerPreparer the proxy preparer to use to prepare
+     *                                  listeners recovered from persistent storage
+     */
+    public void restoreTransientState( EventTypeGenerator generator,
+                                       SendMonitor monitor,
+                                       ProxyPreparer recoveredListenerPreparer )
+    {
+        if( generator == null )
+        {
+            throw new NullPointerException( "EventType.restoreTransientState:" +
+                                            "Must call with a non-null generator" );
+        }
+        if( monitor == null )
+        {
+            throw new NullPointerException( "EventType.restoreTransientState:" +
+                                            "Must call with a non-null monitor" );
+        }
+        if( recoveredListenerPreparer == null )
+        {
+            throw new NullPointerException( "EventType.restoreTransientState:" +
+                                            "Must call with a non-null recoveredListenerPreparer" );
+        }
+        this.generator = generator;
+        this.monitor = monitor;
+        this.recoveredListenerPreparer = recoveredListenerPreparer;
+        generator.recoverEventID( evID );
+    }
+
+    /**
+     * Subclass of <code>RetryTask</code> used by <code>EventType</code>
+     * to send events.
+     */
+    private class SendTask extends RetryTask
+    {
+        /**
+         * Max time we are willing to let a send attempt to go on for
+         */
+        final static private long MAX_TIME = 1000 * 60 * 60 * 24; //~ 1 Day
+
+        /**
+         * Factory used to create the <code>RemoteEvent</code> to be sent
+         */
+        final private EventFactory eventFactory;
+
+        /**
+         * Sequence number the event should have
+         */
+        final private long seqNum;
+
+        /**
+         * Cached event
+         */
+        private RemoteEvent event;
+
+        /**
+         * Registration sequence number of the listener/handback pair
+         * event was built for
+         */
+        private long eventForRegistrationNumber = -1;
+
+        /**
+         * Simple constructor.
+         *
+         * @param taskManager  <code>TaskManager</code> this task is to be
+         *                     put into
+         * @param eventFactory <code>EventFactory</code> that will be used
+         *                     to create the event to be sent
+         * @param seqNum       the sequence number of the event
+         */
+        private SendTask( TaskManager taskManager, WakeupManager wakeupManager,
+                          EventFactory eventFactory, long seqNum )
+        {
+            super( taskManager, wakeupManager );
+            this.eventFactory = eventFactory;
+            this.seqNum = seqNum;
+        }
+
+        // Inherit java doc from super type
+        public boolean tryOnce()
+        {
+            final long now = System.currentTimeMillis();
+            if( now - startTime() > MAX_TIME )
+            {
+                return true;    // we have been trying too long, stop here
+            }
+
+            if( !EventType.this.monitor.isCurrent() )
+            {
+                return true;    // lease gone, stop here
+            }
+
+            // Local copies of listener and handback so they won't
+            // be clobbered by setListener calls
+            RemoteEventListener listener;
+            MarshalledObject handback;
+            long registrationNumber;
+
+            synchronized( EventType.this )
+            {
+                if( !EventType.this.haveListener() )
+                {
+                    return true; // No currently registered listener, stop here
+                }
+
+                listener = EventType.this.getListener();
+                if( listener == null )
+                {
+                    return false; // There is a listener, but we can't unpack
+                    // it -- schedule a retry later
+                }
+                handback = EventType.this.handback;
+                registrationNumber = EventType.this.registrationNumber;
+            }
+
+            // If the handback has changed we need to create a new
+            // event object (we approximate this test by checking the
+            // registrationNumber
+
+            if( event == null ||
+                eventForRegistrationNumber != registrationNumber )
+            {
+                event = eventFactory.createEvent( EventType.this.evID, seqNum,
+                                                  handback );
+                eventForRegistrationNumber = registrationNumber;
+            }
+
+            // Try sending
+            try
+            {
+                listener.notify( event );
+                return true;
+            }
+            catch( Throwable t )
+            {
+                // Classify the exception using ThrowableConstants, if
+                // it is a bad object or uncategorized (which must be
+                // a UnknownEventException) drop the event
+                // registration, if it is a bad invocation mark the
+                // try is done (since re-sending this event won't work),
+                // but don't drop the registration.  If indefinite return
+                // false so a retry will be scheduled.
+                final int cat = ThrowableConstants.retryable( t );
+                if( cat == ThrowableConstants.INDEFINITE )
+                {
+                    logger.log( Levels.HANDLED,
+                                "Problem sending event -- will retry later",
+                                t );
+                    return false;
+                }
+                else if( cat == ThrowableConstants.BAD_INVOCATION )
+                {
+                    logger.log( Level.INFO, "Problem sending event", t );
+                    return true;
+                }
+                else
+                {
+                    EventType.this.monitor.definiteException( EventType.this,
+                                                              event, registrationNumber, t );
+                    logger.log( Level.INFO, "Problem sending event", t );
+                    return true;
+                }
+            }
+
+        }
+
+        // Inherit java doc from super type
+        public boolean runAfter( List tasks, int size )
+        {
+            // We don't need to run these tasks in any particular order
+	    return false;
+	}
+    }
+}

Added: incubator/river/jtsk/skunk/niclas1/services/norm/src/main/java/com/sun/jini/norm/event/EventTypeGenerator.java
URL: http://svn.apache.org/viewvc/incubator/river/jtsk/skunk/niclas1/services/norm/src/main/java/com/sun/jini/norm/event/EventTypeGenerator.java?rev=724975&view=auto
==============================================================================
--- incubator/river/jtsk/skunk/niclas1/services/norm/src/main/java/com/sun/jini/norm/event/EventTypeGenerator.java (added)
+++ incubator/river/jtsk/skunk/niclas1/services/norm/src/main/java/com/sun/jini/norm/event/EventTypeGenerator.java Tue Dec  9 21:11:39 2008
@@ -0,0 +1,161 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.sun.jini.norm.event;
+
+import com.sun.jini.thread.TaskManager;
+import com.sun.jini.thread.WakeupManager;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.Serializable;
+
+/**
+ * Factory class for <code>EventType</code> objects.  All
+ * <code>EventType</code> objects created by the same generator (or
+ * associated with the same generator by a
+ * <code>EventType.restoreTransientState<code> call) will use the same
+ * thread pool to manage their event send threads.
+ *
+ * @author Sun Microsystems, Inc.
+ * @see EventType
+ * @see EventType#restoreTransientState
+ */
+public class EventTypeGenerator implements Serializable
+{
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * Next event ID.
+     *
+     * @serial
+     */
+    private long nextEvID = 1;
+
+    /**
+     * Task manager used to send events
+     */
+    private transient TaskManager taskManager = new TaskManager();
+
+    /**
+     * Wakeup manager used by the event sending tasks to schedule
+     * retries.
+     */
+    private transient WakeupManager wakeupManager =
+        new WakeupManager( new WakeupManager.ThreadDesc( null, true ) );
+
+    /**
+     * Create a new <code>EventType</code> object.  The event ID for
+     * this type will be generated by this call.
+     *
+     * @param monitor Object to callback when an event sending
+     *                attempt fails with a definite exception and to
+     *                ensure that the lease on the event is still current.
+     *                May not be <code>null</code>.
+     * @return the new <code>EventType</code> object
+     * @throws IOException if listener cannot be serialized
+     */
+    public synchronized EventType newEventType( SendMonitor monitor )
+        throws IOException
+    {
+        EventType rslt = new EventType(
+            this, monitor, nextEvID, null, null );
+        // Do this afterward so we don't use up an ID if
+        // we can't create the new object
+        nextEvID++;
+        return rslt;
+    }
+
+    /**
+     * Create a new <code>EventType</code> object specify the
+     * event id it should have.
+     *
+     * @param eventID the event ID of this type
+     * @param monitor Object to callback when an event sending
+     *                attempt fails with a definite exception and to
+     *                ensure that the lease on the event is still current.
+     *                May not be <code>null</code>.
+     * @return the new <code>EventType</code> object
+     * @throws IOException if listener cannot be serialized
+     */
+    public EventType newEventType( SendMonitor monitor, long eventID )
+        throws IOException
+    {
+        return new EventType( this, monitor, eventID, null, null );
+    }
+
+    /**
+     * Called by event types during transient state recovery to ensure
+     * the generator knows about there event ID.
+     * <p>
+     * Note: this method is not synchronized.
+     *
+     * @param evID event ID of recovered <code>EventType</code> object
+     */
+    void recoverEventID( long evID )
+    {
+        if( evID >= nextEvID )
+        {
+            nextEvID = evID + 1;
+        }
+    }
+
+    /**
+     * Return the task manager that <code>EventType</code> objects created
+     * by this generator should use to send their events.
+     */
+    TaskManager getTaskManager()
+    {
+        return taskManager;
+    }
+
+    /**
+     * Return the wakeup manager that <code>EventType</code> objects created
+     * by this generator should use to send their events.
+     */
+    WakeupManager getWakeupManager()
+    {
+        return wakeupManager;
+    }
+
+    /**
+     * Terminate any independent treads started by event types
+     * associated with this generator.
+     */
+    public void terminate()
+    {
+        taskManager.terminate();
+        wakeupManager.stop();
+        wakeupManager.cancelAll();
+    }
+
+    /**
+     * Override <code>readObject</code> to create a <code>TaskManager</code>
+     * and a <code>WakeupManager</code>.
+     *
+     * @see ObjectInputStream#defaultReadObject
+     */
+    private void readObject( ObjectInputStream in )
+        throws IOException, ClassNotFoundException
+    {
+        // fill in the object from the stream
+        in.defaultReadObject();
+
+        taskManager = new TaskManager();
+        wakeupManager =
+            new WakeupManager( new WakeupManager.ThreadDesc( null, true ) );
+    }
+}

Added: incubator/river/jtsk/skunk/niclas1/services/norm/src/main/java/com/sun/jini/norm/event/SendMonitor.java
URL: http://svn.apache.org/viewvc/incubator/river/jtsk/skunk/niclas1/services/norm/src/main/java/com/sun/jini/norm/event/SendMonitor.java?rev=724975&view=auto
==============================================================================
--- incubator/river/jtsk/skunk/niclas1/services/norm/src/main/java/com/sun/jini/norm/event/SendMonitor.java (added)
+++ incubator/river/jtsk/skunk/niclas1/services/norm/src/main/java/com/sun/jini/norm/event/SendMonitor.java Tue Dec  9 21:11:39 2008
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.sun.jini.norm.event;
+
+import net.jini.core.event.RemoteEvent;
+
+/**
+ * Object associated with an <code>EventType</code> so it can ensure
+ * that the lease on an event notification is still valid and notify
+ * the client when a exception occurs in the course of attempting to
+ * send an event.
+ *
+ * @author Sun Microsystems, Inc.
+ * @see EventType
+ * @see EventTypeGenerator
+ */
+public interface SendMonitor
+{
+    /**
+     * Method called when an attempt to send the event associated with
+     * this object results in a definite exception
+     * (e.g. <code>java.rmi.NoSuchObjectException</code> or any other
+     * <code>Throwable</code> that is not a subclass of
+     * <code>java.rmi.RemoteException</code>.
+     * <p>
+     * The caller will own no locks when calling this method.
+     *
+     * @param type               the object that generated the event
+     * @param ev                 the remote event that could not be sent
+     * @param registrationNumber of the event registration that
+     *                           generated the exception.  This can be used
+     *                           to call <code>EventType.clearListenerIfSequenceMatch</code>
+     *                           ensure only the registration that cause the problem
+     *                           gets cleared.
+     * @param t                  the definite exception that caused us to give up
+     *                           sending the event
+     */
+    public void definiteException( EventType type,
+                                   RemoteEvent ev,
+                                   long registrationNumber,
+                                   Throwable t );
+
+    /**
+     * Should return <code>true</code> if the lease associated with this
+     * event is still valid and <code>false</code> otherwise.
+     * <p>
+     * The caller will own no locks when calling this method.
+     */
+    public boolean isCurrent();
+}