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:16:43 UTC
svn commit: r724986 [4/7] - in
/incubator/river/jtsk/skunk/niclas1/services/mercury: ./ 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/mercury/
src/main/resources/ src/main...
Added: incubator/river/jtsk/skunk/niclas1/services/mercury/src/main/java/com/sun/jini/mercury/MailboxProxy.java
URL: http://svn.apache.org/viewvc/incubator/river/jtsk/skunk/niclas1/services/mercury/src/main/java/com/sun/jini/mercury/MailboxProxy.java?rev=724986&view=auto
==============================================================================
--- incubator/river/jtsk/skunk/niclas1/services/mercury/src/main/java/com/sun/jini/mercury/MailboxProxy.java (added)
+++ incubator/river/jtsk/skunk/niclas1/services/mercury/src/main/java/com/sun/jini/mercury/MailboxProxy.java Tue Dec 9 21:16:33 2008
@@ -0,0 +1,305 @@
+/*
+ * 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.mercury;
+
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.ObjectInputStream;
+import java.io.ObjectStreamException;
+import java.io.Serializable;
+import java.rmi.RemoteException;
+import net.jini.admin.Administrable;
+import net.jini.core.constraint.MethodConstraints;
+import net.jini.core.constraint.RemoteMethodControl;
+import net.jini.core.lease.Lease;
+import net.jini.core.lease.LeaseDeniedException;
+import net.jini.event.MailboxPullRegistration;
+import net.jini.event.MailboxRegistration;
+import net.jini.event.PullEventMailbox;
+import net.jini.export.proxytrust.ProxyTrustIterator;
+import net.jini.export.proxytrust.SingletonProxyTrustIterator;
+import net.jini.id.ReferentUuid;
+import net.jini.id.ReferentUuids;
+import net.jini.id.Uuid;
+
+/**
+ * A MailboxProxy is a proxy for the event mailbox service.
+ * This is the object passed to clients of this service.
+ * It implements the <code>PullEventMailbox</code> and the
+ * <code>Administrable</code> interfaces.
+ *
+ * @author Sun Microsystems, Inc.
+ * @since 1.1
+ */
+class MailboxProxy implements PullEventMailbox,
+ Administrable, Serializable, ReferentUuid
+{
+
+ private static final long serialVersionUID = 2L;
+
+ /**
+ * The reference to the event mailbox service implementation
+ *
+ * @serial
+ */
+ final MailboxBackEnd mailbox;
+
+ /**
+ * The proxy's <code>Uuid</code>
+ *
+ * @serial
+ */
+ final Uuid proxyID;
+
+ /**
+ * Creates a mailbox proxy, returning an instance
+ * that implements RemoteMethodControl if the server does too.
+ *
+ * @param mailbox the server proxy
+ * @param id the ID of the server
+ */
+ static MailboxProxy create( MailboxBackEnd mailbox, Uuid id )
+ {
+ if( mailbox instanceof RemoteMethodControl )
+ {
+ return new ConstrainableMailboxProxy( mailbox, id, null );
+ }
+ else
+ {
+ return new MailboxProxy( mailbox, id );
+ }
+ }
+
+ /**
+ * Convenience constructor.
+ */
+ private MailboxProxy( MailboxBackEnd mailbox, Uuid proxyID )
+ {
+ if( mailbox == null || proxyID == null )
+ {
+ throw new IllegalArgumentException( "Cannot accept null arguments" );
+ }
+ this.mailbox = mailbox;
+ this.proxyID = proxyID;
+ }
+
+ // inherit javadoc from parent
+ public MailboxRegistration register( long duration )
+ throws RemoteException, LeaseDeniedException
+ {
+ // Check for a bad argument
+ // Note that -1 (i.e. Lease.ANY) is a valid request
+ if( duration < 1 && duration != Lease.ANY )
+ {
+ throw new IllegalArgumentException(
+ "Duration values must be positive" );
+ }
+ return mailbox.register( duration );
+ }
+
+ // inherit javadoc from parent
+ public MailboxPullRegistration pullRegister( long duration )
+ throws RemoteException, LeaseDeniedException
+ {
+ // Check for a bad argument
+ // Note that -1 (i.e. Lease.ANY) is a valid request
+ if( duration < 1 && duration != Lease.ANY )
+ {
+ throw new IllegalArgumentException(
+ "Duration values must be positive" );
+ }
+ return mailbox.pullRegister( duration );
+ }
+
+ // inherit javadoc from parent
+ public Object getAdmin() throws RemoteException
+ {
+ return mailbox.getAdmin();
+ }
+
+ /* From net.jini.id.ReferentUuid */
+ /**
+ * Returns the universally unique identifier that has been assigned to the
+ * resource this proxy represents.
+ *
+ * @return the instance of <code>Uuid</code> that is associated with the
+ * resource this proxy represents. This method will not return
+ * <code>null</code>.
+ * @see net.jini.id.ReferentUuid
+ */
+ public Uuid getReferentUuid()
+ {
+ return proxyID;
+ }
+
+ /**
+ * Proxies for servers with the same proxyID have the same hash code.
+ */
+ public int hashCode()
+ {
+ return proxyID.hashCode();
+ }
+
+ /**
+ * Proxies for servers with the same <code>proxyID</code> are
+ * considered equal.
+ */
+ public boolean equals( Object o )
+ {
+ return ReferentUuids.compare( this, o );
+ }
+
+ /**
+ * When an instance of this class is deserialized, this method is
+ * automatically invoked. This implementation of this method validates
+ * the state of the deserialized instance.
+ *
+ * @throws <code>InvalidObjectException</code>
+ * if the state of the
+ * deserialized instance of this class is found to be invalid.
+ */
+ private void readObject( ObjectInputStream s )
+ throws IOException, ClassNotFoundException
+ {
+ s.defaultReadObject();
+ /* Verify server */
+ if( mailbox == null )
+ {
+ throw new InvalidObjectException( "MailboxProxy.readObject "
+ + "failure - mailbox "
+ + "field is null" );
+ }//endif
+ /* Verify proxyID */
+ if( proxyID == null )
+ {
+ throw new InvalidObjectException( "MailboxProxy.proxyID "
+ + "failure - proxyID "
+ + "field is null" );
+ }//endif
+ }//end readObject
+
+ /**
+ * During deserialization of an instance of this class, if it is found
+ * that the stream contains no data, this method is automatically
+ * invoked. Because it is expected that the stream should always
+ * contain data, this implementation of this method simply declares
+ * that something must be wrong.
+ *
+ * @throws <code>InvalidObjectException</code>
+ * to indicate that there
+ * was no data in the stream during deserialization of an
+ * instance of this class; declaring that something is wrong.
+ */
+ private void readObjectNoData() throws ObjectStreamException
+ {
+ throw new InvalidObjectException( "no data found when attempting to "
+ + "deserialize MailboxProxy instance" );
+ }//end readObjectNoData
+
+
+ /**
+ * A subclass of MailboxProxy that implements RemoteMethodControl.
+ */
+ final static class ConstrainableMailboxProxy extends MailboxProxy
+ implements RemoteMethodControl
+ {
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Creates an instance of this class.
+ */
+ private ConstrainableMailboxProxy( MailboxBackEnd mailbox, Uuid uuid,
+ MethodConstraints methodConstraints )
+ {
+ super( constrainServer( mailbox, methodConstraints ),
+ uuid );
+ }
+
+ /**
+ * Returns a copy of the server proxy with the specified client
+ * constraints and methods mapping.
+ */
+ private static MailboxBackEnd constrainServer(
+ MailboxBackEnd mailbox,
+ MethodConstraints methodConstraints )
+ {
+ return (MailboxBackEnd)
+ ( (RemoteMethodControl) mailbox ).setConstraints( methodConstraints );
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public RemoteMethodControl setConstraints(
+ MethodConstraints constraints )
+ {
+ return new ConstrainableMailboxProxy( mailbox, proxyID,
+ constraints );
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public MethodConstraints getConstraints()
+ {
+ return ( (RemoteMethodControl) mailbox ).getConstraints();
+ }
+
+ /* Note that the superclass's hashCode method is OK as is. */
+ /* Note that the superclass's equals method is OK as is. */
+
+ /**
+ * Returns a proxy trust iterator that is used in
+ * <code>ProxyTrustVerifier</code> to retrieve this object's
+ * trust verifier.
+ */
+ private ProxyTrustIterator getProxyTrustIterator()
+ {
+ return new SingletonProxyTrustIterator( mailbox );
+ }//end getProxyTrustIterator
+
+ /**
+ * Performs various functions related to the trust verification
+ * process for the current instance of this proxy class, as
+ * detailed in the description for this class.
+ *
+ * @throws <code>InvalidObjectException</code>
+ * if any of the
+ * requirements for trust verification (as detailed in the
+ * class description) are not satisfied.
+ */
+ private void readObject( ObjectInputStream s )
+ throws IOException, ClassNotFoundException
+ {
+ /* Note that basic validation of the fields of this class was
+ * already performed in the readObject() method of this class'
+ * super class.
+ */
+ s.defaultReadObject();
+ // Verify that the server implements RemoteMethodControl
+ if( !( mailbox instanceof RemoteMethodControl ) )
+ {
+ throw new InvalidObjectException(
+ "MailboxAdminProxy.readObject failure - mailbox " +
+ "does not implement constrainable functionality " );
+ }//endif
+ }//end readObject
+
+
+ }
+}
Added: incubator/river/jtsk/skunk/niclas1/services/mercury/src/main/java/com/sun/jini/mercury/MercuryPermission.java
URL: http://svn.apache.org/viewvc/incubator/river/jtsk/skunk/niclas1/services/mercury/src/main/java/com/sun/jini/mercury/MercuryPermission.java?rev=724986&view=auto
==============================================================================
--- incubator/river/jtsk/skunk/niclas1/services/mercury/src/main/java/com/sun/jini/mercury/MercuryPermission.java (added)
+++ incubator/river/jtsk/skunk/niclas1/services/mercury/src/main/java/com/sun/jini/mercury/MercuryPermission.java Tue Dec 9 21:16:33 2008
@@ -0,0 +1,61 @@
+/*
+ * 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.mercury;
+
+import net.jini.security.AccessPermission;
+
+/**
+ * Represents permissions that can be used to express the access control policy
+ * for the Mercury server exported with a
+ * {@link net.jini.jeri.BasicJeriExporter}. This class
+ * can be passed to {@link net.jini.jeri.BasicInvocationDispatcher},
+ * and then used in
+ * security policy permission grants. <p>
+ *
+ * An instance contains a name (also referred to as a "target name") but no
+ * actions list; you either have the named permission or you don't. The
+ * convention is that the target name is the non-qualified name of the remote
+ * method being invoked. Wildcard matches are supported using the syntax
+ * specified by {@link AccessPermission}. <p>
+ *
+ * The possible target names for use with a Mercury server are specified in the
+ * package documentation for {@link com.sun.jini.mercury}.
+ *
+ * @author Sun Microsystems, Inc.
+ * @since 2.0
+ */
+public class MercuryPermission extends AccessPermission
+{
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Creates an instance with the specified target name.
+ *
+ * @param name the target name
+ * @throws NullPointerException if the target name is <code>null</code>
+ * @throws IllegalArgumentException if the target name does not match
+ * the syntax specified in the comments at the beginning of the {@link
+ * AccessPermission} class
+ */
+ public MercuryPermission( String name )
+ {
+ super( name );
+ }
+}
Added: incubator/river/jtsk/skunk/niclas1/services/mercury/src/main/java/com/sun/jini/mercury/NonActivatableMercuryImpl.java
URL: http://svn.apache.org/viewvc/incubator/river/jtsk/skunk/niclas1/services/mercury/src/main/java/com/sun/jini/mercury/NonActivatableMercuryImpl.java?rev=724986&view=auto
==============================================================================
--- incubator/river/jtsk/skunk/niclas1/services/mercury/src/main/java/com/sun/jini/mercury/NonActivatableMercuryImpl.java (added)
+++ incubator/river/jtsk/skunk/niclas1/services/mercury/src/main/java/com/sun/jini/mercury/NonActivatableMercuryImpl.java Tue Dec 9 21:16:33 2008
@@ -0,0 +1,56 @@
+/*
+ * 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.mercury;
+
+import com.sun.jini.start.LifeCycle;
+
+/**
+ * Convenience class intended for use with the
+ * {@link com.sun.jini.start.ServiceStarter} framework to start
+ * an implementation of Mercury that is not activatable, but which
+ * will log its state information to persistent storage.
+ *
+ * @author Sun Microsystems, Inc.
+ * @since 2.0
+ */
+class NonActivatableMercuryImpl extends MailboxImpl
+{
+
+ /**
+ * Constructs a new instance of <code>MailboxImpl</code> that is not
+ * activatable, but which will persist its state.
+ *
+ * @param configArgs <code>String</code> array whose elements are
+ * the arguments to use when creating the server.
+ * @param lifeCycle instance of <code>LifeCycle</code> that, if
+ * non-<code>null</code>, will cause this object's
+ * <code>unregister</code> method to be invoked during
+ * shutdown to notify the service starter framework that
+ * the reference to this service's implementation can be
+ * 'released' for garbage collection. A value of
+ * <code>null</code> for this argument is allowed.
+ * @throws Exception If there was a problem initializing the service.
+ */
+ NonActivatableMercuryImpl( String[] configArgs, LifeCycle lifeCycle )
+ throws Exception
+ {
+ super( configArgs, lifeCycle, true );//true ==> persistent
+ }//end constructor
+
+}//end class NonActivatableMercuryImpl
+
Added: incubator/river/jtsk/skunk/niclas1/services/mercury/src/main/java/com/sun/jini/mercury/PersistentEventLog.java
URL: http://svn.apache.org/viewvc/incubator/river/jtsk/skunk/niclas1/services/mercury/src/main/java/com/sun/jini/mercury/PersistentEventLog.java?rev=724986&view=auto
==============================================================================
--- incubator/river/jtsk/skunk/niclas1/services/mercury/src/main/java/com/sun/jini/mercury/PersistentEventLog.java (added)
+++ incubator/river/jtsk/skunk/niclas1/services/mercury/src/main/java/com/sun/jini/mercury/PersistentEventLog.java Tue Dec 9 21:16:33 2008
@@ -0,0 +1,1237 @@
+/*
+ * 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.mercury;
+
+import com.sun.jini.logging.Levels;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InterruptedIOException;
+import java.util.ArrayList;
+import java.util.NoSuchElementException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import net.jini.core.event.RemoteEvent;
+import net.jini.id.Uuid;
+
+/**
+ * Class that implements the interface for an <tt>EventLog</tt>.
+ * This class encapsulates the details of reading/writing events from/to
+ * some underlying persistence mechanism.
+ *
+ * This class makes certain assumptions. First, the <tt>next</tt> and
+ * <tt>remove</tt> methods are intended to be called in pairs. If
+ * <tt>remove</tt> is not called, then subsequent calls to <tt>next</tt>
+ * will attempt to return the same object. Calling <tt>remove</tt>
+ * essentially advances the read pointer to the next object, if any.
+ * Second, if any <tt>IOExceptions</tt> are encountered during the reading
+ * or writing of an event the associated read/write pointer is advanced
+ * past the offending event. This means that events can be lost if I/O
+ * errors are encountered.
+ *
+ * @author Sun Microsystems, Inc.
+ * @since 2.0
+ */
+
+/*
+Implementation details:
+
+Event state information is maintained by a control log file
+which maintains the current read and write counts/offsets. This file
+is updated whenever next(), add() or remove() is called. This file used to
+initialize the state of the EventLog, if it exists, during the
+initialization process.
+
+Events are logged into log files that maintain a fixed # of objects
+per file. The writing process adds events to a log file until this limit
+is reached. A new log file is then created to handle the next set of events.
+The reading process will delete a log file once all the contained events
+have been successfully processed. This serves as the garbage
+collection mechanism. Note that the actual number of events per log is a
+user-configurable environmental parameter via the
+com.sun.jini.mercury.eventsPerLog property (default = 10).
+
+This class also employs the services of a StreamPool, which limits the
+number of concurrently open file descriptors. This limit is also a user
+configurable value via the com.sun.jini.mercury.streamPoolSize property
+(default = 10).
+
+Event state is kept separate from the service's registration state in
+order to keep the event logging implementation as flexible as possible.
+*/
+
+class PersistentEventLog implements EventLog
+{
+
+ //
+ // Class fields
+ //
+
+ /**
+ * <tt>Logger</tt> used for persistence-related debugging messages
+ */
+ private static final Logger persistenceLogger =
+ MailboxImpl.persistenceLogger;
+
+ /**
+ * Size of control data file: 4 longs * 8 bytes per long
+ */
+ private static final int CTLBLOCK_LEN = 8 * 4;
+
+ /**
+ * File suffix for the control file
+ */
+ private static final String CTLFILE_SUFFIX = "ctl";
+
+ /**
+ * File suffix for the log files
+ */
+ private static final String LOGFILE_SUFFIX = "log";
+
+ /**
+ * Default number of events per log file, if not overriden by the user
+ */
+ private static final long DEFAULT_EVENTS_PER_LOGFILE = 10L;
+
+ /**
+ * Maximum number of event objects per log file. The
+ * default is used unless overridden by <tt>eventsPerLogProperty</tt>.
+ */
+ // Should be final but the compiler complains.
+//TODO - make eventsPerLogFile & maxPoolSize configurable
+/*
+ * Notes: this probably needs to remain constant over service lifetime. Therefore,
+ * this really needs to be treated as an "initial value that persisted and recovered.
+ * Would like to piggy back off MailboxImpl recovery logic, but 1) it needs to recover
+ * first in order to determine "first time up" and 2) seems logically better to keep
+ * these parameters local to EventLog. Will probably need to develop EventLog recovery
+ * logic for this purpose.
+ */
+ private static final long eventsPerLogFile = DEFAULT_EVENTS_PER_LOGFILE;
+
+ /**
+ * Default size for the stream pool, if not overriden by the user
+ */
+ static final int DEFAULT_STREAM_POOL_SIZE = 10;
+
+ /**
+ * Maximum limit for the number of concurrent <tt>LogStream</tt>s
+ * that this pool will concurrently manage. The
+ * default is used unless overridden by <tt>streamPoolSizeProperty</tt>.
+ */
+ private static final int maxPoolSize = DEFAULT_STREAM_POOL_SIZE;
+
+ /**
+ * The <tt>StreamPool</tt> reference to be used for all
+ * instances of <tt>EventLog</tt>.
+ */
+ // Should be final but the compiler complains.
+ private static final StreamPool streamPool =
+ new StreamPool( maxPoolSize );
+
+ //
+ // Object fields
+ //
+
+ /**
+ * The associated <tt>Uuid</tt> for this <tt>EventLog</tt>.
+ */
+ private Uuid uuid = null;
+
+ /**
+ * The current number of written events.
+ */
+ private long wcount = 0;
+
+ /**
+ * The current number of read events.
+ */
+ private long rcount = 0;
+
+ /**
+ * The current write offset into the current "write" log.
+ */
+ private long wpos = 0;
+
+ /**
+ * The read offset into the current "read" log of the
+ * "last read" object.
+ */
+ private long rpos = 0;
+
+ /**
+ * The read offset of the next event. This gets updated to
+ * <tt>rpos</tt> once <tt>remove</tt> is called (indicating
+ * that the last event read was successful).
+ */
+ private long nextReadPos = 0;
+
+ /**
+ * The <tt>EventReader</tt> used to retrieve events.
+ */
+ private EventReader eventReader;
+
+ /**
+ * The <tt>EventWriter</tt> used to store events
+ */
+ private EventWriter eventWriter;
+
+ /**
+ * The <tt>File</tt> object of the event persistence directory
+ */
+ private File logDir;
+
+ /**
+ * The <tt>File</tt> object that will maintain the control data for
+ * for this <tt>EventLog</tt>.
+ */
+ private File controlFile;
+
+ /**
+ * The in memory buffer that holds the control data
+ */
+ private byte[] ctlbuf = new byte[CTLBLOCK_LEN];
+
+ /**
+ * Flag that is used to determine whether or not this object
+ * has been initialized.
+ */
+ private boolean initialized = false;
+
+ /**
+ * Flag that is used to determine whether or not this object
+ * has been closed.
+ */
+ private boolean closed = false;
+
+ private static final boolean debugState = false;
+
+ /**
+ * Simple constructor that takes a <tt>Uuid</tt> argument
+ * and a <tt>File</tt> argument. These arguments are simply
+ * assigned to the appropriate internal fields.
+ *
+ * @throws IllegalArgumentException if any of the arguments are null
+ */
+ PersistentEventLog( Uuid uuid, File logDir )
+ {
+ if( logDir == null || uuid == null )
+ {
+ throw new IllegalArgumentException( "Arguments cannot be null" );
+ }
+ this.uuid = uuid;
+ this.logDir = logDir;
+
+ if( persistenceLogger.isLoggable( Level.FINEST ) )
+ {
+ persistenceLogger.log( Level.FINEST,
+ "PersistentEventLog for: {0}", uuid );
+ }
+ }
+
+ // Inherit documentation from supertype
+ public void init() throws IOException
+ {
+
+ if( initialized )
+ {
+ throw new InternalMailboxException(
+ "Trying to re-initialize control data "
+ + "for: " + uuid );
+ }
+
+ try
+ {
+ if( !logDir.exists() ) // Create log directory if it doesn't exist
+ {
+ logDir.mkdirs();
+ }
+
+ if( !logDir.isDirectory() ) // Verify that logDir is a directory
+ {
+ throw new FileNotFoundException( logDir.toString()
+ + " is not a directory" );
+ }
+
+ controlFile = getControlFile();
+ if( controlFile.isFile() )
+ { // Recover state from existing file
+ if( persistenceLogger.isLoggable( Level.FINEST ) )
+ {
+ persistenceLogger.log( Level.FINEST,
+ "EventLog::init() recovering data for ",
+ uuid );
+ }
+ readControlFile();
+ }
+ else
+ {
+ if( persistenceLogger.isLoggable( Level.FINEST ) )
+ {
+ persistenceLogger.log( Level.FINEST,
+ "default initialization for ", uuid );
+ }
+ }
+
+ eventReader = new EventReader();
+ eventWriter = new EventWriter();
+
+ }
+ finally
+ {
+ }
+
+ printControlData( persistenceLogger, "After EventLog::init" );
+
+ initialized = true;
+
+ if( debugState )
+ {
+ assertInvariants();
+ }
+ }
+
+ // Inherit documentation from supertype
+ public void add( RemoteEvent event ) throws IOException
+ {
+
+ stateCheck();
+
+ if( debugState )
+ {
+ assertInvariants();
+ }
+
+ long logNum = getLogNum( wcount );
+ File log = getLogFile( logNum );
+ LogOutputStream out = null;
+ try
+ {
+ // Get output stream
+ out = streamPool.getLogOutputStream( log, wpos );
+
+ // Write the event
+ eventWriter.write( event, out );
+
+ // Update the control data
+ wpos = out.getOffset();
+ ++wcount;
+ }
+ catch( IOException ioe )
+ {
+ // We'll get interrupted when asked to shutdown.
+ // In this case, we can skip the call to nextWriteLog.
+ if( ioe instanceof InterruptedIOException )
+ {
+ if( persistenceLogger.isLoggable( Level.FINEST ) )
+ {
+ persistenceLogger.log( Level.FINEST,
+ "EventLog::add() interrupted " );
+ }
+ }
+ else
+ {
+ if( persistenceLogger.isLoggable( Level.FINEST ) )
+ {
+ persistenceLogger.log( Level.FINEST,
+ "EventLog::add() received IOException "
+ + "... skipping to next write log" );
+ }
+ nextWriteLog();
+ }
+ if( persistenceLogger.isLoggable( Level.FINEST ) )
+ {
+ persistenceLogger.log( Level.FINEST,
+ "Exception: ", ioe );
+ }
+ throw (IOException) ioe.fillInStackTrace();
+ }
+ finally
+ {
+ // Always make sure to release any obtained resources
+ if( out != null )
+ {
+ if( getLogNum( wcount ) == logNum )
+ {
+ streamPool.releaseLogStream( out );
+ }
+ else
+ {
+ // Done writing to this particular log file, so
+ // remove it.
+ streamPool.removeLogStream( out );
+ wpos = 0;
+ }
+ }
+ // Write control data before returning
+ // TODO (FCS) - handle potential IOException
+ writeControlFile();
+ }
+
+ printControlData( persistenceLogger, "EventLog::add" );
+
+ if( debugState )
+ {
+ assertInvariants();
+ }
+ }
+
+ // Inherit documentation from supertype
+ public RemoteEvent next() throws IOException, ClassNotFoundException
+ {
+ boolean IOExceptionCaught = false;
+
+ stateCheck();
+
+ if( debugState )
+ {
+ assertInvariants();
+ }
+
+ // Check if empty
+ if( isEmpty() )
+ {
+ throw new NoSuchElementException();
+ }
+
+ long logNum = getLogNum( rcount );
+ File log = getLogFile( logNum );
+ LogInputStream in = null;
+ RemoteEvent evt = null;
+ try
+ {
+ // get the input stream
+ in = streamPool.getLogInputStream( log, rpos );
+ // read the event
+ evt = eventReader.read( in );
+ // update the control data
+ nextReadPos = in.getOffset();
+ // Don't increment "real" read count until event is delivered
+ // indicated by a call to remove().
+ }
+ catch( IOException ie )
+ {
+ // We'll get interrupted when asked to shutdown.
+ // In this case, we can skip the call to nextReadLog.
+ if( ie instanceof InterruptedIOException )
+ {
+ if( persistenceLogger.isLoggable( Level.FINEST ) )
+ {
+ persistenceLogger.log( Level.FINEST,
+ "EventLog::next() interrupted " );
+ }
+ }
+ else
+ {
+ if( persistenceLogger.isLoggable( Level.FINEST ) )
+ {
+ persistenceLogger.log( Level.FINEST,
+ "EventLog::next() received IOException "
+ + "... skipping to next read log" );
+ }
+ nextReadLog();
+ IOExceptionCaught = true;
+ }
+ if( persistenceLogger.isLoggable( Level.FINEST ) )
+ {
+ persistenceLogger.log( Level.FINEST,
+ "Exception: ", ie );
+ }
+ throw (IOException) ie.fillInStackTrace();
+ }
+ catch( ClassNotFoundException cnfe )
+ {
+ // Note that the read offset is still valid since the
+ // MarshalledObject extraction should always succeed.
+ // It's just that the RemoteEvent within it could not
+ // be reconstituted. Therefore, just skip to the next
+ // MarshalledObject in the stream.
+ nextReadPos = in.getOffset();
+ throw (ClassNotFoundException) cnfe.fillInStackTrace();
+ }
+ finally
+ {
+ // If an IOException occurs then the eventReader is in
+ // a bad state. Therefore, we get rid of our existing
+ // reference and create a fresh one. The underlying
+ // stream is also removed from from the pool, forcing
+ // a fresh copy to be returned on the next "get" request.
+ if( IOExceptionCaught )
+ {
+ //TODO (FCS) add close to interface
+ //eventReader.close();
+ eventReader = new EventReader();
+ if( in != null )
+ {
+ streamPool.removeLogStream( in );
+ }
+ // Remove associated log file since we are skipping over it
+ if( !log.delete() )
+ {
+ if( persistenceLogger.isLoggable( Levels.HANDLED ) )
+ {
+ persistenceLogger.log( Levels.HANDLED,
+ "Had trouble deleting {0}", log );
+ }
+ }
+ }
+ else
+ {
+ if( in != null )
+ {
+ streamPool.releaseLogStream( in );
+ }
+ }
+
+ // TODO (FCS) - handle potential IOException
+ writeControlFile();
+
+ }
+
+ printControlData( persistenceLogger, "After Event::next" );
+
+ if( debugState )
+ {
+ assertInvariants();
+ }
+
+ return evt;
+ }
+
+ // Inherit documentation from supertype
+ public RemoteEventData[] readAhead( int maxEvents )
+ throws IOException, ClassNotFoundException
+ {
+ boolean IOExceptionCaught = false;
+
+ stateCheck();
+
+ if( debugState )
+ {
+ assertInvariants();
+ }
+
+ // Check if empty
+ if( isEmpty() )
+ {
+ throw new NoSuchElementException();
+ }
+
+ long readCount = rcount;
+ long readPosition = rpos;
+ long logNum = getLogNum( readCount );
+ File log = getLogFile( logNum );
+ RemoteEvent evt = null;
+ ArrayList rData = new ArrayList();
+ int i = 0;
+ LogInputStream in = null;
+ boolean done = false;
+
+ printControlData( persistenceLogger, "Before read::readAhead" );
+ if( persistenceLogger.isLoggable( Level.FINEST ) )
+ {
+ persistenceLogger.log( Level.FINEST,
+ "EventLog::readAhead() maxEvents = {0}",
+ new Object[]{ new Integer( maxEvents ) } );
+ }
+
+ while( ( readCount < wcount ) &&
+ ( rData.size() < maxEvents ) &&
+ !done )
+ {
+ if( logNum != getLogNum( readCount ) )
+ {
+ logNum = getLogNum( readCount );
+ log = getLogFile( logNum );
+ readPosition = 0;
+ }
+ try
+ {
+ // get the input stream
+ in = streamPool.getLogInputStream( log, readPosition );
+ // read the event
+ evt = eventReader.read( in );
+ // update readCount and readPosition
+ readCount++;
+ readPosition = in.getOffset(); // offset to next unread event
+ //Generate new entry
+ rData.add( new RemoteEventData(
+ evt,
+ new RemoteEventDataCursor( readCount, readPosition ) ) );
+ }
+ catch( IOException ie )
+ {
+ // We'll get interrupted when asked to shutdown.
+ // In this case, we can skip the call to nextReadAheadLog.
+ if( ie instanceof InterruptedIOException )
+ {
+ if( persistenceLogger.isLoggable( Level.FINEST ) )
+ {
+ persistenceLogger.log( Level.FINEST,
+ "EventLog::readAhead() interrupted " );
+ }
+ // Stop processing events
+ done = true;
+ }
+ else
+ {
+ if( persistenceLogger.isLoggable( Level.FINEST ) )
+ {
+ persistenceLogger.log( Level.FINEST,
+ "EventLog::readAhead() received IOException "
+ + "... skipping to next read log" );
+ }
+ readCount = nextReadAheadLog( readCount );
+ // TODO - rcount = readCount;
+ // TODO - if bump rcount you need to bump wcount too
+ // TODO - if bump counts then you need to persist them
+ readPosition = 0;
+ IOExceptionCaught = true;
+ if( persistenceLogger.isLoggable( Level.FINEST ) )
+ {
+ persistenceLogger.log( Level.FINEST,
+ "EventLog::readAhead() new readCount is {0}",
+ new Long( readCount ) );
+ }
+ }
+ if( persistenceLogger.isLoggable( Levels.HANDLED ) )
+ {
+ persistenceLogger.log( Levels.HANDLED,
+ "Exception: ", ie );
+ }
+ }
+ catch( ClassNotFoundException cnfe )
+ {
+ // Note that the read offset is still valid since the
+ // MarshalledObject extraction should always succeed.
+ // It's just that the RemoteEvent within it could not
+ // be reconstituted. Therefore, just skip to the next
+ // MarshalledObject in the stream.
+ readCount++;
+ readPosition = in.getOffset();
+ //Generate new entry
+ rData.add( new RemoteEventData(
+ null,
+ new RemoteEventDataCursor( readCount, readPosition ) ) );
+ if( persistenceLogger.isLoggable( Levels.HANDLED ) )
+ {
+ persistenceLogger.log( Levels.HANDLED,
+ "Exception: ", cnfe );
+ }
+ }
+ finally
+ {
+ // If an IOException occurs then the eventReader is in
+ // a bad state. Therefore, we get rid of our existing
+ // reference and create a fresh one. The underlying
+ // stream is also removed from from the pool, forcing
+ // a fresh copy to be returned on the next "get" request.
+ if( IOExceptionCaught )
+ {
+ //TODO (FCS) add close to interface
+ //eventReader.close();
+ eventReader = new EventReader();
+ if( in != null )
+ {
+ streamPool.removeLogStream( in );
+ in = null;
+ }
+ }
+ else
+ {
+ if( in != null )
+ {
+ streamPool.releaseLogStream( in );
+ }
+ /* Shouldn't have to release since we have exclusive
+ * access, but the next getLogInputStream assumes things
+ * are on the freelist.
+ */
+ }
+
+ }
+ }
+
+ printControlData( persistenceLogger, "After Event::readAhead" );
+
+ if( debugState )
+ {
+ assertInvariants();
+ }
+
+ return (RemoteEventData[]) rData.toArray( new RemoteEventData[0] );
+ }
+
+ // Inherit documentation from supertype
+ public boolean isEmpty() throws IOException
+ {
+ stateCheck();
+ return !( rcount < wcount );
+ }
+
+ // Inherit documentation from supertype
+ public void remove() throws IOException
+ {
+ stateCheck();
+
+ if( debugState )
+ {
+ assertInvariants();
+ }
+
+ // Get current log number
+ long logNum = getLogNum( rcount );
+
+ // Update read counts
+ if( rcount < wcount )
+ {
+ ++rcount;
+ rpos = nextReadPos;
+ }
+ else
+ {
+ throw new NoSuchElementException();
+ }
+
+ // Remove old log if we've advanced to a new
+ // log file (ie done reading the old log file).
+ if( getLogNum( rcount ) != logNum )
+ {
+ File log = getLogFile( logNum );
+ LogInputStream in = null;
+ try
+ {
+ in = streamPool.getLogInputStream( log, rpos );
+ streamPool.removeLogStream( in );
+ }
+ finally
+ {
+ if( !log.delete() )
+ {
+ if( persistenceLogger.isLoggable( Levels.HANDLED ) )
+ {
+ persistenceLogger.log( Levels.HANDLED,
+ "Had trouble deleting {0}", log );
+ }
+ }
+ rpos = nextReadPos = 0;
+ }
+ }
+
+ // Store control data
+ writeControlFile();
+
+ // Verify that state remains intact
+ assertInvariants();
+
+
+ printControlData( persistenceLogger, "After Event::remove" );
+
+ }
+
+ // Inherit documentation from supertype
+ public void moveAhead( Object cookie ) throws IOException
+ {
+ stateCheck();
+
+ if( debugState )
+ {
+ assertInvariants();
+ }
+
+ printControlData( persistenceLogger, "Before Event::moveAhead" );
+
+ long readCount = 0;
+ long readPosition = 0;
+ RemoteEventDataCursor cursor = (RemoteEventDataCursor) cookie;
+ if( cursor != null )
+ {
+ readCount = cursor.getReadCount();
+ readPosition = cursor.getReadPosition();
+ }
+ else
+ {
+ /* TODO - should throw NullPointerException, but we do
+ * get called with null if client initially gets an empty set.
+ * Need to change getNextBatchDo() to skip this call
+ * if cookie is null. Also, could just return at this point since
+ * nothing will be advanced.
+ */
+ readCount = rcount;
+ readPosition = rpos;
+ }
+
+ if( readCount > wcount )
+ {
+ throw new NoSuchElementException();
+ }
+
+ long currentLogNum = getLogNum( rcount );
+ long nextLogNum = getLogNum( readCount );
+ if( persistenceLogger.isLoggable( Level.FINEST ) )
+ {
+ persistenceLogger.log( Level.FINEST,
+ "EventLog::moveAhead() readCount = {0}, readPosition = {1}, "
+ + "currentLogNum = {2}, nextLogNum = {3}",
+ new Object[]{ new Long( readCount ), new Long( readPosition ),
+ new Long( currentLogNum ), new Long( nextLogNum ) } );
+ }
+ File logFile = null;
+ LogInputStream in = null;
+ while( currentLogNum < nextLogNum )
+ {
+ try
+ {
+ logFile = getLogFile( currentLogNum );
+ in = streamPool.getLogInputStream( logFile, rpos );
+ streamPool.removeLogStream( in );
+ /*
+ * NOTE - if file doesn't exist (corrupted) then
+ * getLogInputStream throws an IOException and you
+ * end up skipping the removeLogStream() call.
+ * This "log" should eventually get cleared if once
+ * the stream pool hits its limit.
+ */
+
+ }
+ catch( IOException ioe )
+ {
+ if( persistenceLogger.isLoggable( Levels.HANDLED ) )
+ {
+ persistenceLogger.log( Levels.HANDLED,
+ "Had trouble accessing old log file", ioe );
+ }
+ }
+ finally
+ {
+ if( logFile != null && !logFile.delete() )
+ {
+ if( persistenceLogger.isLoggable( Levels.HANDLED ) )
+ {
+ persistenceLogger.log( Levels.HANDLED,
+ "Had trouble deleting {0}", logFile );
+ }
+ }
+ if( persistenceLogger.isLoggable( Level.FINEST ) )
+ {
+ persistenceLogger.log( Level.FINEST,
+ "Deleted {0}", logFile );
+ }
+ currentLogNum++;
+ }
+ }
+ rcount = readCount;
+ // If we started a new log file, then reset the read pointer.
+ if( ( rcount % eventsPerLogFile ) == 0 )
+ {
+ rpos = 0;
+ }
+ else
+ {
+ rpos = readPosition;
+ }
+
+ // Store control data
+ writeControlFile();
+
+ // Verify that state remains intact
+ assertInvariants();
+
+ printControlData( persistenceLogger, "After Event::moveAhead" );
+
+ }
+
+ // Inherit documentation from supertype
+ public void close() throws IOException
+ {
+ stateCheck();
+ if( debugState )
+ {
+ assertInvariants();
+ }
+
+ // Close read log
+ long logNum = getLogNum( rcount );
+ File log = getLogFile( logNum );
+ LogStream strm = null;
+ try
+ {
+ strm = streamPool.getLogInputStream( log, rpos );
+ streamPool.removeLogStream( strm );
+ }
+ catch( FileNotFoundException fnfe )
+ {
+ // Can happen if close is called just after you've finished
+ // reading a log. That is, the readCount is advanced to a new
+ // log which might not exist if a write hasn't taken place.
+ // TODO (FCS) - put a check to verify this condition and throw an
+ // exception otherwise?
+ }
+ catch( IOException ioe )
+ {
+ // catch, but ignore so as not to skip the following
+ // code.
+ }
+
+ // Close write log
+ logNum = getLogNum( wcount );
+ log = getLogFile( logNum );
+ try
+ {
+ strm = streamPool.getLogOutputStream( log, wpos );
+ streamPool.removeLogStream( strm );
+ }
+ catch( IOException ioe )
+ {
+ // catch, but ignore so as not to skip the following
+ // code.
+ }
+
+ // Close control log
+ try
+ {
+ strm = streamPool.getControlLog( controlFile );
+ streamPool.removeLogStream( strm );
+ }
+ catch( IOException ioe )
+ {
+ // catch, but ignore so as not to skip the following
+ // code.
+ }
+
+ //TODO (FCS) - flag that an IOException was caught and rethrow to
+ // indicate that there was a problem.
+
+ closed = true;
+
+ if( persistenceLogger.isLoggable( Level.FINEST ) )
+ {
+ persistenceLogger.log( Level.FINEST,
+ "EventLog::close for {0}", uuid );
+ }
+ }
+
+ // Inherit documentation from supertype
+ public void delete() throws IOException
+ {
+ if( !closed )
+ {
+ throw new IOException( "Cannot delete log until it is closed" );
+ }
+ removeDir( logDir );
+ }
+
+ /**
+ * Attempt to delete the associated event log persistence directory.
+ */
+ private static void removeDir( File logDir )
+ {
+ if( logDir == null || !logDir.isDirectory() )
+ {
+ return;
+ }
+
+ // Get the contents of this directory
+ String[] contents = logDir.list();
+ if( contents == null ) // Can happen if there was an IO error
+ {
+ return;
+ }
+
+ File entry = null;
+ if( persistenceLogger.isLoggable( Level.FINEST ) )
+ {
+ persistenceLogger.log( Level.FINEST,
+ "Deleting contents of: {0}", logDir );
+ }
+ for( int i = 0; i < contents.length; i++ )
+ {
+ entry = new File( logDir, contents[ i ] );
+ if( entry.isDirectory() )
+ {
+ removeDir( entry );
+ }
+ else
+ {
+ if( !entry.delete() )
+ {
+ if( persistenceLogger.isLoggable( Levels.HANDLED ) )
+ {
+ persistenceLogger.log( Levels.HANDLED,
+ "Had trouble deleting file: {0}",
+ entry );
+ }
+ }
+ else
+ {
+ if( persistenceLogger.isLoggable( Level.FINEST ) )
+ {
+ persistenceLogger.log( Level.FINEST,
+ "Deleted file: {0}", entry );
+ }
+ }
+ }
+ }
+
+ if( !logDir.delete() )
+ {
+ if( persistenceLogger.isLoggable( Levels.HANDLED ) )
+ {
+ persistenceLogger.log( Levels.HANDLED,
+ "Had trouble deleting directory: {0}",
+ logDir );
+ }
+ }
+ else
+ {
+ if( persistenceLogger.isLoggable( Level.FINEST ) )
+ {
+ persistenceLogger.log( Level.FINEST,
+ "Deleted directory: {0}", logDir );
+ }
+ }
+ }
+
+ /**
+ * Advance the "read" state to the next available log.
+ */
+ private void nextReadLog()
+ {
+ if( debugState )
+ {
+ assertInvariants();
+ }
+
+ // Normalize event count in case we were called due to a problem with
+ // one of the log files
+ long remainder = rcount % eventsPerLogFile;
+ rcount += ( eventsPerLogFile - remainder );
+ rpos = 0;
+
+ // Ensure that the writeLog data doesn't get behind
+ if( verifyInvariants() == false )
+ {
+ nextWriteLog();
+ }
+
+ // Assert that state is still valid
+ if( debugState )
+ {
+ assertInvariants();
+ }
+
+ printControlData( persistenceLogger, "EventLog::nextReadLog" );
+ }
+
+ /**
+ * Advance the temporary "read" state to the next available log.
+ */
+ private long nextReadAheadLog( long readCount )
+ {
+ // Normalize event count in case we were called due to a problem with
+ // one of the log files
+ long remainder = readCount % eventsPerLogFile;
+ readCount += ( eventsPerLogFile - remainder );
+
+ printControlData( persistenceLogger, "EventLog::nextReadAheadLog" );
+
+ return readCount;
+ }
+
+ /**
+ * Advance the "write" state to the next available log.
+ */
+ private void nextWriteLog()
+ {
+ // Don't check invariants at the top since we can get called
+ // from readNextLog() with invalid state.
+
+ // Normalize event count in case we were called due to a problem with
+ // one of the log files
+ long remainder = wcount % eventsPerLogFile;
+ wcount += ( eventsPerLogFile - remainder );
+ wpos = 0;
+
+ printControlData( persistenceLogger, "EventLog::nextWriteLog" );
+
+ if( debugState )
+ {
+ assertInvariants();
+ }
+ }
+
+ /**
+ * Output state information to the given <tt>Logger</tt>.
+ * This is intended for debugging purposes only.
+ */
+ private void printControlData( Logger logger, String msg )
+ {
+ if( logger.isLoggable( Level.FINEST ) )
+ {
+ logger.log( Level.FINEST, "{0}", msg );
+ logger.log( Level.FINEST, "ID: {0}", uuid );
+ logger.log( Level.FINEST, "ReadCount: {0}",
+ new Long( rcount ) );
+ logger.log( Level.FINEST, "ReadPos: {0}",
+ new Long( rpos ) );
+ logger.log( Level.FINEST, "NextReadPos: {0}",
+ new Long( nextReadPos ) );
+ logger.log( Level.FINEST, "WriteCount: {0}",
+ new Long( wcount ) );
+ logger.log( Level.FINEST, "WritePos: {0}",
+ new Long( wpos ) );
+ }
+ }
+
+ /**
+ * Write state information to the underlying store.
+ */
+ private void writeControlFile() throws IOException
+ {
+ packLong( wcount, ctlbuf, 0 );
+ packLong( rcount, ctlbuf, 8 );
+ packLong( wpos, ctlbuf, 16 );
+ packLong( rpos, ctlbuf, 24 );
+
+ ControlLog ctl = streamPool.getControlLog( controlFile );
+ ctl.seek( 0L );
+ ctl.write( ctlbuf );
+ ctl.getFD().sync();
+ streamPool.releaseLogStream( ctl );
+ }
+
+ /**
+ * Read state information from the underlying store.
+ */
+ private void readControlFile() throws IOException
+ {
+ ControlLog ctl = streamPool.getControlLog( controlFile );
+ ctl.seek( 0L );
+ ctl.readFully( ctlbuf );
+ streamPool.releaseLogStream( ctl );
+
+ wcount = unpackLong( ctlbuf, 0 );
+ rcount = unpackLong( ctlbuf, 8 );
+ wpos = unpackLong( ctlbuf, 16 );
+ rpos = unpackLong( ctlbuf, 24 );
+ }
+
+ /**
+ * Utility method for packing a <tt>long</tt> into a <tt>byte</tt> array.
+ */
+ private static void packLong( long val, byte[] b, int off )
+ {
+ b[ off++ ] = (byte) ( val >>> 56 );
+ b[ off++ ] = (byte) ( val >>> 48 );
+ b[ off++ ] = (byte) ( val >>> 40 );
+ b[ off++ ] = (byte) ( val >>> 32 );
+ b[ off++ ] = (byte) ( val >>> 24 );
+ b[ off++ ] = (byte) ( val >>> 16 );
+ b[ off++ ] = (byte) ( val >>> 8 );
+ b[ off++ ] = (byte) ( val >>> 0 );
+ }
+
+ /**
+ * Utility method for unpacking a <tt>long</tt> from a <tt>byte</tt> array.
+ */
+ private static long unpackLong( byte[] b, int off )
+ {
+ return ( ( b[ off + 0 ] & 0xFFL ) << 56 ) +
+ ( ( b[ off + 1 ] & 0xFFL ) << 48 ) +
+ ( ( b[ off + 2 ] & 0xFFL ) << 40 ) +
+ ( ( b[ off + 3 ] & 0xFFL ) << 32 ) +
+ ( ( b[ off + 4 ] & 0xFFL ) << 24 ) +
+ ( ( b[ off + 5 ] & 0xFFL ) << 16 ) +
+ ( ( b[ off + 6 ] & 0xFFL ) << 8 ) +
+ ( ( b[ off + 7 ] & 0xFFL ) << 0 );
+ }
+
+ /**
+ * Utility method for returning the <tt>File</tt> associated with the
+ * given <tt>lognum</tt>.
+ */
+ private File getLogFile( long lognum )
+ {
+ return new File( logDir, lognum + "." + LOGFILE_SUFFIX ).getAbsoluteFile();
+ }
+
+ /**
+ * Utility method for returning the <tt>File</tt> that contains the
+ * state information for this log.
+ */
+ private File getControlFile()
+ {
+ return new File( logDir, "log." + CTLFILE_SUFFIX ).getAbsoluteFile();
+ }
+
+ /**
+ * Utility method for returning the log file number for the given
+ * (event) <tt>count</tt>.
+ */
+ private static long getLogNum( long count )
+ {
+ return ( count / eventsPerLogFile );
+ }
+
+
+ /**
+ * Asserts that the log is in a valid state.
+ *
+ * @throws IOException if the log is in an invalid state
+ */
+ private void stateCheck() throws IOException
+ {
+ if( !initialized )
+ {
+ throw new IOException( "Trying to use an uninitialized "
+ + "control data object for: " + uuid );
+ }
+ if( closed )
+ {
+ throw new IOException( "Attempt to access closed log file for : "
+ + uuid );
+ }
+ }
+
+ /**
+ * Utility method for checking if the object invariants are valid.
+ */
+ private boolean verifyInvariants()
+ {
+ if( ( wcount < rcount ) ||
+ ( ( getLogNum( wcount ) == getLogNum( rcount ) ) && ( wpos < rpos ) ) )
+ {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Utility method for asserting that the object invariants are valid.
+ *
+ * @throws InternalMailboxException if the invariants aren't valid
+ */
+ private void assertInvariants()
+ {
+ if( verifyInvariants() == false )
+ {
+ printControlData( persistenceLogger, "Dumping invalid state for " + uuid );
+ throw new InternalMailboxException( "Invalid state for " + uuid );
+ }
+ }
+}
Added: incubator/river/jtsk/skunk/niclas1/services/mercury/src/main/java/com/sun/jini/mercury/ProxyUtil.java
URL: http://svn.apache.org/viewvc/incubator/river/jtsk/skunk/niclas1/services/mercury/src/main/java/com/sun/jini/mercury/ProxyUtil.java?rev=724986&view=auto
==============================================================================
--- incubator/river/jtsk/skunk/niclas1/services/mercury/src/main/java/com/sun/jini/mercury/ProxyUtil.java (added)
+++ incubator/river/jtsk/skunk/niclas1/services/mercury/src/main/java/com/sun/jini/mercury/ProxyUtil.java Tue Dec 9 21:16:33 2008
@@ -0,0 +1,83 @@
+/*
+ * 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.mercury;
+
+import java.lang.reflect.Method;
+
+/**
+ * Convenience class that contains a package protected static utility method
+ * used by the proxy classes of this package in proxy trust verification
+ * process.
+ *
+ * Note that this class cannot be instantiated.
+ *
+ * @author Sun Microsystems, Inc.
+ */
+class ProxyUtil
+{
+
+ /**
+ * This class cannot be instantiated.
+ */
+ private ProxyUtil()
+ {
+ throw new AssertionError( "class cannot be instantiated" );
+ }//end constructor
+
+ /**
+ * Returns the public method for the specified <code>Class</code> type,
+ * method name, and array of parameter types.
+ * <p>
+ * This method is typically used in place of {@link Class#getMethod
+ * Class.getMethod} to get a method that should definitely be defined;
+ * thus, this method throws an error instead of an exception if the
+ * given method is missing.
+ * <p>
+ * This method is convenient for the initialization of a static
+ * variable for use as the <code>mappings</code> argument to
+ * {@link com.sun.jini.proxy.ConstrainableProxyUtil#translateConstraints
+ * ConstrainableProxyUtil.translateConstraints}.
+ *
+ * @param type the <code>Class</code> type that defines the
+ * method of interest
+ * @param name <code>String</code> containing the name of the
+ * method of interest
+ * @param parameterTypes the <code>Class</code> types of the parameters
+ * to the method of interest
+ * @return a <code>Method</code> object that provides information about,
+ * and access to, the method of interest
+ * @throws <code>NoSuchMethodError</code> if the method of interest cannot
+ * be found
+ * @throws <code>NullPointerException</code>
+ * if <code>type</code> or
+ * <code>name</code> is <code>null</code>
+ */
+ static Method getMethod( Class type,
+ String name,
+ Class[] parameterTypes )
+ {
+ try
+ {
+ return type.getMethod( name, parameterTypes );
+ }
+ catch( NoSuchMethodException e )
+ {
+ throw (Error) ( new NoSuchMethodError( e.getMessage() ).initCause( e ) );
+ }
+ }//end getMethod
+}//end class ProxyUtil
Added: incubator/river/jtsk/skunk/niclas1/services/mercury/src/main/java/com/sun/jini/mercury/ProxyVerifier.java
URL: http://svn.apache.org/viewvc/incubator/river/jtsk/skunk/niclas1/services/mercury/src/main/java/com/sun/jini/mercury/ProxyVerifier.java?rev=724986&view=auto
==============================================================================
--- incubator/river/jtsk/skunk/niclas1/services/mercury/src/main/java/com/sun/jini/mercury/ProxyVerifier.java (added)
+++ incubator/river/jtsk/skunk/niclas1/services/mercury/src/main/java/com/sun/jini/mercury/ProxyVerifier.java Tue Dec 9 21:16:33 2008
@@ -0,0 +1,178 @@
+/*
+ * 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.mercury;
+
+import com.sun.jini.landlord.ConstrainableLandlordLease;
+import com.sun.jini.landlord.Landlord;
+import com.sun.jini.landlord.LandlordProxyVerifier;
+import java.io.Serializable;
+import java.rmi.RemoteException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import net.jini.core.constraint.MethodConstraints;
+import net.jini.core.constraint.RemoteMethodControl;
+import net.jini.export.proxytrust.TrustEquivalence;
+import net.jini.id.ReferentUuid;
+import net.jini.id.Uuid;
+import net.jini.security.TrustVerifier;
+
+/**
+ * Defines a trust verifier for the smart proxies of a Mercury server.
+ */
+final class ProxyVerifier implements TrustVerifier, Serializable
+{
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Logger for logging information about this instance
+ */
+ private static final Logger logger =
+ Logger.getLogger( "net.jini.security.trust" );
+
+ private static final String proxyVerifierSourceClass =
+ ProxyVerifier.class.getName();
+
+ /**
+ * The Mercury server proxy.
+ */
+ private final RemoteMethodControl serverProxy;
+
+ /**
+ * The unique identifier associated with the backend server referenced
+ * by the <code>serverProxy</code>, used for comparison with the IDs
+ * extracted from the smart proxies being verified.
+ *
+ * @serial
+ */
+ private final Uuid proxyID;
+
+ /**
+ * Returns a verifier for the smart proxies of the specified Mercury server
+ * proxy.
+ *
+ * @param serverProxy the Mercury server proxy
+ * @throws UnsupportedOperationException if <code>serverProxy</code> does
+ * not implement both {@link RemoteMethodControl} and {@link
+ * TrustEquivalence}
+ */
+ ProxyVerifier( MailboxBackEnd serverProxy, Uuid proxyID )
+ {
+ if( !( serverProxy instanceof RemoteMethodControl ) )
+ {
+ throw new UnsupportedOperationException(
+ "No verifier available for non-constrainable service" );
+ }
+ else if( !( serverProxy instanceof TrustEquivalence ) )
+ {
+ throw new UnsupportedOperationException(
+ "Verifier requires service proxy to implement " +
+ "TrustEquivalence" );
+ }
+ else if( proxyID == null )
+ {
+ throw new IllegalArgumentException(
+ "Proxy id cannot be null" );
+ }
+ this.serverProxy = (RemoteMethodControl) serverProxy;
+ this.proxyID = proxyID;
+ }
+
+ /**
+ * @throws NullPointerException {@inheritDoc}
+ */
+ public boolean isTrustedObject( Object obj, TrustVerifier.Context ctx )
+ throws RemoteException
+ {
+ if( logger.isLoggable( Level.FINER ) )
+ {
+ logger.entering( proxyVerifierSourceClass, "isTrustedObject",
+ new Object[]{ obj, ctx } );
+ }
+ if( obj == null || ctx == null )
+ {
+ throw new NullPointerException( "Arguments must not be null" );
+ }
+ RemoteMethodControl otherServerProxy;
+ Uuid inputProxyID = null;
+ if( obj instanceof Registration.ConstrainableRegistration )
+ {
+ Registration reg = (Registration) obj;
+ // verify sub-components
+ if( !isTrustedObject( reg.lease, ctx ) ||
+ !isTrustedObject( reg.listener, ctx ) )
+ {
+ return false;
+ }
+ otherServerProxy = (RemoteMethodControl) reg.mailbox;
+ }
+ else if( obj instanceof MailboxBackEnd &&
+ obj instanceof RemoteMethodControl )
+ {
+ /* Inner proxy verification case. To simplify logic, below,
+ * just assume the same Uuid that we have in hand.
+ */
+ otherServerProxy = (RemoteMethodControl) obj;
+ inputProxyID = proxyID;
+ }
+ else if( obj instanceof MailboxProxy.ConstrainableMailboxProxy )
+ {
+ otherServerProxy = (RemoteMethodControl) ( (MailboxProxy) obj ).mailbox;
+ inputProxyID = ( (ReferentUuid) obj ).getReferentUuid();
+ }
+ else if( obj instanceof MailboxAdminProxy.ConstrainableMailboxAdminProxy )
+ {
+ otherServerProxy = (RemoteMethodControl) ( (MailboxAdminProxy) obj ).server;
+ inputProxyID = ( (ReferentUuid) obj ).getReferentUuid();
+ }
+ else if( obj instanceof ListenerProxy.ConstrainableListenerProxy )
+ {
+ otherServerProxy = (RemoteMethodControl) ( (ListenerProxy) obj ).server;
+ }
+ else if( obj instanceof ConstrainableLandlordLease )
+ {
+ final LandlordProxyVerifier lpv =
+ new LandlordProxyVerifier( (Landlord) serverProxy, proxyID );
+ return lpv.isTrustedObject( obj, ctx );
+ }
+ else
+ {
+ logger.log( Level.FINEST, "Object {0} is not a supported type",
+ obj );
+ return false;
+ }
+
+ // For top-level proxies, quickly verify proxy Uuid
+ if( ( inputProxyID != null ) &&
+ !( proxyID.equals( inputProxyID ) ) )
+ {
+ return false;
+ }
+
+ MethodConstraints mc = otherServerProxy.getConstraints();
+ TrustEquivalence trusted =
+ (TrustEquivalence) serverProxy.setConstraints( mc );
+ boolean result = trusted.checkTrustEquivalence( otherServerProxy );
+ if( logger.isLoggable( Level.FINER ) )
+ {
+ logger.exiting( proxyVerifierSourceClass, "isTrustedObject",
+ Boolean.valueOf( result ) );
+ }
+ return result;
+ }
+}
Added: incubator/river/jtsk/skunk/niclas1/services/mercury/src/main/java/com/sun/jini/mercury/Registration.java
URL: http://svn.apache.org/viewvc/incubator/river/jtsk/skunk/niclas1/services/mercury/src/main/java/com/sun/jini/mercury/Registration.java?rev=724986&view=auto
==============================================================================
--- incubator/river/jtsk/skunk/niclas1/services/mercury/src/main/java/com/sun/jini/mercury/Registration.java (added)
+++ incubator/river/jtsk/skunk/niclas1/services/mercury/src/main/java/com/sun/jini/mercury/Registration.java Tue Dec 9 21:16:33 2008
@@ -0,0 +1,448 @@
+/*
+ * 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.mercury;
+
+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.io.ObjectStreamException;
+import java.io.Serializable;
+import java.lang.reflect.Method;
+import java.rmi.RemoteException;
+import java.util.Collection;
+import net.jini.core.constraint.MethodConstraints;
+import net.jini.core.constraint.RemoteMethodControl;
+import net.jini.core.event.RemoteEventListener;
+import net.jini.core.lease.Lease;
+import net.jini.event.MailboxPullRegistration;
+import net.jini.event.MailboxRegistration;
+import net.jini.event.RemoteEventIterator;
+import net.jini.export.proxytrust.ProxyTrustIterator;
+import net.jini.export.proxytrust.SingletonProxyTrustIterator;
+import net.jini.id.ReferentUuid;
+import net.jini.id.ReferentUuids;
+import net.jini.id.Uuid;
+
+/**
+ * The <tt>Registration</tt> class is the client-side proxy
+ * returned to event mailbox clients as the result of the
+ * registration process. It implements the <tt>MailboxRegistration</tt>
+ * interface and delegates functionality to the mailbox service
+ * where necessary.
+ *
+ * @author Sun Microsystems, Inc.
+ * @since 1.1
+ */
+class Registration implements MailboxPullRegistration,
+ Serializable, ReferentUuid
+{
+
+ private static final long serialVersionUID = 2L;
+
+ /**
+ * Unique identifier for this registration
+ */
+ final Uuid registrationID;
+
+ /**
+ * Reference to service implementation
+ */
+ final MailboxBackEnd mailbox;
+
+ /**
+ * Reference to service provided RemoteEventListener implementation
+ */
+ final ListenerProxy listener;
+
+ /**
+ * The service's registration lease
+ */
+ final Lease lease;
+
+ /**
+ * Creates a mailbox registration proxy, returning an instance
+ * that implements RemoteMethodControl if the server does too.
+ *
+ * @param server the server proxy
+ * @param id the ID of the lease set
+ * @param lease the lease set's lease
+ */
+ static Registration create( Uuid id, MailboxBackEnd server, Lease lease )
+ {
+ if( server instanceof RemoteMethodControl )
+ {
+ return new ConstrainableRegistration( id, server, lease, null );
+ }
+ else
+ {
+ return new Registration( id, server, lease );
+ }
+ }
+
+ /**
+ * Convenience constructor
+ */
+ private Registration( Uuid id, MailboxBackEnd srv, Lease l )
+ {
+ if( id == null || srv == null || l == null )
+ {
+ throw new IllegalArgumentException( "Cannot accept null arguments" );
+ }
+ registrationID = id;
+ mailbox = srv;
+ listener = ListenerProxy.create( id, srv );
+ lease = l;
+ }
+
+ // inherit javadoc from supertype
+ public Lease getLease()
+ {
+ return lease;
+ }
+
+ // inherit javadoc from supertype
+ public RemoteEventListener getListener()
+ {
+ return listener;
+ }
+
+ // inherit javadoc from supertype
+ public void enableDelivery( RemoteEventListener target )
+ throws RemoteException
+ {
+ // Prevent resubmission of this registration's listener
+ if( ( target instanceof ListenerProxy ) &&
+ ( listener.equals( (ListenerProxy) target ) ) )
+ {
+ throw new IllegalArgumentException( "Cannot resubmit " +
+ "a target that was provided by the EventMailbox service" );
+ }
+ else
+ { // OK to make the call, now
+ try
+ {
+ mailbox.enableDelivery( registrationID, target );
+ }
+ catch( ThrowThis tt )
+ {
+ tt.throwRemoteException();
+ }
+ }
+ }
+
+ // inherit javadoc from supertype
+ public void disableDelivery() throws RemoteException
+ {
+ try
+ {
+ mailbox.disableDelivery( registrationID );
+ }
+ catch( ThrowThis tt )
+ {
+ tt.throwRemoteException();
+ }
+ }
+
+ // inherit javadoc from supertype
+ public RemoteEventIterator getRemoteEvents()
+ throws RemoteException
+ {
+ RemoteEventIteratorImpl i = null;
+ try
+ {
+ RemoteEventIteratorData d = mailbox.getRemoteEvents( registrationID );
+ i = new RemoteEventIteratorImpl(
+ d.uuid, registrationID, mailbox, d.events );
+ }
+ catch( ThrowThis tt )
+ {
+ tt.throwRemoteException();
+ }
+ return i;
+ }
+
+ // inherit javadoc from supertype
+ public void addUnknownEvents( Collection unknownEvents )
+ throws RemoteException
+ {
+ //TODO - verify collection contains RemoteEvents
+ try
+ {
+ mailbox.addUnknownEvents( registrationID, unknownEvents );
+ }
+ catch( ThrowThis tt )
+ {
+ tt.throwRemoteException();
+ }
+
+ }
+
+ /* From net.jini.id.ReferentUuid */
+ /**
+ * Returns the universally unique identifier that has been assigned to the
+ * resource this proxy represents.
+ *
+ * @return the instance of <code>Uuid</code> that is associated with the
+ * resource this proxy represents. This method will not return
+ * <code>null</code>.
+ * @see net.jini.id.ReferentUuid
+ */
+ public Uuid getReferentUuid()
+ {
+ return registrationID;
+ }
+
+ /**
+ * Proxies with the same registrationID have the same hash code.
+ */
+ public int hashCode()
+ {
+ return registrationID.hashCode();
+ }
+
+ /**
+ * Proxies with the same registrationID are considered equal.
+ */
+ public boolean equals( Object o )
+ {
+ return ReferentUuids.compare( this, o );
+ }
+
+ /**
+ * When an instance of this class is deserialized, this method is
+ * automatically invoked. This implementation of this method validates
+ * the state of the deserialized instance.
+ *
+ * @throws <code>InvalidObjectException</code>
+ * if the state of the
+ * deserialized instance of this class is found to be invalid.
+ */
+ private void readObject( ObjectInputStream s )
+ throws IOException, ClassNotFoundException
+ {
+ s.defaultReadObject();
+ /* Verify server */
+ if( mailbox == null )
+ {
+ throw new InvalidObjectException( "Registration.readObject "
+ + "failure - mailbox "
+ + "field is null" );
+ }//endif
+ /* Verify registrationID */
+ if( registrationID == null )
+ {
+ throw new InvalidObjectException
+ ( "Registration.readObject "
+ + "failure - registrationID field is null" );
+ }//endif
+ /* Verify regLease */
+ if( lease == null )
+ {
+ throw new InvalidObjectException
+ ( "Registration.readObject "
+ + "failure - lease field is null" );
+ }//endif
+ /* Verify listener */
+ if( listener == null )
+ {
+ throw new InvalidObjectException
+ ( "Registration.readObject "
+ + "failure - listener field is null" );
+ }//endif
+ }//end readObject
+
+ /**
+ * During deserialization of an instance of this class, if it is found
+ * that the stream contains no data, this method is automatically
+ * invoked. Because it is expected that the stream should always
+ * contain data, this implementation of this method simply declares
+ * that something must be wrong.
+ *
+ * @throws <code>InvalidObjectException</code>
+ * to indicate that there
+ * was no data in the stream during deserialization of an
+ * instance of this class; declaring that something is wrong.
+ */
+ private void readObjectNoData() throws ObjectStreamException
+ {
+ throw new InvalidObjectException( "no data found when attempting to "
+ + "deserialize Registration instance" );
+ }//end readObjectNoData
+
+ /**
+ * A subclass of Registration that implements RemoteMethodControl.
+ */
+ final static class ConstrainableRegistration extends Registration
+ implements RemoteMethodControl
+ {
+ private static final long serialVersionUID = 1L;
+
+ // Mappings from client to server methods,
+ private static final Method[] methodMap1 = {
+ ProxyUtil.getMethod( MailboxPullRegistration.class,
+ "getRemoteEvents", new Class[]{ } ),
+ ProxyUtil.getMethod( MailboxBackEnd.class,
+ "getRemoteEvents", new Class[]{ Uuid.class } ),
+ // Use the same constraints for getNextBatch as getRemoteEvents
+ ProxyUtil.getMethod( MailboxPullRegistration.class,
+ "getRemoteEvents", new Class[]{ } ),
+ ProxyUtil.getMethod( MailboxBackEnd.class,
+ "getNextBatch", new Class[]{
+ Uuid.class, Uuid.class, long.class, Object.class } ),
+ ProxyUtil.getMethod( MailboxPullRegistration.class,
+ "addUnknownEvents", new Class[]{ Collection.class } ),
+ ProxyUtil.getMethod( MailboxBackEnd.class,
+ "addUnknownEvents", new Class[]{ Uuid.class, Collection.class } ),
+ ProxyUtil.getMethod( MailboxRegistration.class,
+ "enableDelivery", new Class[]{ RemoteEventListener.class } ),
+ ProxyUtil.getMethod( MailboxBackEnd.class,
+ "enableDelivery", new Class[]{ Uuid.class,
+ RemoteEventListener.class } ),
+ ProxyUtil.getMethod( MailboxRegistration.class,
+ "disableDelivery", new Class[]{ } ),
+ ProxyUtil.getMethod( MailboxBackEnd.class,
+ "disableDelivery", new Class[]{ Uuid.class } )
+ };
+ /**
+ * The client constraints placed on this proxy or <code>null</code>.
+ *
+ * @serial
+ */
+ private MethodConstraints methodConstraints;
+
+ /**
+ * Creates an instance of this class.
+ */
+ private ConstrainableRegistration( Uuid id, MailboxBackEnd server,
+ Lease lease, MethodConstraints methodConstraints )
+ {
+ super( id, constrainServer( server, methodConstraints ),
+ lease );
+ this.methodConstraints = methodConstraints;
+ }
+
+ // inherit javadoc from supertype
+ public RemoteEventIterator getRemoteEvents( long maxEvents, long timeout )
+ throws RemoteException
+ {
+ //
+ //TODO - return constrained remote iterator impl
+ //
+ return super.getRemoteEvents();
+ }
+
+ /**
+ * Returns a copy of the server proxy with the specified client
+ * constraints and methods mapping.
+ */
+ private static MailboxBackEnd constrainServer(
+ MailboxBackEnd server,
+ MethodConstraints methodConstraints )
+ {
+ return (MailboxBackEnd)
+ ( (RemoteMethodControl) server ).setConstraints(
+ ConstrainableProxyUtil.translateConstraints(
+ methodConstraints, methodMap1 ) );
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public RemoteMethodControl setConstraints(
+ MethodConstraints constraints )
+ {
+ return new ConstrainableRegistration( registrationID, mailbox, lease,
+ constraints );
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public MethodConstraints getConstraints()
+ {
+ return methodConstraints;
+ }
+
+ /* Note that the superclass's hashCode method is OK as is. */
+ /* Note that the superclass's equals method is OK as is. */
+
+ /* Note that the superclass's hashCode method is OK as is. */
+
+ /**
+ * Returns a proxy trust iterator that is used in
+ * <code>ProxyTrustVerifier</code> to retrieve this object's
+ * trust verifier.
+ */
+ private ProxyTrustIterator getProxyTrustIterator()
+ {
+ return new SingletonProxyTrustIterator( mailbox );
+ }//end getProxyTrustIterator
+
+ /**
+ * Verifies that the registrationID, lease and mailbox fields are
+ * not null, that mailbox implements RemoteMethodControl, and that the
+ * mailbox proxy has the appropriate method constraints.
+ *
+ * @throws InvalidObjectException if registrationID, lease or mailbox
+ * is null, if mailbox does not implement RemoteMethodControl,
+ * or if server has the wrong constraints
+ */
+ private void readObject( ObjectInputStream s )
+ throws IOException, ClassNotFoundException
+ {
+ /* Note that basic validation of the fields of this class was
+ * already performed in the readObject() method of this class'
+ * super class.
+ */
+ s.defaultReadObject();
+ /* Verify the server and its constraints */
+ ConstrainableProxyUtil.verifyConsistentConstraints( methodConstraints,
+ mailbox,
+ methodMap1 );
+ if( !( lease instanceof ConstrainableLandlordLease ) )
+ {
+ throw new InvalidObjectException
+ ( "Registration.readObject failure - "
+ + "lease is not an instance of "
+ + "ConstrainableLandlordLease" );
+ }//endif
+
+ if( !( listener instanceof ListenerProxy.ConstrainableListenerProxy ) )
+ {
+ throw new InvalidObjectException
+ ( "Registration.readObject failure - "
+ + "listener is not an instance of "
+ + "ListenerProxy.ConstrainableListenerProxy" );
+ }//endif
+
+ /* Verify listener's ID */
+ if( registrationID !=
+ ( (ListenerProxy.ConstrainableListenerProxy) listener ).registrationID )
+ {
+ throw new InvalidObjectException
+ ( "Registration.readObject "
+ + "failure - listener ID "
+ + "is not equal to "
+ + "proxy ID" );
+ }
+ }
+ }
+}