JXTA

net.jxta.impl.endpoint
Class BlockingMessenger

java.lang.Object
  extended by net.jxta.util.AbstractSimpleSelectable
      extended by net.jxta.endpoint.AbstractMessenger
          extended by net.jxta.impl.endpoint.BlockingMessenger
All Implemented Interfaces:
Messenger, SimpleSelectable
Direct Known Subclasses:
CbJxMessenger, HttpClientMessenger, HttpServletMessenger, LoopbackMessenger, RelayServerClient.RelayMessenger, RouterMessenger, TcpMessenger, TlsMessenger

public abstract class BlockingMessenger
extends AbstractMessenger

This class is a near-drop-in replacement for the previous BlockingMessenger class. To subclassers (that is, currently, transports) the only difference is that some overloaded methods have a different name (class hierarchy reasons made it impossible to preserve the names without forcing an API change for applications). The other difference which is not API visible, is that it implements the standard MessengerState behaviour and semantics required by the changes in the endpoint framework. This the only base messenger class meant to be extended by outside code that is in the impl tree. The reason being that what it replaces was there already and that new code should not become dependant upon it.


Nested Class Summary
 
Nested classes/interfaces inherited from interface net.jxta.util.SimpleSelectable
SimpleSelectable.IdentityReference
 
Field Summary
 
Fields inherited from class net.jxta.endpoint.AbstractMessenger
DEFAULT_MTU, dstAddress
 
Fields inherited from class net.jxta.util.AbstractSimpleSelectable
identityReference
 
Fields inherited from interface net.jxta.endpoint.Messenger
ANYSTATE, BREAKING, BROKEN, CLOSED, CLOSING, CONNECTED, DISCONNECTED, DISCONNECTING, IDLE, RECONCLOSING, RECONNECTING, RECONSATURATED, RESOLCLOSING, RESOLPENDING, RESOLSATURATED, RESOLVED, RESOLVING, SATURATED, SENDING, SENDINGSATURATED, TERMINAL, UNRESOLVABLE, UNRESOLVED, UNRESOLVING, USABLE
 
Constructor Summary
BlockingMessenger(PeerGroupID homeGroupID, EndpointAddress dest, boolean selfDestruct)
          Constructor.
 
Method Summary
 void close()
          Close this messenger after processing any pending messages.
protected abstract  void closeImpl()
          Close connection.
 Messenger getChannelMessenger(PeerGroupID redirection, String service, String serviceParam)
          If applicable, returns another messenger that will send messages to the same destination address than this one, but with the specified default service and serviceParam, possibly rewriting addresses to ensure delivery through the specified redirection.
protected  EndpointAddress getDestAddressToUse(String service, String serviceParam)
          Assemble a destination address for a message based upon the messenger default destination address and the optional provided overrides.
 EndpointAddress getLogicalDestinationAddress()
          Returns the logical destination of this messenger.
protected abstract  EndpointAddress getLogicalDestinationImpl()
          Obtain the logical destination address from the implementer (a transport for example).
 int getState()
          Returns the current state.
 boolean isClosed()
          Returns true if this messenger is closed and no longer accepting messages to be sent.
protected abstract  boolean isIdleImpl()
          return true if this messenger has not been used for a long time.
 void resolve()
          Force the messenger to start resolving if it is not resolved yet.
 void sendMessageB(Message msg, String service, String serviceParam)
          Simple sending: blocks until the message was accepted for sending or the messenger is not Messenger.USABLE; whichever occurs first.
protected abstract  void sendMessageBImpl(Message message, String service, String param)
          Send a message blocking as needed until the message is sent.
 boolean sendMessageN(Message msg, String service, String serviceParam)
          Sends a message to the destination specified at construction.
 void setOwner(Object owner)
          Sets an owner for this blocking messenger.
protected  void shutdown()
          A transport may call this to cause an orderly closure of its messengers.
 
Methods inherited from class net.jxta.endpoint.AbstractMessenger
flush, getDestinationAddress, getDestinationAddressObject, getMTU, isIdle, isSynchronous, itemChanged, sendMessage, sendMessage, sendMessage, setStateLock, toString, waitState
 
Methods inherited from class net.jxta.util.AbstractSimpleSelectable
getIdentityReference, haveListeners, notifyChange, register, registerListener, unregister, unregisterListener
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait
 
Methods inherited from interface net.jxta.util.SimpleSelectable
getIdentityReference, register, unregister
 

Constructor Detail

BlockingMessenger

public BlockingMessenger(PeerGroupID homeGroupID,
                         EndpointAddress dest,
                         boolean selfDestruct)
Constructor.

We start in the CONNECTED state, we pretend to have a queue of size 1, and we can never re-connect. Although this messenger fully respects the asynchronous semantics, it is saturated as soon as one msg is being send, and if not saturated, send is actually performed by the invoker thread. So return is not completely immediate. This is a barely acceptable implementation, but this is also a transition adapter that is bound to disappear one release from now. The main goal is to get things going until transports are adapted.

Parameters:
homeGroupID - the group that this messenger works for. This is the group of the endpoint service or transport that created this messenger.
dest - where messages should be addressed to
selfDestruct - true if this messenger must self close destruct when idle. Warning: If selfDestruct is used, this messenger will remained referenced for as long as isIdleImpl returns false.
Method Detail

setOwner

public void setOwner(Object owner)
Sets an owner for this blocking messenger. Owners are normally canonical messengers. The goal of registering the owner is to keep that owner reachable as long as this blocking messenger is. Canonical messengers are otherwise softly referenced, and so, may be deleted whenever memory is tight.

We do not want to use finalizers or the equivalent reference queue mechanism; so we have no idea when a blocking messenger is no-longer referenced by any canonical. In addition it may be expensive to make and so we want to keep it for a while anyway. As a result, instead of keeping a blocking messenger open as long as there is a canonical, we do the opposite: we keep the canonical (owner, here) as long as the blocking messenger is open (and usually beyond, memory allowing). How long a blocking messenger will stay around depends upon that messenger's implementation. That may even be left up to the GC, in the end (if close is not needed AND the messenger is cheap to make). In that case, the owner is likely the only referrer, and so both will have the same lifetime.

Parameters:
owner - The object that should be kept referenced at least as long as this one.

getDestAddressToUse

protected EndpointAddress getDestAddressToUse(String service,
                                              String serviceParam)
Assemble a destination address for a message based upon the messenger default destination address and the optional provided overrides.

Parameters:
service - The destination service or null to use default.
serviceParam - The destination service parameter or null to use default.

shutdown

protected final void shutdown()
A transport may call this to cause an orderly closure of its messengers.


isClosed

public boolean isClosed()
Returns true if this messenger is closed and no longer accepting messages to be sent. This is a shortcut for (getState() & USABLE == 0). Once closed, a messenger should be discarded.

This is a minimal implementation. It may not detect closure initiated by the other side unless the messenger was actually used since. A more accurate (but not mandatory implementation) would actually go and check the underlying connection, if relevant...unless breakage initiated by the other side is actually reported asynchronously when it happens. Breakage detection from the other side need not be reported atomically with its occurrence. This not very important since we canonicalize transport messengers and so do not need to aggressively collect closed ones. When not used, messengers die by themselves.

We overload isClosed because many messengers still use super.isClosed() as part of their own implementation or don't override it at all. They expect it to be true only when all is shutdown; not while we're closing gently. FIXME - jice@jxta.org 20040413: transports should get a deeper retrofit eventually.

Specified by:
isClosed in interface Messenger
Overrides:
isClosed in class AbstractMessenger
Returns:
true if this messenger is closed, otherwise false.

getLogicalDestinationAddress

public final EndpointAddress getLogicalDestinationAddress()
Returns the logical destination of this messenger. This may be a different address than is returned by getDestinationAddress and refers to the entity which is located at the destination address.

By analogy, a telephone number would be the destination address, and the owner of that telephone number would be the logical destination. Each logical destination may be known by one or more destination addresses.

getLogicalDestinationAddress() requires resolution (it's the address advertised by the other end). For a blocking messenger it's easy. We're born resolved. So, just ask the implementor what it is.

Returns:
EndpointAddress the logical destination address of this messenger.
See Also:
Messenger.getDestinationAddress()

close

public final void close()
Close this messenger after processing any pending messages. This method is not blocking. Upon return, the messenger will be in one of the non Messenger.USABLE states, which means that no message may be sent through it. Any other effect of this method, such as an underlying connection being closed, or all pending messages being processed, may be deferred indefinitely. When the messenger has completely processed the closure request, it will be in one of the Messenger.TERMINAL states (which are also Messenger.IDLE states). Therefore, if one is interested in the outcome of the closure, one may wait for the messenger to be in a Messenger.TERMINAL or Messenger.IDLE state, and check which it is. Messenger.CLOSED denotes success (all outstanding messages have been sent), as opposed to Messenger.UNRESOLVABLE or Messenger.BROKEN.

Some transports historically overload the close method of BlockingMessenger. The final is there to make sure we know about it. However, there should be no harm done if the unchanged code is renamed to closeImpl; even if it calls super.close(). The real problem, however, is transports calling close (was their own, but now it means this one), when they want to break. It will make things look like someone just called close, but it will not actually break anything. However, that will cause the state machine to go through the close process. this will end up calling closeImpl(). That will do.


sendMessageB

public void sendMessageB(Message msg,
                         String service,
                         String serviceParam)
                  throws IOException
Simple sending: blocks until the message was accepted for sending or the messenger is not Messenger.USABLE; whichever occurs first. If a service name and service param are specified, they will replace those specified at construction for the purpose of sending this message only.

Error Handling:

WARNING: The Message object should not be reused or modified until completely processed. Concurrent modification of a message while a messenger is sending the message will produce incorrect and unpredictable results. If completion is not monitored, the message should never be reused. If necessary, a clone of the message may be provided to Messenger.sendMessageB(net.jxta.endpoint.Message, java.lang.String, java.lang.String):

     messenger.sendMessageB( (Message) myMessage.clone(), theService, theParam );
 

There is no guarantee that a message successfully sent will actually be received.

Parameters:
msg - the message
service - Optionally replaces the service in the destination address. If null then the destination address's default service will be used. If the empty string ("") is used then no service is included in the destination address.
serviceParam - Optionally replaces the service param in the destination address. If null then the destination address's default service parameter will be used. If the empty string ("") is used then no service param is included in the destination address.
Throws:
IOException - Thrown if the message cannot be sent.

sendMessageN

public final boolean sendMessageN(Message msg,
                                  String service,
                                  String serviceParam)
Sends a message to the destination specified at construction. If a service name and service param are specified, they will replace those specified at construction for the purpose of sending this message only.

This method is identical to Messenger.sendMessage(Message,String,String), except that it does not throw an exception. The invoker has to retrieve a detailed status from the message if needed.

Error Handling:

WARNING: The Message object should not be reused or modified until completely processed. Concurrent modification of a message while a messenger is sending the message will produce incorrect and unpredictable results. If completion is not monitored, the message should never be reused. If necessary, a clone of the message may be provided to Messenger.sendMessageN(net.jxta.endpoint.Message, java.lang.String, java.lang.String):

     messenger.sendMessageN( (Message) myMessage.clone(), theService, theParam );
 

There is no guarantee that a message successfully sent will actually be received.

Parameters:
msg - The message to send.
service - Optionally replaces the service in the destination address. If null then the destination address's default service will be used. If the empty string ("") is used then no service is included in the destination address.
serviceParam - Optionally replaces the service param in the destination address. If null then the destination address's default service parameter will be used. If the empty string ("") is used then no service param is included in the destination address.
Returns:
boolean true if the message has been accepted for sending, otherwise false.

resolve

public final void resolve()
Force the messenger to start resolving if it is not resolved yet. Any attempt at sending a message has the same effect, but the message may fail as a result, depending upon the method used.


getState

public final int getState()
Returns the current state.

Returns:
one of the legal discrete state values.

getChannelMessenger

public final Messenger getChannelMessenger(PeerGroupID redirection,
                                           String service,
                                           String serviceParam)
If applicable, returns another messenger that will send messages to the same destination address than this one, but with the specified default service and serviceParam, possibly rewriting addresses to ensure delivery through the specified redirection. This is not generally useful to applications and most messengers will return null. This method is needed by the EndpointService when interacting with Messengers provided by Transport modules. If you are not implementing a Transport module, then you can ignore this method.

Important: The channel so obtained is not configured to support the Messenger.sendMessage(Message,String,String, OutgoingMessageEventListener) legacy method. If use of this method is desired, ChannelMessenger.setMessageWatcher(net.jxta.endpoint.ListenerAdaptor) must be used first.

Parameters:
redirection - The requested redirection. The resulting channel messenger will use this to force delivery of the message only in the specified group (or possibly descendents, but not parents). If null the local group is assumed. This redirection is applied only to messages that are sent to a service name and service param that do not imply a group redirection.
service - The service to which the resulting channel will send messages, when they are not sent to a specified service.
serviceParam - The service parameter that the resulting channel will use to send messages, when no parameter is specified.
Returns:
a channelMessenger as specified.
See Also:
MessageSender.getMessenger(EndpointAddress,Object)

closeImpl

protected abstract void closeImpl()
Close connection. May fail current send.


sendMessageBImpl

protected abstract void sendMessageBImpl(Message message,
                                         String service,
                                         String param)
                                  throws IOException
Send a message blocking as needed until the message is sent.

Parameters:
message - The message to send.
service - The destination service.
param - The destination serivce param.
Throws:
IOException - Thrown for errors encountered while sending the message.

isIdleImpl

protected abstract boolean isIdleImpl()
return true if this messenger has not been used for a long time. The definition of long time is: "sufficient such that closing it is worth the cost of having to re-open". A messenger should self close if it thinks it meets the definition of idle. BlockingMessenger leaves the evaluation to the transport but does the work automatically. Important: if self destruction is used, this method must work; not just return false. See the constructor. In general, if closeImpl does not need to do anything, then self destruction is not needed.

Returns:
true if theis messenger is, by it's own definition, idle.

getLogicalDestinationImpl

protected abstract EndpointAddress getLogicalDestinationImpl()
Obtain the logical destination address from the implementer (a transport for example).


JXSE