/*
* 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.lang.reflect.Method;
import java.rmi.RemoteException;
import java.util.Collection;
import javax.security.auth.Subject;
import com.sun.jini.landlord.ConstrainableLandlordLease;
import com.sun.jini.proxy.ConstrainableProxyUtil;
import com.sun.jini.proxy.ThrowThis;
import net.jini.core.constraint.MethodConstraints;
import net.jini.core.constraint.RemoteMethodControl;
import net.jini.id.ReferentUuid;
import net.jini.id.ReferentUuids;
import net.jini.id.Uuid;
import net.jini.security.proxytrust.ProxyTrustIterator;
import net.jini.security.proxytrust.SingletonProxyTrustIterator;
import net.jini.security.TrustVerifier;
import net.jini.event.MailboxPullRegistration;
import net.jini.event.MailboxRegistration;
import net.jini.event.RemoteEventIterator;
import net.jini.core.event.RemoteEventListener;
import net.jini.core.lease.Lease;
/**
* 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");
}
}
}
}