public interface FCPPluginConnection
PluginRespirator#connectToOtherPlugin(String, ClientSideFCPMessageHandler)
PluginRespirator.getPluginConnectionByID(UUID)
FredPluginFCPMessageHandler
FredPluginFCPMessageHandler.ServerSideFCPMessageHandler
FredPluginFCPMessageHandler.ClientSideFCPMessageHandler
FCPPluginMessage
Logger
to log "freenet.clients.fcp.FCPPluginConnection:DEBUG" to
cause logging of all sent and received messages.sendSynchronous(SendDirection, FCPPluginMessage, long)
will not deliver replies
to the message handler but only return them instead.PluginRespirator#connectToOtherPlugin(String, ClientSideFCPMessageHandler)
. It keeps
them open by keeping a strong reference to the FCPPluginConnection. Once it does not strongly
reference it anymore, Freenet detects that by monitoring garbage collection, and considers the
connection as closed then. A closed connection is indicated to the server plugin by the send
functions throwing IOException
.UUID
of a client connection in their database so they are able to send data to the client
if an event of interest to the client happens in the future. Therefore, the UUID
of a
connection must not change during the lifetime of the connection. To ensure a permanent
UUID
of a connection, only a single FCPPluginConnection can exist per server plugin per
network connection).
In opposite to a FCP connection to fred itself, which is represented by
PersistentRequestClient
and can exist across restarts, a FCPPluginConnection is kept in
existence by fred only while the actual client is connected. In case of networked plugin FCP,
this is while the parent network connection is open; or in case of non-networked plugin
FCP, while the FCPPluginConnection is strong-referenced by the client plugin.
There is no such thing as persistence beyond client disconnection / restarts.
This was decided to simplify implementation:
- Persistence should have been implemented by using the existing persistence framework of
PersistentRequestClient
. That would require extending the class though, and it is a
complex class. The work for extending it was out of scope of the time limit for implementing
this class.
- FCPPluginConnection instances need to be created without a network connection for intra-node
plugin connections. If we extended class PersistentRequestClient
, a lot of care would
have to be taken to allow it to exist without a network connection - that would even be more
work.
FCPPluginConnectionImpl
of this interface.
Notably, the said section provides an overview of the flow of messages.Modifier and Type | Interface and Description |
---|---|
static class |
FCPPluginConnection.SendDirection
The send functions are fully symmetrical: They work the same way no matter whether client
is sending to server or server is sending to client.
Thus, to prevent us from having to duplicate the send functions, this enum specifies in which situation we are. |
Modifier and Type | Method and Description |
---|---|
java.util.UUID |
getID() |
void |
send(FCPPluginConnection.SendDirection direction,
FCPPluginMessage message)
Can be used by both server and client implementations to send messages to each other.
The messages sent by this function will be delivered to the remote side at either: - the message handler handlePluginFCPMessage(FCPPluginConnection, FCPPluginMessage) .- or, if existing, a thread waiting for a reply message in sendSynchronous(SendDirection, FCPPluginMessage, long) .This is an asynchronous, non-blocking send function. This has the following differences to the blocking send sendSynchronous(
SendDirection, FCPPluginMessage, long) :- It may return before the message has been sent. The message sending happens in another thread so this function can return immediately. In opposite to that, a sendSynchronous() would wait for a reply to arrive, so once it returns, the message is guaranteed to have been sent. - The reply is delivered to your message handler FredPluginFCPMessageHandler . |
void |
send(FCPPluginMessage message)
Same as
send(SendDirection, FCPPluginMessage) with the FCPPluginConnection.SendDirection
parameter being the default direction.Please do read its JavaDoc as it contains a very precise specification how to use it and thereby also this function. The default direction is determined automatically depending on whether you are a client or server. You are acting as a client, and thus by default send to the server, when you obtain a FCPPluginConnection...: - from the return value of PluginRespirator#connectToOtherPlugin(String, ClientSideFCPMessageHandler) .- as parameter to your message handler callback handlePluginFCPMessage(FCPPluginConnection, FCPPluginMessage) .You are acting as a server, and thus by default send to the client, when you obtain a FCPPluginConnection...: - as parameter to your message handler callback handlePluginFCPMessage(FCPPluginConnection, FCPPluginMessage) .- from the return value of PluginRespirator.getPluginConnectionByID(UUID) . |
FCPPluginMessage |
sendSynchronous(FCPPluginConnection.SendDirection direction,
FCPPluginMessage message,
long timeoutNanoSeconds)
Can be used by both server and client implementations to send messages in a blocking
manner to each other.
The messages sent by this function will be delivered to the message handler FredPluginFCPMessageHandler.handlePluginFCPMessage(FCPPluginConnection,
FCPPluginMessage) of the remote side.This has the following differences to a regular non-synchronous send(SendDirection, FCPPluginMessage) :- It will wait for a reply message of the remote side before returning. A regular send() would instead queue the message for sending, and then return immediately. |
FCPPluginMessage |
sendSynchronous(FCPPluginMessage message,
long timeoutNanoSeconds)
Same as
sendSynchronous(SendDirection, FCPPluginMessage, long) with the
FCPPluginConnection.SendDirection parameter being the default direction.Please do read its JavaDoc as it contains a very precise specification how to use it and thereby also this function. For an explanation of how the default send direction is determined, see send(FCPPluginMessage) . |
java.lang.String |
toString() |
void send(FCPPluginConnection.SendDirection direction, FCPPluginMessage message) throws java.io.IOException
handlePluginFCPMessage(FCPPluginConnection, FCPPluginMessage)
.sendSynchronous(SendDirection, FCPPluginMessage, long)
.sendSynchronous(
SendDirection, FCPPluginMessage, long)
:FredPluginFCPMessageHandler
. It will
not be directly available to the thread which called this function.IOException
you nevertheless must
not assume that the message has been sent.IOException
, you must assume that the
connection is dead and the message has not been sent.FCPPluginMessage.identifier
as the original message.FredPluginFCPMessageHandler.ServerSideFCPMessageHandler
or
FredPluginFCPMessageHandler.ClientSideFCPMessageHandler
, be sure to read the JavaDoc
of the message handling functions first as it puts additional constraints on the usage
of the FCPPluginConnection they receive.direction
- Whether to send the message to the server or the client message handler.send(FCPPluginMessage)
to avoid having to specify this.message
- You must not send the same message twice: This can break sendSynchronous(
SendDirection, FCPPluginMessage, long)
.java.io.IOException
- If the connection has been closed meanwhile.ATTENTION: If this is not thrown, that does NOT mean that the connection is
alive. Messages are sent asynchronously, so it can happen that a closed connection is not
detected before this function returns.
The only way of knowing that a send succeeded is by receiving a reply message in your
FredPluginFCPMessageHandler
.
If you need to know whether the send succeeded on the same thread which shall call the
send function, you can also use sendSynchronous(SendDirection, FCPPluginMessage,
long)
which will return the reply right away.
You may instead use the blocking sendSynchronous() if your thread needs to know whether
messages arrived, to ensure a certain order of arrival, or to know the reply to a
message.
void send(FCPPluginMessage message) throws java.io.IOException
send(SendDirection, FCPPluginMessage)
with the FCPPluginConnection.SendDirection
parameter being the default direction.PluginRespirator#connectToOtherPlugin(String, ClientSideFCPMessageHandler)
.handlePluginFCPMessage(FCPPluginConnection, FCPPluginMessage)
.handlePluginFCPMessage(FCPPluginConnection, FCPPluginMessage)
.PluginRespirator.getPluginConnectionByID(UUID)
.java.io.IOException
FCPPluginMessage sendSynchronous(FCPPluginConnection.SendDirection direction, FCPPluginMessage message, long timeoutNanoSeconds) throws java.io.IOException, java.lang.InterruptedException
FredPluginFCPMessageHandler.handlePluginFCPMessage(FCPPluginConnection,
FCPPluginMessage)
of the remote side.send(SendDirection, FCPPluginMessage)
:FredPluginFCPMessageHandler.handlePluginFCPMessage(
FCPPluginConnection, FCPPluginMessage)
in another thread.Thread.interrupt()
upon pending calls
to this function during shutdown. You must keep track of threads which are executing
this function on your own, and call Thread.interrupt()
upon them at shutdown of your
plugin. The interruption will then cause the function to throw InterruptedException
quickly, which your calling threads should obey by exiting to ensure a fast shutdown.FCPPluginMessage.construct(
SimpleFieldSet, Bucket)
(or one of its shortcuts) and do not call this function twice upon
the same message.FredPluginFCPMessageHandler
instead of being
returned from this function.FredPluginFCPMessageHandler
should just drop reply messages which were not expected
and log them as at Logger.LogLevel.WARNING
. The information here was merely provided to help
you with debugging the cause of these events, not to make you change your code
to assume that sendSynchronous does not work. For clean code, please write it in a way which
assumes that the function works properly.FredPluginFCPMessageHandler.ServerSideFCPMessageHandler
or
FredPluginFCPMessageHandler.ClientSideFCPMessageHandler
, be sure to read the JavaDoc
of the message handling functions first as it puts additional constraints on the usage
of the FCPPluginConnection they receive.direction
- Whether to send the message to the server or the client message handler.sendSynchronous(FCPPluginMessage, long)
to avoid having to specify
this.message
- Must be constructed using FCPPluginMessage.construct(SimpleFieldSet,
Bucket)
or one of its shortcuts.timeoutNanoSeconds
- The function will wait for a reply to arrive for this amount of time.IOException
is thrown.FredPluginFCPMessageHandler
.TimeUnit
to easily convert seconds,
milliseconds, etc. to nanoseconds.FCPPluginMessage
which the remote partner sent to your message.FCPPluginMessage.errorCode
and FCPPluginMessage.errorMessage
might indicate the type of the error.java.io.IOException
- If the given timeout expired before a reply was received or if the connection has
been closed before even sending the message.java.lang.InterruptedException
- If another thread called Thread.interrupt()
upon the thread which you used to
execute this function.An overview of how synchronous sends and especially their threading work internally is
provided at the map which stores them.
,
The non-blocking, asynchronous send() should be used instead of this whenever possible.
FCPPluginMessage sendSynchronous(FCPPluginMessage message, long timeoutNanoSeconds) throws java.io.IOException, java.lang.InterruptedException
sendSynchronous(SendDirection, FCPPluginMessage, long)
with the
FCPPluginConnection.SendDirection
parameter being the default direction.send(FCPPluginMessage)
.java.io.IOException
java.lang.InterruptedException
java.util.UUID getID()
ID can be used with {@link PluginRespirator#getPluginConnectionByID(UUID)}.
java.lang.String toString()
toString
in class java.lang.Object