Hi, The review of the FCP rewrite is a huge undertaking, so Iâll limit myself to the functional changes since the review of bertm.
To get only these, I filtered the commits by their commit messages[1] and removed anything which looked like a documentation change or purely stylistic changes. As a result the number of line changes (removed + added) went down from 13834 to 1211. As first step Iâll purely paste the diff here (and attach it along with a htmlized version for people without diff highlighting). @xor: Please have a look at the commits and check whether any important functional change is missing (if yes, please add it). Also please give us a 6-line description of the comments from bertm in his review. We must be able to verify against that, and each one of us clicking each outdated comment on github is not a viable way to do that. Best wishes, Arne [1]: hg log --template "{node} : {desc|firstline}\n" -r "6c438b4c279d0a671be6516cee34052c7c3d5101::29ba0908ee2a81afdfaa1ab369382e1ad892b726" | sed "s/.*JavaDoc.*//" | sed "s/.*TODO.*//" | sed "s/.*Organize.*//" | sed s/.*ocument.*// | sed s/.*explain.*// | sed s/.*spelling.*// | sed s/.*sort.*// | sed s/.*[Ii]ndent.*// | sed s/.*[Mm]erge.*// | sed s/.*[Mm]ove.*// | sed s/.*[Ee]xtract.*// | sed s/.*[Rr]ename.*// | cut -d : -f 1 | xargs hg export # HG changeset patch # User xor-freenet <xor at freenetproject.org> # Date 1420557120 -3600 # Tue Jan 06 16:12:00 2015 +0100 # Node ID 6c438b4c279d0a671be6516cee34052c7c3d5101 # Parent 754640ea02b7a7a8b2165aa759c5eb10eb02eff0 FCPPluginClient.send(): Improve readability - Improve documentation for the codepath of delivering messages to sendSynchronous() threads. - Rename maybeDispatchMessageLocallyToSendSynchronousThread() to dispatchMessageLocallyToSendSynchronousThreadIfExisting(). Thats more uniform with the other dispatch functions since they now all are prefixed with "dispatch" , and the "IfExisting" is more self-explanatory than "maybe" because it implies the condition upon which it is done: If a sendSynchronous() thread exists. diff -r 754640ea02b7 -r 6c438b4c279d src/freenet/clients/fcp/FCPPluginClient.java --- a/src/freenet/clients/fcp/FCPPluginClient.java Wed Dec 10 04:23:00 2014 +0100 +++ b/src/freenet/clients/fcp/FCPPluginClient.java Tue Jan 06 16:12:00 2015 +0100 @@ -643,14 +643,23 @@ : "We already decided that the message handler exists locally. " + "We should have only decided so if the handler is not null."; - // Since the message handler is determined to be local at this point, we now must check - // whether it is a blocking sendSynchronous() thread instead of a regular - // FredPluginFCPMessageHandler. - // sendSynchronous() does the following: It sends a message and then blocks its thread - // waiting for a message replying to it to arrive so it can return it to the caller. - // If the message we are processing here is a reply, it might be the one which a - // sendSynchronous() is waiting for. - if(maybeDispatchMessageLocallyToSendSynchronousThread(direction, message)) + // The message handler is determined to be local at this point. There are two possible + // types of local message handlers: + // 1) An object provided by the server/client which implements FredPluginFCPMessageHandler. + // The message is delivered by executing a callback on that object, with the message + // as parameter. + // 2) A call to sendSynchronous() which is blocking because it is waiting for a reply + // to the message it sent so it can return the reply message to the caller. + // The reply message is delivered by passing it to the sendSynchronous() thread through + // an internal table of this class. + // + // The following function call checks for whether case 2 applies, and handles it if yes: + // If there is such a waiting sendSynchronous() thread, it delivers the message to it, and + // returns true, and we are done: By contract, messages are preferably delivered to + // sendSynchronous(). + // If there was no sendSynchronous() thread, it returns false, and we must continue to + // handle case 1. + if(dispatchMessageLocallyToSendSynchronousThreadIfExisting(direction, message)) return; // We now know that the message handler is not attached by network, and that it is not a @@ -725,8 +734,9 @@ * An overview of how synchronous sends and especially their threading work internally * is provided at the map which stores them. */ - private boolean maybeDispatchMessageLocallyToSendSynchronousThread(final SendDirection direction, - final FCPPluginMessage message) { + private boolean dispatchMessageLocallyToSendSynchronousThreadIfExisting( + final SendDirection direction, final FCPPluginMessage message) { + // Since the message handler is determined to be local at this point, we now must check // whether it is a blocking sendSynchronous() thread instead of a regular // FredPluginFCPMessageHandler. # HG changeset patch # User xor-freenet <xor at freenetproject.org> # Date 1420559434 -3600 # Tue Jan 06 16:50:34 2015 +0100 # Node ID 53db2d8eab097abbb354db7f4ed641362addaecb # Parent 6c438b4c279d0a671be6516cee34052c7c3d5101 FCPConnectionHandler: Add send() to replace public member variable usage - Temporarily deprecate the function of the member variable which led to public usage of it. - Add documentation about the deprecation to tell people to replace it with send(). - Also document the temporary character of the deprecation. diff -r 6c438b4c279d -r 53db2d8eab09 src/freenet/clients/fcp/FCPConnectionHandler.java --- a/src/freenet/clients/fcp/FCPConnectionHandler.java Tue Jan 06 16:12:00 2015 +0100 +++ b/src/freenet/clients/fcp/FCPConnectionHandler.java Tue Jan 06 16:50:34 2015 +0100 @@ -166,7 +166,21 @@ // TODO: When getting rid of the non-UUID connectionIdentifier, use UUID.randomUUID(); this.connectionIdentifierUUID = UUID.nameUUIDFromBytes(identifier); } - + + /** + * Queues the message for sending at the {@link FCPConnectionOutputHandler}.<br> + * <br> + * + * ATTENTION: The function will return immediately before even trying to send the message, the + * message will be sent asynchronously.<br> + * As a consequence, this function not throwing does not give any guarantee whatsoever that the + * message will ever be sent. + */ + @SuppressWarnings("deprecation") + public final void send(final FCPMessage message) { + outputHandler.queue(message); + } + void start() { inputHandler.start(); outputHandler.start(); diff -r 6c438b4c279d -r 53db2d8eab09 src/freenet/clients/fcp/FCPConnectionOutputHandler.java --- a/src/freenet/clients/fcp/FCPConnectionOutputHandler.java Tue Jan 06 16:12:00 2015 +0100 +++ b/src/freenet/clients/fcp/FCPConnectionOutputHandler.java Tue Jan 06 16:50:34 2015 +0100 @@ -119,6 +119,19 @@ } } + /** + * @deprecated Use {@link FCPConnectionHandler#send(FCPMessage)} instead of using public + * access to the member variable {@link FCPConnectionHandler#outputHandler} to call + * this function here upon the outputHandler. In other words: Replace + * <code>fcpConnectionHandler.outputHandler.queue(...)</code> + * with <code>fcpConnectionHandler.send(...)</code><br> + * TODO: The deprecation is merely to enforce people to stop using the said + * member variable in a public way. The function itself is fine to stay. Once the + * public usage has been replaced by the suggested way of using send(), please make + * the member variable {@link FCPConnectionHandler#outputHandler} private and remove + * the deprecation at this function here. + */ + @Deprecated public void queue(FCPMessage msg) { if(logDEBUG) Logger.debug(this, "Queueing "+msg, new Exception("debug")); # HG changeset patch # User xor-freenet <xor at freenetproject.org> # Date 1420559621 -3600 # Tue Jan 06 16:53:41 2015 +0100 # Node ID de6402f91d982b00bbce5fd982266dc6ee536933 # Parent 53db2d8eab097abbb354db7f4ed641362addaecb FCPPluginClient: Don't use FCPConnectionHandler member variable The replacement of queue() with send() is what is suggested at queue()'s JavaDoc. diff -r 53db2d8eab09 -r de6402f91d98 src/freenet/clients/fcp/FCPPluginClient.java --- a/src/freenet/clients/fcp/FCPPluginClient.java Tue Jan 06 16:50:34 2015 +0100 +++ b/src/freenet/clients/fcp/FCPPluginClient.java Tue Jan 06 16:53:41 2015 +0100 @@ -711,7 +711,7 @@ if (clientConnection.isClosed()) throw new IOException("Connection to client closed for " + this); - clientConnection.outputHandler.queue(new FCPPluginServerMessage(serverPluginName, message)); + clientConnection.send(new FCPPluginServerMessage(serverPluginName, message)); } /** # HG changeset patch # User xor-freenet <xor at freenetproject.org> # Date 1420565343 -3600 # Tue Jan 06 18:29:03 2015 +0100 # Node ID 42790e12661341c6fac8a1e4e3365bfcdeb6796a # Parent d328a143bcec85e4e3369b357cadee9ced0f7d03 PluginManager.getFCPPlugin(): Explain deprecation diff -r d328a143bcec -r 42790e126613 src/freenet/pluginmanager/PluginManager.java --- a/src/freenet/pluginmanager/PluginManager.java Tue Jan 06 18:20:46 2015 +0100 +++ b/src/freenet/pluginmanager/PluginManager.java Tue Jan 06 18:29:03 2015 +0100 @@ -938,7 +938,9 @@ * look for a FCPPlugin with given classname * @param plugname * @return the plugin or null if not found - * @deprecated Use {@link #getPluginFCPServer(String)} instead. + * @deprecated The {@link FredPluginFCP} API, which this returns, was deprecated to be replaced + * by {@link FredPluginFCPMessageHandler}. The equivalent function for the new API + * is {link #getPluginFCPServer(String)}. */ @Deprecated public FredPluginFCP getFCPPlugin(String plugname) { # HG changeset patch # User xor-freenet <xor at freenetproject.org> # Date 1420565858 -3600 # Tue Jan 06 18:37:38 2015 +0100 # Node ID 69be82200079f159c0cf6771987eeb69a3fc7b91 # Parent 6f0719590f85a66a5dce254ed5b7fcc73a79697b PluginManager.getFCPPlugin(): Explain how to finish the deprecation diff -r 6f0719590f85 -r 69be82200079 src/freenet/pluginmanager/PluginManager.java --- a/src/freenet/pluginmanager/PluginManager.java Tue Jan 06 18:33:02 2015 +0100 +++ b/src/freenet/pluginmanager/PluginManager.java Tue Jan 06 18:37:38 2015 +0100 @@ -939,8 +939,13 @@ * @param plugname * @return the plugin or null if not found * @deprecated The {@link FredPluginFCP} API, which this returns, was deprecated to be replaced - * by {@link FredPluginFCPMessageHandler.ServerSideFCPMessageHandler}. The - * equivalent function for the new API is {link #getPluginFCPServer(String)}. + * by {@link FredPluginFCPMessageHandler.ServerSideFCPMessageHandler}. + * Plugin authors should implement the new interface instead of the old, + * and this codepath to support plugins which implement the old interface should + * be removed one day. No new code will be needed then: The code to use the + * new interface already exists in its own codepath - the equivalent function for + * the new API is {link #getPluginFCPServer(String)}, and it is already being used + * automatically for plugins which implement it. */ @Deprecated public FredPluginFCP getFCPPlugin(String plugname) { # HG changeset patch # User xor-freenet <xor at freenetproject.org> # Date 1420833646 -3600 # Fri Jan 09 21:00:46 2015 +0100 # Node ID a3b255be89e56da622d9c6c14efdbd19e04caee6 # Parent 8bbde4c2a2db3017fb0ff186e1c22ade08815abc FCPPluginMessage.constructRawMessage(): Trim visibility diff -r 8bbde4c2a2db -r a3b255be89e5 src/freenet/clients/fcp/FCPPluginMessage.java --- a/src/freenet/clients/fcp/FCPPluginMessage.java Fri Jan 09 20:56:17 2015 +0100 +++ b/src/freenet/clients/fcp/FCPPluginMessage.java Fri Jan 09 21:00:46 2015 +0100 @@ -294,7 +294,7 @@ * See the JavaDoc of the member variables with the same name as the parameters for an * explanation of the parameters.<br> */ - public static FCPPluginMessage constructRawMessage(ClientPermissions permissions, + static FCPPluginMessage constructRawMessage(ClientPermissions permissions, String identifier, SimpleFieldSet params, Bucket data, Boolean success, String errorCode, String errorMessage) { # HG changeset patch # User xor-freenet <xor at freenetproject.org> # Date 1420835780 -3600 # Fri Jan 09 21:36:20 2015 +0100 # Node ID d932dec809fd97d223ae73c3f58b7c69f4750576 # Parent a424a96cb813df6751f7dc5f389bb9643f854680 FCPPluginClient.isServerDead(): Trim visibility diff -r a424a96cb813 -r d932dec809fd src/freenet/clients/fcp/FCPPluginClient.java --- a/src/freenet/clients/fcp/FCPPluginClient.java Fri Jan 09 21:31:48 2015 +0100 +++ b/src/freenet/clients/fcp/FCPPluginClient.java Fri Jan 09 21:36:20 2015 +0100 @@ -220,7 +220,7 @@ * a generic class WeakValueMap from that one and use to to power both the existing * class and the one which deals with this variable here. * </p> - * @see #isServerDead() Public interface function to check whether the WeakReference is nulled. + * @see #isServerDead() Use isServerDead() to check whether this WeakReference is nulled. */ private final WeakReference<ServerSideFCPMessageHandler> server; @@ -475,6 +475,12 @@ } /** + * ATTENTION: Only for internal use in {@link FCPConnectionHandler#getPluginClient(String)}.<br> + * Server / client code should always {@link #send(SendDirection, FCPPluginMessage)} messages + * to check whether the connection is alive. (To ensure that the implementation of this class + * could safely be changed to allow the server to be attached by network instead of always + * running locally in the same node as it currently is.) + * * @return <p>True if the server plugin has been unloaded. Once this returns true, this * FCPPluginClient <b>cannot</b> be repaired, even if the server plugin is loaded again. * Then you should discard this client and create a fresh one.</p> @@ -486,7 +492,7 @@ * is alive merely an indication, true / server is dead as the definite truth.<br> * If you need to validate a connection to be alive, send periodic pings. </p> */ - public boolean isServerDead() { + boolean isServerDead() { return server.get() == null; } # HG changeset patch # User xor-freenet <xor at freenetproject.org> # Date 1420837732 -3600 # Fri Jan 09 22:08:52 2015 +0100 # Node ID e255017cc021aae2ee7ff7a773b7ad37343d37ea # Parent d932dec809fd97d223ae73c3f58b7c69f4750576 FCPPluginClient.getServerPluginName(): Trim visibility The JavaDoc already labeled it as "for internal use" diff -r d932dec809fd -r e255017cc021 src/freenet/clients/fcp/FCPPluginClient.java --- a/src/freenet/clients/fcp/FCPPluginClient.java Fri Jan 09 21:36:20 2015 +0100 +++ b/src/freenet/clients/fcp/FCPPluginClient.java Fri Jan 09 22:08:52 2015 +0100 @@ -470,7 +470,7 @@ * The class name of the plugin to which this FCPPluginClient is connected. * @see This is for internal usage by {@link FCPConnectionHandler#getPluginClient(String)}. */ - public String getServerPluginName() { + String getServerPluginName() { return serverPluginName; } # HG changeset patch # User xor-freenet <xor at freenetproject.org> # Date 1420840915 -3600 # Fri Jan 09 23:01:55 2015 +0100 # Node ID 7209339131a01c925783a1e2decf1b3e4d73fe66 # Parent 7a8d58eef9937aeeea0fe71ff477277362f30c72 FCPPluginConnection: Clarify that server is a plugin, client may not be Also adapt JavaDoc to rename "Client" -> "Connection" for this section. More adaption w.r.t. that will follow. diff -r 7a8d58eef993 -r 7209339131a0 src/freenet/clients/fcp/FCPPluginConnection.java --- a/src/freenet/clients/fcp/FCPPluginConnection.java Fri Jan 09 22:56:04 2015 +0100 +++ b/src/freenet/clients/fcp/FCPPluginConnection.java Fri Jan 09 23:01:55 2015 +0100 @@ -15,7 +15,10 @@ import freenet.support.api.Bucket; /** - * <p>An FCP client communicating with a plugin running within fred.</p> + * An FCP connection between:<br> + * - a fred plugin which provides its services by a FCP server.<br> + * - a client application which uses those services. The client may be a plugin as well, or be + * connected by a networked FCP connection.<br><br> * * <h1>How to use this properly</h1><br> * # HG changeset patch # User xor-freenet <xor at freenetproject.org> # Date 1420914720 -3600 # Sat Jan 10 19:32:00 2015 +0100 # Node ID c54c14dbff2a00eb0097a252ed5768a12374f1c8 # Parent c9d86a341c0d227a734ae0c344bb1a2991416c04 FCPPluginConnection: Add missing license header diff -r c9d86a341c0d -r c54c14dbff2a src/freenet/clients/fcp/FCPPluginConnection.java --- a/src/freenet/clients/fcp/FCPPluginConnection.java Fri Jan 09 23:41:31 2015 +0100 +++ b/src/freenet/clients/fcp/FCPPluginConnection.java Sat Jan 10 19:32:00 2015 +0100 @@ -1,3 +1,6 @@ +/* This code is part of Freenet. It is distributed under the GNU General + * Public License, version 2 (or at your option any later version). See + * http://www.gnu.org/ for further details of the GPL. */ package freenet.clients.fcp; import java.io.IOException; # HG changeset patch # User xor-freenet <xor at freenetproject.org> # Date 1420917113 -3600 # Sat Jan 10 20:11:53 2015 +0100 # Node ID 1824423b2d8a13424ab19e9d11edbeca7343dfe4 # Parent 4a46dadc19d0d87833799846d648168327bfe541 FCPPluginConnection.send(): Fix "synchronousSend()" function name mixup diff -r 4a46dadc19d0 -r 1824423b2d8a src/freenet/clients/fcp/FCPPluginConnection.java --- a/src/freenet/clients/fcp/FCPPluginConnection.java Sat Jan 10 20:09:35 2015 +0100 +++ b/src/freenet/clients/fcp/FCPPluginConnection.java Sat Jan 10 20:11:53 2015 +0100 @@ -107,16 +107,16 @@ * SendDirection, FCPPluginMessage, long)}:<br> * - It may return <b>before</b> the message has been sent.<br> * The message sending happens in another thread so this function can return immediately.<br> - * In opposite to that, a synchronousSend() would wait for a reply to arrive, so once it + * 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.<br> * - The reply is delivered to your message handler {@link FredPluginFCPMessageHandler}. It will * not be directly available to the thread which called this function.<br> - * A synchronousSend() would return the reply to the caller.<br> + * A sendSynchronous() would return the reply to the caller.<br> * - You have no guarantee whatsoever that the message will be delivered.<br> - * A synchronousSend() will tell you that a reply was received, which guarantees that the + * A sendSynchronous() will tell you that a reply was received, which guarantees that the * message was delivered.<br> * - The order of arrival of messages is random.<br> - * A synchronousSend() only returns after the message was delivered already, so by calling + * A sendSynchronous() only returns after the message was delivered already, so by calling * it multiple times in a row on the same thread, you would enforce the order of the * messages arriving at the remote side.<br><br> * # HG changeset patch # User xor-freenet <xor at freenetproject.org> # Date 1420920960 -3600 # Sat Jan 10 21:16:00 2015 +0100 # Node ID 293ceea684646899e6658fdb82edf99bf21cfa13 # Parent 29d4a0d2b39e673173f28152e90a3c4105b8963d FCPPluginConnection: Add getServerPluginName() Already implemented in the interface's implementation FCPPluginClient. I had previously not added it to the interface since I wanted to keep it package-private and interfaces can only have public functions. But I would prefer for the package's internal code to typify variables by the interface and not by the implementation, so the interface needs to have that function. diff -r 29d4a0d2b39e -r 293ceea68464 src/freenet/clients/fcp/FCPPluginClient.java --- a/src/freenet/clients/fcp/FCPPluginClient.java Sat Jan 10 21:10:08 2015 +0100 +++ b/src/freenet/clients/fcp/FCPPluginClient.java Sat Jan 10 21:16:00 2015 +0100 @@ -408,11 +408,7 @@ return id; } - /** - * The class name of the plugin to which this FCPPluginClient is connected. - * @see This is for internal usage by {@link FCPConnectionHandler#getPluginClient(String)}. - */ - String getServerPluginName() { + @Override public String getServerPluginName() { return serverPluginName; } diff -r 29d4a0d2b39e -r 293ceea68464 src/freenet/clients/fcp/FCPPluginConnection.java --- a/src/freenet/clients/fcp/FCPPluginConnection.java Sat Jan 10 21:10:08 2015 +0100 +++ b/src/freenet/clients/fcp/FCPPluginConnection.java Sat Jan 10 21:16:00 2015 +0100 @@ -360,4 +360,9 @@ /** @return A verbose String containing the internal state. Useful for debug logs. */ public String toString(); + /** + * The class name of the plugin to which this FCPPluginConnection is connected. + * @see This is for internal usage by {@link FCPConnectionHandler#getPluginClient(String)}. + */ + public String getServerPluginName(); } \ No newline at end of file # HG changeset patch # User xor-freenet <xor at freenetproject.org> # Date 1420924529 -3600 # Sat Jan 10 22:15:29 2015 +0100 # Node ID 142f2abcd7ec60b0ef70389cab8e67456270f707 # Parent ece7e2c466440261975c409b4edddf8d3fa64058 FCPPluginConnection.getServerPluginName(): Fix useless line wrap diff -r ece7e2c46644 -r 142f2abcd7ec src/freenet/clients/fcp/FCPPluginConnection.java --- a/src/freenet/clients/fcp/FCPPluginConnection.java Sat Jan 10 21:24:28 2015 +0100 +++ b/src/freenet/clients/fcp/FCPPluginConnection.java Sat Jan 10 22:15:29 2015 +0100 @@ -363,9 +363,8 @@ /** * The class name of the FCP server plugin to which this FCPPluginConnection is connected.<br> * This is what was specified for the parameter <code>String pluginName</code> by the client - * when connecting by calling - * {@link PluginRespirator#connectToOtherPlugin(String, ClientSideFCPMessageHandler)} - * . + * when connecting by calling {@link PluginRespirator#connectToOtherPlugin(String, + * ClientSideFCPMessageHandler)}. */ public String getServerPluginName(); } \ No newline at end of file # HG changeset patch # User xor-freenet <xor at freenetproject.org> # Date 1421060986 -3600 # Mon Jan 12 12:09:46 2015 +0100 # Node ID ae4a097065b3ad9d33a0fea040cfeecb84fb60dd # Parent 0cd24017f93dfcc44738eff80344e83e1b19ffc8 FCPPluginClient: Fix excessive line length diff -r 0cd24017f93d -r ae4a097065b3 src/freenet/clients/fcp/FCPPluginClient.java --- a/src/freenet/clients/fcp/FCPPluginClient.java Mon Jan 12 12:06:04 2015 +0100 +++ b/src/freenet/clients/fcp/FCPPluginClient.java Mon Jan 12 12:09:46 2015 +0100 @@ -392,8 +392,8 @@ * - {@link PluginRespirator#connectToOtherPlugin(String, ClientSideFCPMessageHandler)} can then * be used for obtaining a FCPPluginClient instead of this constructor. This also is a * function which is used in regular mode of operation.<br> - * - The aforementioned {@link PluginRespirator#getPluginConnectionByID(UUID)} will then work for - * FCPPluginClients obtained through the connectToOtherPlugin(). + * - The aforementioned {@link PluginRespirator#getPluginConnectionByID(UUID)} will then work + * for FCPPluginClients obtained through the connectToOtherPlugin(). */ public static FCPPluginClient constructForUnitTest(ServerSideFCPMessageHandler server, ClientSideFCPMessageHandler client) { # HG changeset patch # User xor-freenet <xor at freenetproject.org> # Date 1421061337 -3600 # Mon Jan 12 12:15:37 2015 +0100 # Node ID 29b36e8801298a170e1c99c9c419848a29094d07 # Parent 33564410d690044fc680d32e3d21c32639ae8d71 FCPPluginConnection: Sort functions by importance diff -r 33564410d690 -r 29b36e880129 src/freenet/clients/fcp/FCPPluginConnection.java --- a/src/freenet/clients/fcp/FCPPluginConnection.java Mon Jan 12 12:14:14 2015 +0100 +++ b/src/freenet/clients/fcp/FCPPluginConnection.java Mon Jan 12 12:15:37 2015 +0100 @@ -88,12 +88,6 @@ public interface FCPPluginConnection { /** - * @return A unique identifier among all FCPPluginConnections. - * @see The ID can be used with {@link PluginRespirator#getPluginConnectionByID(UUID)}. - */ - public UUID getID(); - - /** * 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.<br/> * Thus, to prevent us from having to duplicate the send functions, this enum specifies in which @@ -356,8 +350,11 @@ SendDirection direction, FCPPluginMessage message, long timeoutNanoSeconds) throws IOException, InterruptedException; - /** @return A verbose String containing the internal state. Useful for debug logs. */ - public String toString(); + /** + * @return A unique identifier among all FCPPluginConnections. + * @see The ID can be used with {@link PluginRespirator#getPluginConnectionByID(UUID)}. + */ + public UUID getID(); /** * The class name of the FCP server plugin to which this FCPPluginConnection is connected.<br> @@ -366,4 +363,8 @@ * ClientSideFCPMessageHandler)}. */ public String getServerPluginName(); + + /** @return A verbose String containing the internal state. Useful for debug logs. */ + public String toString(); + } \ No newline at end of file # HG changeset patch # User xor-freenet <xor at freenetproject.org> # Date 1421260650 -3600 # Wed Jan 14 19:37:30 2015 +0100 # Node ID 788be9e7cba7f9710f0238170c73b80eb06153c2 # Parent d3cef1a22d8cb721113847a80c6b280a900c7e72 Fix missed "FCPPluginClient" -> "FCPPluginConnectionImpl" renaming The "Client" -> "Connection" interface extraction + renaming is not finished yet, as some places where usage of FCPPluginConnectionImpl has to be replaced with FCPPluginConnection might still remain. This merely fixes all remaining textual references of "FCPPluginClient" diff -r d3cef1a22d8c -r 788be9e7cba7 src/freenet/clients/fcp/FCPPluginConnectionImpl.java --- a/src/freenet/clients/fcp/FCPPluginConnectionImpl.java Wed Jan 14 19:28:59 2015 +0100 +++ b/src/freenet/clients/fcp/FCPPluginConnectionImpl.java Wed Jan 14 19:37:30 2015 +0100 @@ -123,7 +123,7 @@ /** - * Unique identifier among all FCPPluginClients. + * Unique identifier among all {@link FCPPluginConnection}s and FCPPluginConnectionImpls * @see #getID() */ private final UUID id = UUID.randomUUID(); @@ -394,7 +394,7 @@ * be used for obtaining a FCPPluginConnectionImpl instead of this constructor. This also is a * function which is used in regular mode of operation.<br> * - The aforementioned {@link PluginRespirator#getPluginConnectionByID(UUID)} will then work - * for FCPPluginClients obtained through the connectToOtherPlugin(). + * for FCPPluginConnectionImpls obtained through the connectToOtherPlugin(). */ public static FCPPluginConnectionImpl constructForUnitTest(ServerSideFCPMessageHandler server, ClientSideFCPMessageHandler client) { # HG changeset patch # User xor-freenet <xor at freenetproject.org> # Date 1421261915 -3600 # Wed Jan 14 19:58:35 2015 +0100 # Node ID ec7dc79c251d2758ba519f5da880ecb78d008c8a # Parent aae324185eebed32e663508effc55aaa631f54f2 FCPConnectionHandler.getFCPPluginConnection(): Trim visibility Only meant to be used by the package for message deployment and thus doesn't have to be public. diff -r aae324185eeb -r ec7dc79c251d src/freenet/clients/fcp/FCPConnectionHandler.java --- a/src/freenet/clients/fcp/FCPConnectionHandler.java Wed Jan 14 19:44:32 2015 +0100 +++ b/src/freenet/clients/fcp/FCPConnectionHandler.java Wed Jan 14 19:58:35 2015 +0100 @@ -634,7 +634,7 @@ * @throws PluginNotFoundException * If the specified plugin is not loaded or does not provide an FCP server. */ - public FCPPluginConnection getFCPPluginConnection(String serverPluginName) + FCPPluginConnection getFCPPluginConnection(String serverPluginName) throws PluginNotFoundException { // The suspected typical usage pattern of this function is that the great majority of calls # HG changeset patch # User xor-freenet <xor at freenetproject.org> # Date 1421266988 -3600 # Wed Jan 14 21:23:08 2015 +0100 # Node ID 6362805419f753e3730965e28d2b9c68047c8f82 # Parent 022e936b8617482985c6c3cf8c6a065239293018 FCPPluginConnectionImpl: Use parent interface as type when sensible Not complete yet, more similar commits to follow for this class. diff -r 022e936b8617 -r 6362805419f7 src/freenet/clients/fcp/FCPPluginConnectionImpl.java --- a/src/freenet/clients/fcp/FCPPluginConnectionImpl.java Wed Jan 14 21:18:18 2015 +0100 +++ b/src/freenet/clients/fcp/FCPPluginConnectionImpl.java Wed Jan 14 21:23:08 2015 +0100 @@ -59,14 +59,14 @@ * - The {@link FCPConnectionInputHandler} uses {@link FCPMessage#create(String, SimpleFieldSet)} * to parse the message and obtain the actual {@link FCPPluginClientMessage}.<br/> * - The {@link FCPPluginClientMessage} uses {@link FCPConnectionHandler#getFCPPluginConnection( - * String)} to obtain the FCPPluginConnectionImpl to the server.<br/> - * - The {@link FCPPluginClientMessage} uses {@link FCPPluginConnectionImpl#send(SendDirection, + * String)} to obtain the FCPPluginConnection to the server.<br/> + * - The {@link FCPPluginClientMessage} uses {@link FCPPluginConnection#send(SendDirection, * FCPPluginMessage)} to send the message to the server plugin.<br/> * - The FCP server plugin handles the message at * {@link ServerSideFCPMessageHandler#handlePluginFCPMessage(FCPPluginConnection, * FCPPluginMessage)}.<br/> - * - As each FCPPluginConnectionImpl object exists for the lifetime of a network connection, the FCP - * server plugin may store the UUID of the FCPPluginConnectionImpl and query it via + * - As each FCPPluginConnection object exists for the lifetime of a network connection, the FCP + * server plugin may store the UUID of the FCPPluginConnection and query it via * {@link PluginRespirator#getPluginConnectionByID(UUID)}. It can use this to send messages to the * client application on its own, that is not triggered by any client messages.<br/> * </p> @@ -76,29 +76,30 @@ * FredPluginFCPMessageHandler.ClientSideFCPMessageHandler)} to try to create a connection.<br/> * - The {@link PluginRespirator} uses {@link FCPServer#createFCPPluginConnectionForIntraNodeFCP( * String, FredPluginFCPMessageHandler.ClientSideFCPMessageHandler)} to get a - * FCPPluginConnectionImpl.<br> - * - The client plugin uses the send functions of the FCPPluginConnectionImpl. Those are the same as + * FCPPluginConnection.<br> + * - The client plugin uses the send functions of the FCPPluginConnection. Those are the same as * with networked FCP connections.<br/> * - The FCP server plugin handles the message at * {@link ServerSideFCPMessageHandler#handlePluginFCPMessage(FCPPluginConnection, * FCPPluginMessage)}. That is the same handler as with networked FCP connections.<br/> - * - The client plugin keeps a strong reference to the FCPPluginConnectionImpl in memory as long as + * - The client plugin keeps a strong reference to the FCPPluginConnection in memory as long as * it wants to keep the connection open.<br/> * - Same as with networked FCP connections, the FCP server plugin can store the UUID of the - * FCPPluginConnectionImpl and in the future re-obtain the connection by + * FCPPluginConnection and in the future re-obtain the connection by * {@link PluginRespirator#getPluginConnectionByID(UUID)}. It can use this to send messages to the * client application on its own, that is not triggered by any client messages. <br/> * - Once the client plugin is done with the connection, it discards the strong reference to the - * FCPPluginConnectionImpl. Because the {@link FCPPluginConnectionTracker} monitors garbage - * collection of {@link FCPPluginConnectionImpl} objects, getting rid of all strong references to - * a {@link FCPPluginConnectionImpl} is sufficient as a disconnection mechanism.<br/> + * FCPPluginConnection. Because the {@link FCPPluginConnectionTracker} monitors garbage + * collection of FCPPluginConnection objects, getting rid of all strong references to a + * FCPPluginConnection is sufficient as a disconnection mechanism.<br/> * Thus, an intra-node client connection is considered as disconnected once the - * FCPPluginConnectionImpl is not strongly referenced by the client plugin anymore. If a server - * plugin then tries to obtain the client by its UUID again (via the aforementioned + * FCPPluginConnection is not strongly referenced by the client plugin anymore. If a server + * plugin then tries to obtain the client connection by its UUID again (via the aforementioned * {@link PluginRespirator#getPluginConnectionByID(UUID)}, the get will fail. So if the server - * plugin stores client UUIDs, it needs no special disconnection mechanism except for periodically - * trying to send a message to each client. Once obtaining the client by its UUID fails, or - * sending the message fails, the server can opportunistically purge the UUID from its database. + * plugin stores connection UUIDs, it needs no special disconnection mechanism except for + * periodically trying to send a message to each client. Once obtaining the client connection by + * its UUID fails, or sending the message fails, the server can opportunistically purge the UUID + * from its database. * <br/>This mechanism also works for networked FCP.<br> * </p></p> */ @@ -391,10 +392,10 @@ * - As loading a plugin by JAR is the same mode of operation as with a regular node, * there will be a PluginRespirator available to it.<br> * - {@link PluginRespirator#connectToOtherPlugin(String, ClientSideFCPMessageHandler)} can then - * be used for obtaining a FCPPluginConnectionImpl instead of this constructor. This also is the + * be used for obtaining a FCPPluginConnection instead of this constructor. This also is the * function to obtain a FCPPluginConnection which is used in regular mode of operation.<br> * - The aforementioned {@link PluginRespirator#getPluginConnectionByID(UUID)} will then work - * for FCPPluginConnectionImpls obtained through the connectToOtherPlugin(). + * for FCPPluginConnections obtained through the connectToOtherPlugin(). */ public static FCPPluginConnectionImpl constructForUnitTest(ServerSideFCPMessageHandler server, ClientSideFCPMessageHandler client) { # HG changeset patch # User xor-freenet <xor at freenetproject.org> # Date 1421270478 -3600 # Wed Jan 14 22:21:18 2015 +0100 # Node ID 7d91a4958bb358dd1926a92f62c0394231a36531 # Parent 9d1d0bc056dd2234d6aaf8b8060cddc286a7ed91 FCPPluginConnectionImpl: Catch Error thrown by message handlers We should assume plugins to be buggy, and thus be conservative about catching. diff -r 9d1d0bc056dd -r 7d91a4958bb3 src/freenet/clients/fcp/FCPPluginConnectionImpl.java --- a/src/freenet/clients/fcp/FCPPluginConnectionImpl.java Wed Jan 14 21:49:33 2015 +0100 +++ b/src/freenet/clients/fcp/FCPPluginConnectionImpl.java Wed Jan 14 22:21:18 2015 +0100 @@ -668,8 +668,15 @@ FCPPluginMessage reply = null; try { - reply = messageHandler.handlePluginFCPMessage( - FCPPluginConnectionImpl.this, message); + try { + reply = messageHandler.handlePluginFCPMessage( + FCPPluginConnectionImpl.this, message); + } catch(Error e) { + // TODO: Code quality: This is a workaround for Java 6 not having + // "catch(RuntimeException | Error e)". Once we are on Java 7, remove this + // catch() block, and catch both types with the catch() block below. + throw new RuntimeException(e); + } } catch(RuntimeException e) { // The message handler is a server or client implementation, and thus as third // party code might have bugs. So we need to catch any RuntimeException here. # HG changeset patch # User xor-freenet <xor at freenetproject.org> # Date 1421270754 -3600 # Wed Jan 14 22:25:54 2015 +0100 # Node ID d93a92b458fe2e54079538e8db796b15e6420d19 # Parent 7d91a4958bb358dd1926a92f62c0394231a36531 FCPPluginConnectionImpl: Fix wrong Throwable type in error messages We also catch(Error e) above (and convert it into RuntimeException), so saying that it throw a RuntimeException is wrong. Throwable is the common parent type. diff -r 7d91a4958bb3 -r d93a92b458fe src/freenet/clients/fcp/FCPPluginConnectionImpl.java --- a/src/freenet/clients/fcp/FCPPluginConnectionImpl.java Wed Jan 14 22:21:18 2015 +0100 +++ b/src/freenet/clients/fcp/FCPPluginConnectionImpl.java Wed Jan 14 22:25:54 2015 +0100 @@ -683,9 +683,8 @@ // Notice that this is not normal mode of operation: Instead of throwing, // the JavaDoc requests message handlers to return a reply with success=false. - String errorMessage = "FredPluginFCPMessageHandler threw" - + " RuntimeException. See JavaDoc of its member interfaces for how signal" - + " errors properly." + String errorMessage = "FredPluginFCPMessageHandler threw." + + " See JavaDoc of its member interfaces for how signal errors properly." + " Client = " + FCPPluginConnectionImpl.this + "; SendDirection = " + direction + "; message = " + message; @@ -699,7 +698,7 @@ // quickly instead of having to wait for the timeout because no reply // arrives. reply = FCPPluginMessage.constructReplyMessage(message, null, null, false, - "InternalError", errorMessage + "; RuntimeException = " + e.toString()); + "InternalError", errorMessage + "; Throwable = " + e.toString()); } } # HG changeset patch # User xor-freenet <xor at freenetproject.org> # Date 1421271553 -3600 # Wed Jan 14 22:39:13 2015 +0100 # Node ID 6e8823e16ad20f38b472062f4566b5e32025fc4d # Parent b381cf165d7ec36af3a461e36ebfd3a4d8f95e2a FCPPluginConnectionImpl: Unify logging Do it the same way as in the rest of the function diff -r b381cf165d7e -r 6e8823e16ad2 src/freenet/clients/fcp/FCPPluginConnectionImpl.java --- a/src/freenet/clients/fcp/FCPPluginConnectionImpl.java Wed Jan 14 22:37:47 2015 +0100 +++ b/src/freenet/clients/fcp/FCPPluginConnectionImpl.java Wed Jan 14 22:39:13 2015 +0100 @@ -725,7 +725,9 @@ messageHandler, "Fred did not receive a reply from the message " + "handler even though it was allowed to reply. " + "This would cause sendSynchronous() to timeout! " - + "Original message: " + message); + + " connection = " + FCPPluginConnectionImpl.this + + "; SendDirection = " + direction + + "; message = " + message); } } # HG changeset patch # User xor-freenet <xor at freenetproject.org> # Date 1421271619 -3600 # Wed Jan 14 22:40:19 2015 +0100 # Node ID 9280fa1593f0ccff425467fcdce7acc636a59fed # Parent 6e8823e16ad20f38b472062f4566b5e32025fc4d FCPPluginConnectionImpl: Use parent interface as type when sensible Not complete yet, more similar commits to follow for this class diff -r 6e8823e16ad2 -r 9280fa1593f0 src/freenet/clients/fcp/FCPPluginConnectionImpl.java --- a/src/freenet/clients/fcp/FCPPluginConnectionImpl.java Wed Jan 14 22:39:13 2015 +0100 +++ b/src/freenet/clients/fcp/FCPPluginConnectionImpl.java Wed Jan 14 22:40:19 2015 +0100 @@ -779,7 +779,7 @@ /** @return A suitable {@link String} for use as the name of this thread */ @Override public String toString() { - // Don't use FCPPluginConnectionImpl.toString() as it would be too long to fit in + // Don't use FCPPluginConnection.toString() as it would be too long to fit in // the thread list on the Freenet FProxy web interface. return "FCPPluginConnection for " + serverPluginName; } # HG changeset patch # User xor-freenet <xor at freenetproject.org> # Date 1421336574 -3600 # Thu Jan 15 16:42:54 2015 +0100 # Node ID 15fef97e809064eac67f5a6b3da16d82d2a09abd # Parent 9280fa1593f0ccff425467fcdce7acc636a59fed FCPPluginConnectionImpl.sendSynchronous(): Unify error message format Also explain *what* timed out diff -r 9280fa1593f0 -r 15fef97e8090 src/freenet/clients/fcp/FCPPluginConnectionImpl.java --- a/src/freenet/clients/fcp/FCPPluginConnectionImpl.java Wed Jan 14 22:40:19 2015 +0100 +++ b/src/freenet/clients/fcp/FCPPluginConnectionImpl.java Thu Jan 15 16:42:54 2015 +0100 @@ -850,9 +850,10 @@ // Include the FCPPluginMessage in the Exception so the developer can determine // whether it is an issue of the remote side taking a long time to execute // for certain messages. - throw new IOException("The synchronous call timed out for " + this + "; " - + "direction = " + direction + "; " - + "message = " + message); + throw new IOException("sendSynchronous() timed out waiting for reply! " + + " connection = " + FCPPluginConnectionImpl.this + + "; SendDirection = " + direction + + "; message = " + message); } // The thread which sets synchronousSend.reply to be non-null calls # HG changeset patch # User xor-freenet <xor at freenetproject.org> # Date 1421337107 -3600 # Thu Jan 15 16:51:47 2015 +0100 # Node ID 6c5e581ec28a75fc217bcf7285e1c2c62fa5ec93 # Parent 15fef97e809064eac67f5a6b3da16d82d2a09abd FCPPluginConnectionImpl.toString(): Add "server" member variable diff -r 15fef97e8090 -r 6c5e581ec28a src/freenet/clients/fcp/FCPPluginConnectionImpl.java --- a/src/freenet/clients/fcp/FCPPluginConnectionImpl.java Thu Jan 15 16:42:54 2015 +0100 +++ b/src/freenet/clients/fcp/FCPPluginConnectionImpl.java Thu Jan 15 16:51:47 2015 +0100 @@ -890,7 +890,8 @@ @Override public String toString() { - return "FCPPluginConnectionImpl (ID: " + id + "; server plugin: " + serverPluginName + return "FCPPluginConnectionImpl (ID: " + id + "; server class: " + serverPluginName + + "; server: " + (server != null ? server.get() : null) + "; client: " + client + "; clientConnection: " + clientConnection + ")"; } # HG changeset patch # User xor-freenet <xor at freenetproject.org> # Date 1421337307 -3600 # Thu Jan 15 16:55:07 2015 +0100 # Node ID 16fb9a043d1906f353530f6f0e23e9cd8e7229a9 # Parent 6c5e581ec28a75fc217bcf7285e1c2c62fa5ec93 FCPPluginConnectionImpl: Use parent interface as type when sensible This completes those changes for this class. diff -r 6c5e581ec28a -r 16fb9a043d19 src/freenet/clients/fcp/FCPPluginConnectionImpl.java --- a/src/freenet/clients/fcp/FCPPluginConnectionImpl.java Thu Jan 15 16:51:47 2015 +0100 +++ b/src/freenet/clients/fcp/FCPPluginConnectionImpl.java Thu Jan 15 16:55:07 2015 +0100 @@ -427,7 +427,7 @@ * FCPPluginConnectionImpl <b>cannot</b> be repaired, even if the server plugin is * loaded again. Then you should discard this client and create a fresh one.</p> * - * <p><b>ATTENTION:</b> Future implementations of {@link FCPPluginConnectionImpl} might + * <p><b>ATTENTION:</b> Future implementations of {@link FCPPluginConnection} might * allow the server plugin to reside in a different node, and only be attached by * network. Due to the unreliability of network connections, then this function will not * be able to reliably detect whether the server is dead.<br> # HG changeset patch # User xor-freenet <xor at freenetproject.org> # Date 1421445140 -3600 # Fri Jan 16 22:52:20 2015 +0100 # Node ID 6e853b7efb00230b05545ec54b1074990934ebf3 # Parent 11e5dd8e4c0ff16bf40276645a69e1e290948f4c FCPPluginConnection: Add send functions with default SendDirection This marks the begin of branch FCPPluginConnection-default-SendDirection, whose goal shall be to implement those functions. diff -r 11e5dd8e4c0f -r 6e853b7efb00 src/freenet/clients/fcp/FCPPluginConnection.java --- a/src/freenet/clients/fcp/FCPPluginConnection.java Thu Jan 15 20:29:06 2015 +0100 +++ b/src/freenet/clients/fcp/FCPPluginConnection.java Fri Jan 16 22:52:20 2015 +0100 @@ -9,6 +9,7 @@ import freenet.pluginmanager.FredPluginFCPMessageHandler; import freenet.pluginmanager.FredPluginFCPMessageHandler.ClientSideFCPMessageHandler; +import freenet.pluginmanager.FredPluginFCPMessageHandler.ServerSideFCPMessageHandler; import freenet.pluginmanager.PluginRespirator; import freenet.support.Logger; import freenet.support.Logger.LogLevel; @@ -190,6 +191,31 @@ public void send(SendDirection direction, FCPPluginMessage message) throws IOException; /** + * Same as {@link #send(SendDirection, FCPPluginMessage)} with the {@link SendDirection} + * parameter being the default direction.<br> + * <b>Please do read its JavaDoc as it contains a very precise specification how to use it and + * thereby also this function.</b><br><br> + * + * The default direction is determined automatically depending on whether you are a client or + * server.<br><br> + * + * You are acting as a client, and thus by default send to the server, when you obtain a + * FCPPluginConnection...:<br> + * - from the return value of + * {@link PluginRespirator#connectToOtherPlugin(String, ClientSideFCPMessageHandler)}.<br> + * - as parameter to your message handler callback {@link ClientSideFCPMessageHandler# + * handlePluginFCPMessage(FCPPluginConnection, FCPPluginMessage)}.<br><br> + * + * You are acting as a server, and thus by default send to the client, when you obtain a + * FCPPluginConnection...:<br> + * - as parameter to your message handler callback {@link ServerSideFCPMessageHandler# + * handlePluginFCPMessage(FCPPluginConnection, FCPPluginMessage)}.<br> + * - from the return value of {@link PluginRespirator#getPluginConnectionByID(UUID)}.<br> + */ + public void send(FCPPluginMessage message) throws IOException; + + + /** * Can be used by both server and client implementations to send messages in a blocking * manner to each other.<br> * The messages sent by this function will be delivered to the message handler @@ -352,6 +378,19 @@ throws IOException, InterruptedException; /** + * Same as {@link #sendSynchronous(SendDirection, FCPPluginMessage, long)} with the + * {@link SendDirection} parameter being the default direction.<br> + * <b>Please do read its JavaDoc as it contains a very precise specification how to use it and + * thereby also this function.</b><br><br> + * + * For an explanation of how the default send direction is determined, see + * {@link #send(FCPPluginMessage)}. + */ + public FCPPluginMessage sendSynchronous(FCPPluginMessage message, long timeoutNanoSeconds) + throws IOException, InterruptedException; + + + /** * @return A unique identifier among all FCPPluginConnections. * @see The ID can be used with {@link PluginRespirator#getPluginConnectionByID(UUID)}. */ # HG changeset patch # User xor-freenet <xor at freenetproject.org> # Date 1421450378 -3600 # Sat Jan 17 00:19:38 2015 +0100 # Node ID ec7d03e9917e283ef16443ecaf86dea4ae2e04da # Parent 6e853b7efb00230b05545ec54b1074990934ebf3 FCPPluginConnectionImpl: Add member class DefaultSendDirectionAdapter Will be used to implement the send funtions which default to a specific SendDirection. diff -r 6e853b7efb00 -r ec7d03e9917e src/freenet/clients/fcp/FCPPluginConnectionImpl.java --- a/src/freenet/clients/fcp/FCPPluginConnectionImpl.java Fri Jan 16 22:52:20 2015 +0100 +++ b/src/freenet/clients/fcp/FCPPluginConnectionImpl.java Sat Jan 17 00:19:38 2015 +0100 @@ -889,6 +889,69 @@ } } + /** + * Encapsulates a FCPPluginConnectionImpl object and a default {@link SendDirection} to + * implement the send functions which don't require a direction parameter:<br> + * - {@link FCPPluginConnection#send(FCPPluginMessage)}<br> + * - {@link FCPPluginConnection#sendSynchronous(FCPPluginMessage, long)}}<br><br> + * + * An adapter is needed instead of storing this as a member variable in FCPPluginConnectionImpl + * because a single FCPPluginConnectionImpl object is handed out both to the the server AND the + * client which uses, and their default send direction will be different:<br> + * A server will want to send to the client by default, but the client will want to default to + * sending to the server.<br><br> + * + * Is abstract and has two implementing child classes (to implement differing internal + * requirements, see {@link #getConnection()}):<br> + * - {@link SendToClientAdapter} for default direction {@link SendDirection#ToClient}.<br> + * - {@link SendToServerAdapter} for default direction {@link SendDirection#ToServer}.<br> + */ + private abstract static class DefaultSendDirectionAdapter implements FCPPluginConnection { + + private final SendDirection defaultDirection; + + DefaultSendDirectionAdapter(SendDirection defaultDirection) { + this.defaultDirection = defaultDirection; + } + + /** + * Returns the encapsulated backend FCPPluginConnection which shall be used for sending.<br> + * <br> + * + * Abstract because storage of a FCPPluginConnection object is different for servers and + * clients and thus must be implemented in separate child classes:<br> + * - Clients may and must store a FCPPluginConnection with a hard reference because a + * connection is considered as closed once there is no more hard reference to it.<br> + * Disconnection is detected by monitoring the FCPluginConnection for garbage collection. + * <br> + * - Servers must store a FCPPluginConnection with a {@link WeakReference} (or always query + * it by UUID from the node) to ensure that they will get garbage connected once the + * client decides to disconnect by dropping all strong references. + */ + protected abstract FCPPluginConnection getConnection() throws IOException; + + + @Override public void send(FCPPluginMessage message) throws IOException { + send(defaultDirection, message); + } + + @Override public FCPPluginMessage sendSynchronous(FCPPluginMessage message, + long timeoutNanoSeconds) throws IOException, InterruptedException { + return sendSynchronous(defaultDirection, message, timeoutNanoSeconds); + } + + @Override public void send(SendDirection direction, FCPPluginMessage message) + throws IOException { + getConnection().send(direction, message); + } + + @Override public FCPPluginMessage sendSynchronous(SendDirection direction, + FCPPluginMessage message, long timeoutNanoSeconds) + throws IOException, InterruptedException { + return getConnection().sendSynchronous(direction, message, timeoutNanoSeconds); + } + } + @Override public String toString() { return "FCPPluginConnectionImpl (ID: " + id + "; server class: " + serverPluginName # HG changeset patch # User xor-freenet <xor at freenetproject.org> # Date 1421450797 -3600 # Sat Jan 17 00:26:37 2015 +0100 # Node ID a22003ad422630d1bf85a7dca52011540aa3204d # Parent ec7d03e9917e283ef16443ecaf86dea4ae2e04da FCPPluginConnectionImpl: Fix grammar typo diff -r ec7d03e9917e -r a22003ad4226 src/freenet/clients/fcp/FCPPluginConnectionImpl.java --- a/src/freenet/clients/fcp/FCPPluginConnectionImpl.java Sat Jan 17 00:19:38 2015 +0100 +++ b/src/freenet/clients/fcp/FCPPluginConnectionImpl.java Sat Jan 17 00:26:37 2015 +0100 @@ -897,7 +897,7 @@ * * An adapter is needed instead of storing this as a member variable in FCPPluginConnectionImpl * because a single FCPPluginConnectionImpl object is handed out both to the the server AND the - * client which uses, and their default send direction will be different:<br> + * client which use it, and their default send direction will be different:<br> * A server will want to send to the client by default, but the client will want to default to * sending to the server.<br><br> * # HG changeset patch # User xor-freenet <xor at freenetproject.org> # Date 1421684302 -3600 # Mon Jan 19 17:18:22 2015 +0100 # Node ID 15ce0a77c5cb872b617f7eede166df65f5b6b322 # Parent a22003ad422630d1bf85a7dca52011540aa3204d FCPPluginConnectionImpl: Add member class SendToClientAdapter Implements DefaultSendDirectionAdapter with the direction of sending to the client. Not private since it will have to be used by the FCPServer. Explanation will follow when committing that code. diff -r a22003ad4226 -r 15ce0a77c5cb src/freenet/clients/fcp/FCPPluginConnectionImpl.java --- a/src/freenet/clients/fcp/FCPPluginConnectionImpl.java Sat Jan 17 00:26:37 2015 +0100 +++ b/src/freenet/clients/fcp/FCPPluginConnectionImpl.java Mon Jan 19 17:18:22 2015 +0100 @@ -952,6 +952,45 @@ } } + /** + * Encapsulates a FCPPluginConnectionImpl object with a default {@link SendDirection} of + * {@link SendDirection#ToClient} to implement the send functions which don't require a + * direction parameter:<br> + * - {@link FCPPluginConnection#send(FCPPluginMessage)}<br> + * - {@link FCPPluginConnection#sendSynchronous(FCPPluginMessage, long)}}<br><br> + * + * Must only be used by the server, not by the client: Clients must keep a strong reference to + * the connection to prevent its garbage collection (= disconnection), but this does not keep + * a strong reference.<br> + * See section "Disconnecting properly" at {@link PluginRespirator#connectToOtherPlugin( + * String, ClientSideFCPMessageHandler)}. + */ + static final class SendToClientAdapter extends DefaultSendDirectionAdapter { + + /** Is used to query the underlying FCPPluginConnectionImpl dynamically by its {@link UUID} + * {@link #id} since this class, being aimed at being used by the server, may not keep a + * strong reference to the connection to ensure that the client owns the power of purging + * all strong references to it to cause disconnection. */ + private final FCPPluginConnectionTracker tracker; + + /** The {@link FCPPluginConnection#getID()} of the underlying connection. */ + private final UUID id; + + SendToClientAdapter(FCPPluginConnectionTracker tracker, UUID connectionID) { + super(SendDirection.ToClient); + this.tracker = tracker; + this.id = connectionID; + } + + @Override protected FCPPluginConnection getConnection() throws IOException { + return tracker.getConnection(id); + } + + @Override public UUID getID() { + return id; + } + } + @Override public String toString() { return "FCPPluginConnectionImpl (ID: " + id + "; server class: " + serverPluginName # HG changeset patch # User xor-freenet <xor at freenetproject.org> # Date 1421684716 -3600 # Mon Jan 19 17:25:16 2015 +0100 # Node ID 60ebdf73fc98b420007852fb38dde69ae4557a76 # Parent 15ce0a77c5cb872b617f7eede166df65f5b6b322 FCPPluginConnectionImpl: Add member class SendToServerAdapter Implements DefaultSendDirectionAdapter with the direction of sending to the server. diff -r 15ce0a77c5cb -r 60ebdf73fc98 src/freenet/clients/fcp/FCPPluginConnectionImpl.java --- a/src/freenet/clients/fcp/FCPPluginConnectionImpl.java Mon Jan 19 17:18:22 2015 +0100 +++ b/src/freenet/clients/fcp/FCPPluginConnectionImpl.java Mon Jan 19 17:25:16 2015 +0100 @@ -991,6 +991,39 @@ } } + /** + * Encapsulates a FCPPluginConnectionImpl object with a default {@link SendDirection} of + * {@link SendDirection#ToServer} to implement the send functions which don't require a + * direction parameter:<br> + * - {@link FCPPluginConnection#send(FCPPluginMessage)}<br> + * - {@link FCPPluginConnection#sendSynchronous(FCPPluginMessage, long)}}<br><br> + * + * ATTENTION: Must only be used by the client, not by the server: Client disconnection is + * implemented by monitoring the garbage collection of their FCPPluginConnectionImpl objects + * - once the connection is not strong referenced anymore, it is considered as closed. + * As this class keeps a strong reference to the connection, if servers did use it, they would + * prevent client disconnection.<br> + * See section "Disconnecting properly" at {@link PluginRespirator#connectToOtherPlugin( + * String, ClientSideFCPMessageHandler)}. + */ + private static final class SendToServerAdapter extends DefaultSendDirectionAdapter { + + private final FCPPluginConnection parent; + + SendToServerAdapter(FCPPluginConnectionImpl parent) { + super(SendDirection.ToServer); + this.parent = parent; + } + + @Override protected FCPPluginConnection getConnection() { + return parent; + } + + @Override public UUID getID() { + return parent.getID(); + } + } + @Override public String toString() { return "FCPPluginConnectionImpl (ID: " + id + "; server class: " + serverPluginName # HG changeset patch # User xor-freenet <xor at freenetproject.org> # Date 1421685975 -3600 # Mon Jan 19 17:46:15 2015 +0100 # Node ID 9bc0180a40977468419e9ae3c8ec729d3d6ea9ca # Parent 1e611fd6dbf22ef88c8fa0d0edc9ee3a2d01bb40 FCPPluginConnectionImpl: Add storage for DefaultSendDirectionAdapters This also changes the factory functions FCPPluginConnectionImpl.construct*() to automatically register the connection at the FCPPluginConnectionTracker, which is more robust anyway. diff -r 1e611fd6dbf2 -r 9bc0180a4097 src/freenet/clients/fcp/FCPPluginConnectionImpl.java --- a/src/freenet/clients/fcp/FCPPluginConnectionImpl.java Mon Jan 19 17:27:18 2015 +0100 +++ b/src/freenet/clients/fcp/FCPPluginConnectionImpl.java Mon Jan 19 17:46:15 2015 +0100 @@ -6,6 +6,7 @@ import java.io.IOException; import java.lang.ref.ReferenceQueue; import java.lang.ref.WeakReference; +import java.util.EnumMap; import java.util.TreeMap; import java.util.UUID; import java.util.concurrent.TimeUnit; @@ -270,6 +271,17 @@ */ private final ReadWriteLock synchronousSendsLock = new ReentrantReadWriteLock(); + /** + * A {@link DefaultSendDirectionAdapter} is an adapter which encapsulates a + * FCPPluginConnectionImpl object with a default {@link SendDirection} to implement the send + * functions which don't require a direction parameter:<br> + * - {@link FCPPluginConnection#send(FCPPluginMessage)}<br> + * - {@link FCPPluginConnection#sendSynchronous(FCPPluginMessage, long)}}<br><br> + * + * For each possible {@link SendDirection}, this map keeps the responsible adapter. */ + private final EnumMap<SendDirection, DefaultSendDirectionAdapter> defaultSendDirectionAdapters + = new EnumMap<SendDirection, DefaultSendDirectionAdapter>(SendDirection.class); + /** * For being used by networked FCP connections:<br/> @@ -278,12 +290,15 @@ * The client is not running within the node, it is attached by network with a * {@link FCPConnectionHandler}.<br/> * - * @see #constructForNetworkedFCP(Executor, PluginManager, String, FCPConnectionHandler) + * @see #constructForNetworkedFCP(FCPPluginConnectionTracker, Executor, PluginManager, String, + * FCPConnectionHandler) * The public interface to this constructor. */ - private FCPPluginConnectionImpl(Executor executor, String serverPluginName, - ServerSideFCPMessageHandler serverPlugin, FCPConnectionHandler clientConnection) { + private FCPPluginConnectionImpl(FCPPluginConnectionTracker tracker, Executor executor, + String serverPluginName, ServerSideFCPMessageHandler serverPlugin, + FCPConnectionHandler clientConnection) { + assert(tracker != null); assert(executor != null); assert(serverPlugin != null); assert(serverPluginName != null); @@ -294,6 +309,10 @@ this.server = new WeakReference<ServerSideFCPMessageHandler>(serverPlugin); this.client = null; this.clientConnection = clientConnection; + this.defaultSendDirectionAdapters.put(SendDirection.ToServer, + new SendToServerAdapter(this)); + this.defaultSendDirectionAdapters.put(SendDirection.ToClient, + new SendToClientAdapter(tracker, id)); } /** @@ -303,23 +322,24 @@ * The client is not running within the node, it is attached by network with the given * {@link FCPConnectionHandler} clientConnection.<br/> * - * <p>You <b>must</b> register any newly created connections at - * {@link FCPPluginConnectionTracker#registerConnection(FCPPluginConnection)} before handing - * them out to plugin code.</p> + * The returned connection is registered at the given {@link FCPPluginConnectionTracker}. */ - static FCPPluginConnectionImpl constructForNetworkedFCP(Executor executor, - PluginManager serverPluginManager, String serverPluginName, - FCPConnectionHandler clientConnection) + static FCPPluginConnectionImpl constructForNetworkedFCP(FCPPluginConnectionTracker tracker, + Executor executor, PluginManager serverPluginManager, + String serverPluginName, FCPConnectionHandler clientConnection) throws PluginNotFoundException { + assert(tracker != null); assert(executor != null); assert(serverPluginManager != null); assert(serverPluginName != null); assert(clientConnection != null); - return new FCPPluginConnectionImpl(executor, + FCPPluginConnectionImpl result = new FCPPluginConnectionImpl(tracker, executor, serverPluginName, serverPluginManager.getPluginFCPServer(serverPluginName), clientConnection); + tracker.registerConnection(result); + return result; } @@ -332,12 +352,15 @@ * The client's message handler is accessible as an implementor of * {@link ClientSideFCPMessageHandler}.<br> * - * @see #constructForIntraNodeFCP(Executor, PluginManager, String, ClientSideFCPMessageHandler) + * @see #constructForIntraNodeFCP(FCPPluginConnectionTracker, Executor, PluginManager, String, + * ClientSideFCPMessageHandler) * The public interface to this constructor. */ - private FCPPluginConnectionImpl(Executor executor, String serverPluginName, - ServerSideFCPMessageHandler server, ClientSideFCPMessageHandler client) { + private FCPPluginConnectionImpl(FCPPluginConnectionTracker tracker, Executor executor, + String serverPluginName, ServerSideFCPMessageHandler server, + ClientSideFCPMessageHandler client) { + assert(tracker != null); assert(executor != null); assert(serverPluginName != null); assert(server != null); @@ -348,6 +371,10 @@ this.server = new WeakReference<ServerSideFCPMessageHandler>(server); this.client = client; this.clientConnection = null; + this.defaultSendDirectionAdapters.put(SendDirection.ToServer, + new SendToServerAdapter(this)); + this.defaultSendDirectionAdapters.put(SendDirection.ToClient, + new SendToClientAdapter(tracker, id)); } /** @@ -359,13 +386,11 @@ * The client message handler is available as the passed {@link ClientSideFCPMessageHandler} * client.<br> * - * <p>You <b>must</b> register any newly created connections at - * {@link FCPPluginConnectionTracker#registerConnection(FCPPluginConnection)} before handing - * them out to plugin code.</p> + * The returned connection is registered at the given {@link FCPPluginConnectionTracker}. */ - static FCPPluginConnectionImpl constructForIntraNodeFCP(Executor executor, - PluginManager serverPluginManager, String serverPluginName, - ClientSideFCPMessageHandler client) + static FCPPluginConnectionImpl constructForIntraNodeFCP(FCPPluginConnectionTracker tracker, + Executor executor, PluginManager serverPluginManager, + String serverPluginName, ClientSideFCPMessageHandler client) throws PluginNotFoundException { assert(executor != null); @@ -373,8 +398,10 @@ assert(serverPluginName != null); assert(client != null); - return new FCPPluginConnectionImpl(executor, + FCPPluginConnectionImpl result = new FCPPluginConnectionImpl(tracker, executor, serverPluginName, serverPluginManager.getPluginFCPServer(serverPluginName), client); + tracker.registerConnection(result); + return result; } /** diff -r 1e611fd6dbf2 -r 9bc0180a4097 src/freenet/clients/fcp/FCPServer.java --- a/src/freenet/clients/fcp/FCPServer.java Mon Jan 19 17:27:18 2015 +0100 +++ b/src/freenet/clients/fcp/FCPServer.java Mon Jan 19 17:46:15 2015 +0100 @@ -498,8 +498,10 @@ throws PluginNotFoundException { FCPPluginConnectionImpl connection = FCPPluginConnectionImpl.constructForNetworkedFCP( - node.executor, node.pluginManager, serverPluginName, messageHandler); - pluginConnectionTracker.registerConnection(connection); + pluginConnectionTracker, node.executor, node.pluginManager, + serverPluginName, messageHandler); + // The constructor function already did this for us + /* pluginConnectionTracker.registerConnection(connection); */ return connection; } @@ -531,8 +533,10 @@ throws PluginNotFoundException { FCPPluginConnectionImpl connection = FCPPluginConnectionImpl.constructForIntraNodeFCP( - node.executor, node.pluginManager, serverPluginName, messageHandler); - pluginConnectionTracker.registerConnection(connection); + pluginConnectionTracker, node.executor, node.pluginManager, + serverPluginName, messageHandler); + // The constructor function already did this for us + /* pluginConnectionTracker.registerConnection(connection); */ return connection; } # HG changeset patch # User xor-freenet <xor at freenetproject.org> # Date 1421688234 -3600 # Mon Jan 19 18:23:54 2015 +0100 # Node ID 6be89d28497a9dae74feb8db5c29cccdc5702b9d # Parent 71d628581847701f24ac24287f394d9d228d15e6 FCPPluginConnectionImpl.constructForUnitTest(): Compile-fix Sorry diff -r 71d628581847 -r 6be89d28497a src/freenet/clients/fcp/FCPPluginConnectionImpl.java --- a/src/freenet/clients/fcp/FCPPluginConnectionImpl.java Mon Jan 19 18:19:52 2015 +0100 +++ b/src/freenet/clients/fcp/FCPPluginConnectionImpl.java Mon Jan 19 18:23:54 2015 +0100 @@ -430,7 +430,10 @@ assert(server != null); assert(client != null); - return new FCPPluginConnectionImpl(new PooledExecutor(), server.toString(), server, client); + FCPPluginConnectionTracker tracker = new FCPPluginConnectionTracker(); + tracker.start(); + return new FCPPluginConnectionImpl( + tracker, new PooledExecutor(), server.toString(), server, client); } @Override # HG changeset patch # User xor-freenet <xor at freenetproject.org> # Date 1421688898 -3600 # Mon Jan 19 18:34:58 2015 +0100 # Node ID af4895a54495e22146f8fa45d06d1bd385c1f7bd # Parent 3c2ab5957f292e9dfe82e06e3fb08e742fcfe0da FCPPluginConnectionImpl: Add getDefaultSendDirectionAdapter() Uses the recently added table defaultSendDirectionAdapters to re-use existing adapters. diff -r 3c2ab5957f29 -r af4895a54495 src/freenet/clients/fcp/FCPPluginConnectionImpl.java --- a/src/freenet/clients/fcp/FCPPluginConnectionImpl.java Mon Jan 19 18:28:22 2015 +0100 +++ b/src/freenet/clients/fcp/FCPPluginConnectionImpl.java Mon Jan 19 18:34:58 2015 +0100 @@ -1002,6 +1002,9 @@ /** The {@link FCPPluginConnection#getID()} of the underlying connection. */ private final UUID id; + /** + * Please use {@link FCPPluginConnectionImpl#getDefaultSendDirectionAdapter(SendDirection)} + * whenever possible to reuse adapters instead of creating new ones with this constructor.*/ SendToClientAdapter(FCPPluginConnectionTracker tracker, UUID connectionID) { super(SendDirection.ToClient); this.tracker = tracker; @@ -1036,6 +1039,9 @@ private final FCPPluginConnection parent; + /** + * Please use {@link FCPPluginConnectionImpl#getDefaultSendDirectionAdapter(SendDirection)} + * whenever possible to reuse adapters instead of creating new ones with this constructor.*/ SendToServerAdapter(FCPPluginConnectionImpl parent) { super(SendDirection.ToServer); this.parent = parent; @@ -1050,6 +1056,17 @@ } } + /** + * Returns a {@link DefaultSendDirectionAdapter} (which implements FCPPluginConnection) wrapped + * around this FCPPluginConnectionImpl for which the following send functions will then always + * send to the {@link SendDirection} which was passed to this function:<br> + * - {@link FCPPluginConnection#send(FCPPluginMessage)}<br> + * - {@link FCPPluginConnection#sendSynchronous(FCPPluginMessage, long)}<br><br> + */ + public FCPPluginConnection getDefaultSendDirectionAdapter(SendDirection direction) { + return defaultSendDirectionAdapters.get(direction); + } + @Override public String toString() { return "FCPPluginConnectionImpl (ID: " + id + "; server class: " + serverPluginName # HG changeset patch # User xor-freenet <xor at freenetproject.org> # Date 1421689122 -3600 # Mon Jan 19 18:38:42 2015 +0100 # Node ID bb09b50c03529e15e635c865d701236b8782bd69 # Parent af4895a54495e22146f8fa45d06d1bd385c1f7bd FCPPluginConnectionImpl: Implement send functions without SendDirection The following commits will fix the code which hands out FCPPluginConnectionImpl to always wrap it inside a DefaultSendDirectionAdapter like the JavaDoc already promises. diff -r af4895a54495 -r bb09b50c0352 src/freenet/clients/fcp/FCPPluginConnectionImpl.java --- a/src/freenet/clients/fcp/FCPPluginConnectionImpl.java Mon Jan 19 18:34:58 2015 +0100 +++ b/src/freenet/clients/fcp/FCPPluginConnectionImpl.java Mon Jan 19 18:38:42 2015 +0100 @@ -1067,6 +1067,44 @@ return defaultSendDirectionAdapters.get(direction); } + + /** + * @throws NoSendDirectionSpecifiedException + * Is always thrown since this function is only implemented for FCPPluginConnectionImpl + * objects which are wrapped inside a {@link DefaultSendDirectionAdapter}.<br> + * Objects of type FCPPluginConnectionImpl will never be handed out directly to the server + * or client application code, they will always be wrapped in such an adapter - so this + * function will work for servers and clients. */ + @Override public void send(FCPPluginMessage message) { + throw new NoSendDirectionSpecifiedException(); + } + + /** + * @throws NoSendDirectionSpecifiedException + * Is always thrown since this function is only implemented for FCPPluginConnectionImpl + * objects which are wrapped inside a {@link DefaultSendDirectionAdapter}.<br> + * Objects of type FCPPluginConnectionImpl will never be handed out directly to the server + * or client application code, they will always be wrapped in such an adapter - so this + * function will work for servers and clients. */ + @Override public FCPPluginMessage sendSynchronous(FCPPluginMessage message, + long timeoutNanoSeconds) { + throw new NoSendDirectionSpecifiedException(); + } + + /** + * @see FCPPluginConnectionImpl#send(FCPPluginMessage) + * @see FCPPluginConnectionImpl#sendSynchronous(FCPPluginMessage, long) */ + @SuppressWarnings("serial") + private static final class NoSendDirectionSpecifiedException + extends UnsupportedOperationException { + + public NoSendDirectionSpecifiedException() { + super("You must obtain a FCPPluginConnectionImpl with a default SendDirection via " + + "getDefaultSendDirectionAdapter() before you may use this function!"); + } + } + + @Override public String toString() { return "FCPPluginConnectionImpl (ID: " + id + "; server class: " + serverPluginName # HG changeset patch # User xor-freenet <xor at freenetproject.org> # Date 1421689274 -3600 # Mon Jan 19 18:41:14 2015 +0100 # Node ID 6a2f8daf88b27b6c6a9bc0f5e7c208a6d81f17b2 # Parent bb09b50c03529e15e635c865d701236b8782bd69 FCPPluginConnectionImpl: Pass DefaultSendDirectionAdapter ... to message handlers of client / server. What remains to be done is to adapt PluginRespirator.connectToOtherPlugin() / getPluginConnectionByID() to pass an adapter as well. diff -r bb09b50c0352 -r 6a2f8daf88b2 src/freenet/clients/fcp/FCPPluginConnectionImpl.java --- a/src/freenet/clients/fcp/FCPPluginConnectionImpl.java Mon Jan 19 18:38:42 2015 +0100 +++ b/src/freenet/clients/fcp/FCPPluginConnectionImpl.java Mon Jan 19 18:41:14 2015 +0100 @@ -697,7 +697,7 @@ try { try { reply = messageHandler.handlePluginFCPMessage( - FCPPluginConnectionImpl.this, message); + getDefaultSendDirectionAdapter(direction.invert()), message); } catch(Error e) { // TODO: Code quality: This is a workaround for Java 6 not having // "catch(RuntimeException | Error e)". Once we are on Java 7, remove this # HG changeset patch # User xor-freenet <xor at freenetproject.org> # Date 1421695347 -3600 # Mon Jan 19 20:22:27 2015 +0100 # Node ID 9947f6d4f1790f9cc7ec447700f935c142fd7d92 # Parent 6a2f8daf88b27b6c6a9bc0f5e7c208a6d81f17b2 FCPPluginConnectionTracker: Add getConnectionWeakReference() Will be used for improving the implementation of FCPPluginConnectionImpl.SendToClientAdapter diff -r 6a2f8daf88b2 -r 9947f6d4f179 src/freenet/clients/fcp/FCPPluginConnectionTracker.java --- a/src/freenet/clients/fcp/FCPPluginConnectionTracker.java Mon Jan 19 18:41:14 2015 +0100 +++ b/src/freenet/clients/fcp/FCPPluginConnectionTracker.java Mon Jan 19 20:22:27 2015 +0100 @@ -80,7 +80,7 @@ * from the {@link TreeMap}. For fast removal, we need their key in the map, which is the * connection ID, so we should store it in the {@link WeakReference}. */ - private static final class ConnectionWeakReference + static final class ConnectionWeakReference extends WeakReference<FCPPluginConnection> { public final UUID connectionID; @@ -136,23 +136,37 @@ * If there has been no connection with the given ID or if the client has disconnected. */ public FCPPluginConnection getConnection(UUID connectionID) throws IOException { - ConnectionWeakReference ref = null; + ConnectionWeakReference ref = getConnectionWeakReference(connectionID); + + FCPPluginConnection connection = ref.get(); + + if(connection == null) { + throw new IOException("Client has closed the connection. " + + "Connection ID = " + connectionID); + } + + return connection; + } + + /** + * Same as {@link #getConnection(UUID)} with the only difference of returning a + * {@link WeakReference} to the connection instead of the connection itself.<br> + * <b>Please do read its JavaDoc to understand when to use this!</b> + */ + ConnectionWeakReference getConnectionWeakReference(UUID connectionID) + throws IOException { connectionsByIDLock.readLock().lock(); try { - ref = connectionsByID.get(connectionID); + ConnectionWeakReference ref = connectionsByID.get(connectionID); + if(ref != null) + return ref; } finally { connectionsByIDLock.readLock().unlock(); } - FCPPluginConnection connection = ref != null ? ref.get() : null; - - if(connection == null) { - throw new IOException("FCPPluginConnection not found, maybe client has disconnected." - + " Connection ID: " + connectionID); - } - - return connection; + throw new IOException("FCPPluginConnection not found, maybe client has disconnected." + + " Connection ID: " + connectionID); } # HG changeset patch # User xor-freenet <xor at freenetproject.org> # Date 1421696241 -3600 # Mon Jan 19 20:37:21 2015 +0100 # Node ID 985e34cc79b19b4412e8e3d3606cffeec5d4751b # Parent 9947f6d4f1790f9cc7ec447700f935c142fd7d92 FCPPluginConnectionImpl.SendToClientAdapter: Optimize Store a WeakReference instead of always querying the connection from the FCPPluginConnectionTracker. This will save us a O(N*LOG(N)) query from the FCPPluginConnectionTracker TreeMap for each call of getConnection(), and thus for each send() / sendSynchronous(). This means that the class' visibility can be trimmed to private since it shall only be newly constructed from the FCPPluginConnectionImpl now, otherwise the constructor is not guaranteed to work. This also means that object identity of a FCPPluginConnection is guaranteed: We will always use the same SendToClientAdapter stored in the FCPluginConnectionImpl, because it only allows the outside to query that one, not create fresh ones. diff -r 9947f6d4f179 -r 985e34cc79b1 src/freenet/clients/fcp/FCPPluginConnectionImpl.java --- a/src/freenet/clients/fcp/FCPPluginConnectionImpl.java Mon Jan 19 20:22:27 2015 +0100 +++ b/src/freenet/clients/fcp/FCPPluginConnectionImpl.java Mon Jan 19 20:37:21 2015 +0100 @@ -991,32 +991,48 @@ * See section "Disconnecting properly" at {@link PluginRespirator#connectToOtherPlugin( * String, ClientSideFCPMessageHandler)}. */ - static final class SendToClientAdapter extends DefaultSendDirectionAdapter { + private static final class SendToClientAdapter extends DefaultSendDirectionAdapter { - /** Is used to query the underlying FCPPluginConnectionImpl dynamically by its {@link UUID} - * {@link #id} since this class, being aimed at being used by the server, may not keep a - * strong reference to the connection to ensure that the client owns the power of purging - * all strong references to it to cause disconnection. */ - private final FCPPluginConnectionTracker tracker; - - /** The {@link FCPPluginConnection#getID()} of the underlying connection. */ - private final UUID id; + /** + * {@link WeakReference} to the underlying FCPPluginConnectionImpl.<br> + * Once this becomes null, the connection is definitely dead - see + * {@link FCPPluginConnectionTracker}.<br> + * Notice: The ConnectionWeakReference child class of {@link WeakReference} is used because + * it also stores the connection ID, which is needed for {@link #getID()}. + */ + private final FCPPluginConnectionTracker.ConnectionWeakReference connectionRef; /** * Please use {@link FCPPluginConnectionImpl#getDefaultSendDirectionAdapter(SendDirection)} * whenever possible to reuse adapters instead of creating new ones with this constructor.*/ SendToClientAdapter(FCPPluginConnectionTracker tracker, UUID connectionID) { super(SendDirection.ToClient); - this.tracker = tracker; - this.id = connectionID; + + // Reuse the WeakReference from the FCPPluginConnectionTracker instead of creating our + // own one since it has to keep a WeakReference for every connection anyway, and + // WeakReferences might be expensive to maintain for the VM. + try { + this.connectionRef = tracker.getConnectionWeakReference(connectionID); + } catch (IOException e) { + // This function should only be used during construction of the underlying + // FCPPluginConnectionImpl. While it is being constructed, it should not be + // considered as disconnected already, and thus the FCPPluginConnectionTracker + // should never throw IOException. + throw new RuntimeException("SHOULD NOT HAPPEN: " + e); + } } @Override protected FCPPluginConnection getConnection() throws IOException { - return tracker.getConnection(id); + FCPPluginConnection connection = connectionRef.get(); + if(connection == null) { + throw new IOException("Client has closed the connection. " + + "Connection ID = " + connectionRef.connectionID); + } + return connection; } @Override public UUID getID() { - return id; + return connectionRef.connectionID; } } # HG changeset patch # User xor-freenet <xor at freenetproject.org> # Date 1421697102 -3600 # Mon Jan 19 20:51:42 2015 +0100 # Node ID 7fcaf96a4528b46e999f4881f6e07e4cc78f1c0f # Parent 985e34cc79b19b4412e8e3d3606cffeec5d4751b FCPPluginConnectionTracker: Store FCPPluginConnection*Impl* instead of just FCPPluginConnection. This is necessary because new code in FCPServer soon to be committed will need functions of the Impl which do not make sense to add to the parent interface. diff -r 985e34cc79b1 -r 7fcaf96a4528 src/freenet/clients/fcp/FCPPluginConnectionTracker.java --- a/src/freenet/clients/fcp/FCPPluginConnectionTracker.java Mon Jan 19 20:37:21 2015 +0100 +++ b/src/freenet/clients/fcp/FCPPluginConnectionTracker.java Mon Jan 19 20:51:42 2015 +0100 @@ -17,8 +17,9 @@ import freenet.support.io.NativeThread; /** - * <p>Keeps a list of all {@link FCPPluginConnection}s which are connected to server plugins running - * in the node. Allows the server plugins to query a client connection by its {@link UUID}.</p> + * Keeps a list of all {@link FCPPluginConnectionImpl}s which are connected to server plugins + * running in the node. Allows the server plugins to query a client connection by its {@link UUID}. + * <br><br> * * <p>To understand the purpose of this, please consider the following:<br/> * The normal flow of plugin FCP is that clients send messages to a server plugin, and the server @@ -69,8 +70,8 @@ * Queue which monitors nulled weak references in {@link #connectionsByID}.<br> * Monitored in {@link #realRun()}. */ - private final ReferenceQueue<FCPPluginConnection> closedConnectionsQueue - = new ReferenceQueue<FCPPluginConnection>(); + private final ReferenceQueue<FCPPluginConnectionImpl> closedConnectionsQueue + = new ReferenceQueue<FCPPluginConnectionImpl>(); /** @@ -81,12 +82,12 @@ * connection ID, so we should store it in the {@link WeakReference}. */ static final class ConnectionWeakReference - extends WeakReference<FCPPluginConnection> { + extends WeakReference<FCPPluginConnectionImpl> { public final UUID connectionID; - public ConnectionWeakReference(FCPPluginConnection referent, - ReferenceQueue<FCPPluginConnection> referenceQueue) { + public ConnectionWeakReference(FCPPluginConnectionImpl referent, + ReferenceQueue<FCPPluginConnectionImpl> referenceQueue) { super(referent, referenceQueue); connectionID = referent.getID(); @@ -94,16 +95,16 @@ } /** - * Stores the {@link FCPPluginConnection} so in the future it can be obtained by its ID with + * Stores the {@link FCPPluginConnectionImpl} so in the future it can be obtained by its ID with * {@link #getConnection(UUID)}. * - * <b>Must</b> be called for any newly created {@link FCPPluginConnection} before passing it to - * {@link ServerSideFCPMessageHandler#handlePluginFCPMessage(FCPPluginConnection, + * <b>Must</b> be called for any newly created {@link FCPPluginConnectionImpl} before passing it + * to {@link ServerSideFCPMessageHandler#handlePluginFCPMessage(FCPPluginConnection, * FCPPluginMessage)}. * * Unregistration is not supported and not necessary. */ - void registerConnection(FCPPluginConnection connection) { + void registerConnection(FCPPluginConnectionImpl connection) { connectionsByIDLock.writeLock().lock(); try { // No duplicate checks needed: FCPPluginConnection.getID() is a random UUID. @@ -135,10 +136,10 @@ * @throws IOException * If there has been no connection with the given ID or if the client has disconnected. */ - public FCPPluginConnection getConnection(UUID connectionID) throws IOException { + public FCPPluginConnectionImpl getConnection(UUID connectionID) throws IOException { ConnectionWeakReference ref = getConnectionWeakReference(connectionID); - FCPPluginConnection connection = ref.get(); + FCPPluginConnectionImpl connection = ref.get(); if(connection == null) { throw new IOException("Client has closed the connection. " diff -r 985e34cc79b1 -r 7fcaf96a4528 src/freenet/clients/fcp/FCPServer.java --- a/src/freenet/clients/fcp/FCPServer.java Mon Jan 19 20:37:21 2015 +0100 +++ b/src/freenet/clients/fcp/FCPServer.java Mon Jan 19 20:51:42 2015 +0100 @@ -71,8 +71,8 @@ String bindTo; private String allowedHosts; AllowedHosts allowedHostsFullAccess; - /** Stores {@link FCPPluginConnection} objects by ID and automatically garbage collects them so - * we don't have to bloat this class with that. */ + /** Stores {@link FCPPluginConnectionImpl} objects by ID and automatically garbage collects them + * so we don't have to bloat this class with that. */ final FCPPluginConnectionTracker pluginConnectionTracker; final WeakHashMap<String, PersistentRequestClient> rebootClientsByName; final PersistentRequestClient globalRebootClient; # HG changeset patch # User xor-freenet <xor at freenetproject.org> # Date 1421697521 -3600 # Mon Jan 19 20:58:41 2015 +0100 # Node ID 26f3fc23479755d7b9d3da6b27d566fff5e6754d # Parent 7fcaf96a4528b46e999f4881f6e07e4cc78f1c0f FCPServer: Set default send direction in returned FCPPluginConnections .. by using the recently implemented getDefaultSendDirectionAdapter(). diff -r 7fcaf96a4528 -r 26f3fc234797 src/freenet/clients/fcp/FCPServer.java --- a/src/freenet/clients/fcp/FCPServer.java Mon Jan 19 20:51:42 2015 +0100 +++ b/src/freenet/clients/fcp/FCPServer.java Mon Jan 19 20:58:41 2015 +0100 @@ -27,6 +27,7 @@ import freenet.client.async.PersistentJob; import freenet.clients.fcp.ClientGet.ReturnType; import freenet.clients.fcp.ClientRequest.Persistence; +import freenet.clients.fcp.FCPPluginConnection.SendDirection; import freenet.config.Config; import freenet.config.InvalidConfigValueException; import freenet.config.SubConfig; @@ -524,6 +525,10 @@ * {@link PluginRespirator#connectToOtherPlugin(String, * FredPluginFCPMessageHandler.ClientSideFCPMessageHandler)}. Plugins must use that instead.</p> * + * ATTENTION: Since this function is only to be used by the aforementioned connectToPlugin() + * which in turn is only to be used by clients, the returned connection will have a default send + * direction of {@link SendDirection#ToServer}. + * * @see FCPPluginConnectionImpl * The class JavaDoc of FCPPluginConnectionImpl explains the code path for both networked * and non-networked FCP. @@ -537,18 +542,27 @@ serverPluginName, messageHandler); // The constructor function already did this for us /* pluginConnectionTracker.registerConnection(connection); */ - return connection; + return connection.getDefaultSendDirectionAdapter(SendDirection.ToServer); } /** * <p><b>The documentation of {@link FCPPluginConnectionTracker#getConnection(UUID)} applies to * this function.</b></p> * + * ATTENTION: Only for internal use by the frontend function + * {@link PluginRespirator#getPluginConnectionByID(UUID)}. Plugins must use that instead.<br> + * <br> + * + * ATTENTION: Since this function is only to be used by the aforementioned + * getPluginConnectionByID() which in turn is only to be used by servers, the returned + * connection will have a default send direction of {@link SendDirection#ToClient}. + * * @see FCPPluginConnectionTracker * The JavaDoc of FCPPluginConnectionTracker explains the general purpose of this mechanism. */ public final FCPPluginConnection getPluginConnectionByID(UUID connectionID) throws IOException { - return pluginConnectionTracker.getConnection(connectionID); + return pluginConnectionTracker.getConnection(connectionID) + .getDefaultSendDirectionAdapter(SendDirection.ToClient); } public PersistentRequestClient registerRebootClient(String name, NodeClientCore core, FCPConnectionHandler handler) { # HG changeset patch # User xor-freenet <xor at freenetproject.org> # Date 1421697610 -3600 # Mon Jan 19 21:00:10 2015 +0100 # Node ID 6661a193d6dc6af1517a57f153b82c7b01de9817 # Parent 26f3fc23479755d7b9d3da6b27d566fff5e6754d FCPServer.createFCPPluginConnectionForIntraNodeFCP(): Trim return type Reducing this to the parent interface FCPPluginConnection will allow setting the visibility of FCPPluginConnectionImpl to package private since what this commit changes is IIRC the only place which uses FCPPluginConnectionImpl in a non-package-private way. - This was made possible by implementing the usage of getDefaultSendDirectionAdapter() in this function. I had speculated that this function would be called in a caller of the FCPServer function different package, which is why this used to return the *Impl. But now that we call it here already, the FCPServer doesn't need to return the Impl. diff -r 26f3fc234797 -r 6661a193d6dc src/freenet/clients/fcp/FCPServer.java --- a/src/freenet/clients/fcp/FCPServer.java Mon Jan 19 20:58:41 2015 +0100 +++ b/src/freenet/clients/fcp/FCPServer.java Mon Jan 19 21:00:10 2015 +0100 @@ -533,7 +533,7 @@ * The class JavaDoc of FCPPluginConnectionImpl explains the code path for both networked * and non-networked FCP. */ - public final FCPPluginConnectionImpl createFCPPluginConnectionForIntraNodeFCP( + public final FCPPluginConnection createFCPPluginConnectionForIntraNodeFCP( String serverPluginName, ClientSideFCPMessageHandler messageHandler) throws PluginNotFoundException { # HG changeset patch # User xor-freenet <xor at freenetproject.org> # Date 1421698282 -3600 # Mon Jan 19 21:11:22 2015 +0100 # Node ID 78bee089eb2fa9eaaa3a24512cc10b62f05a243c # Parent a314c83833894c988e0c9a546d6b5ffb6c21fc63 FCPPluginConnectionImpl: Trim visibility diff -r a314c8383389 -r 78bee089eb2f src/freenet/clients/fcp/FCPPluginConnectionImpl.java --- a/src/freenet/clients/fcp/FCPPluginConnectionImpl.java Mon Jan 19 21:09:39 2015 +0100 +++ b/src/freenet/clients/fcp/FCPPluginConnectionImpl.java Mon Jan 19 21:11:22 2015 +0100 @@ -104,7 +104,7 @@ * <br/>This mechanism also works for networked FCP.<br> * </p></p> */ -public final class FCPPluginConnectionImpl implements FCPPluginConnection { +final class FCPPluginConnectionImpl implements FCPPluginConnection { /** Automatically set to true by {@link Logger} if the log level is set to * {@link LogLevel#DEBUG} for this class. # HG changeset patch # User xor-freenet <xor at freenetproject.org> # Date 1421701166 -3600 # Mon Jan 19 21:59:26 2015 +0100 # Node ID 91d2b74586bb4bd973f62e51e4082fd674c57d6a # Parent c426dc857d67ac35539bd19b93079fd6127c599a FCPPluginConnectionImpl: Fix "SHOULD NOT HAPPEN: java.io.IOException:" Unit test failure would be as follows: [junit] SHOULD NOT HAPPEN: java.io.IOException: FCPPluginConnection not found, maybe client has disconnected. Connection ID: 83665b37-32a6-41f3-9af7-5ca20db13324 [junit] java.lang.RuntimeException: SHOULD NOT HAPPEN: java.io.IOException: FCPPluginConnection not found, maybe client has disconnected. Connection ID: 83665b37-32a6-41f3-9af7-5ca20db13324 [junit] at freenet.clients.fcp.FCPPluginConnectionImpl$SendToClientAdapter.<init>(FCPPluginConnectionImpl.java:1021) [junit] at freenet.clients.fcp.FCPPluginConnectionImpl.<init>(FCPPluginConnectionImpl.java:376) [junit] at freenet.clients.fcp.FCPPluginConnectionImpl.constructForUnitTest(FCPPluginConnectionImpl.java:435) [junit] at freenet.clients.fcp.FCPPluginConnectionImplTest.testSendSynchronousThreadSafety(FCPPluginConnectionImplTest.java:38) diff -r c426dc857d67 -r 91d2b74586bb src/freenet/clients/fcp/FCPPluginConnectionImpl.java --- a/src/freenet/clients/fcp/FCPPluginConnectionImpl.java Mon Jan 19 21:11:52 2015 +0100 +++ b/src/freenet/clients/fcp/FCPPluginConnectionImpl.java Mon Jan 19 21:59:26 2015 +0100 @@ -311,6 +311,9 @@ this.clientConnection = clientConnection; this.defaultSendDirectionAdapters.put(SendDirection.ToServer, new SendToServerAdapter(this)); + // new SendToClientAdapter() will need to query this connection from the tracker already. + // Thus, we have to register before constructing it. + tracker.registerConnection(this); this.defaultSendDirectionAdapters.put(SendDirection.ToClient, new SendToClientAdapter(tracker, id)); } @@ -335,11 +338,8 @@ assert(serverPluginName != null); assert(clientConnection != null); - FCPPluginConnectionImpl result = new FCPPluginConnectionImpl(tracker, executor, - serverPluginName, serverPluginManager.getPluginFCPServer(serverPluginName), - clientConnection); - tracker.registerConnection(result); - return result; + return new FCPPluginConnectionImpl(tracker, executor, serverPluginName, + serverPluginManager.getPluginFCPServer(serverPluginName), clientConnection); } @@ -373,6 +373,9 @@ this.clientConnection = null; this.defaultSendDirectionAdapters.put(SendDirection.ToServer, new SendToServerAdapter(this)); + // new SendToClientAdapter() will need to query this connection from the tracker already. + // Thus, we have to register before constructing it. + tracker.registerConnection(this); this.defaultSendDirectionAdapters.put(SendDirection.ToClient, new SendToClientAdapter(tracker, id)); } @@ -398,10 +401,8 @@ assert(serverPluginName != null); assert(client != null); - FCPPluginConnectionImpl result = new FCPPluginConnectionImpl(tracker, executor, - serverPluginName, serverPluginManager.getPluginFCPServer(serverPluginName), client); - tracker.registerConnection(result); - return result; + return new FCPPluginConnectionImpl(tracker, executor, serverPluginName, + serverPluginManager.getPluginFCPServer(serverPluginName), client); } /** # HG changeset patch # User xor-freenet <xor at freenetproject.org> # Date 1421773177 -3600 # Tue Jan 20 17:59:37 2015 +0100 # Node ID 975557185f03b534046300d7688933ce8ce596c8 # Parent 3076f7d2292da011dbdbed5328cc9a65d5cad395 ServerSideFCPMessageHandler: Allow keeping strong refs to connections The FCPPluginConnections which we pass to the message handler have recently been changed to be a FCPPluginConnectionImpl.SendToClientAdapter, which internally only keeps a WeakReference to the FCPPluginConnectionImpl. Thus, the server may keep a strong reference to that wrapper without preventing GC of the actual FCPPluginConnectionImpl. Additional included JavaDoc improvements: - The "Notice that there is no..." sentence of the last item in the enumeration is moved to the front to structure the sentences to be ordered as 1. what is wrong 2. how to deal with it - Don't push people very much to implement "Ping": Say "you may" instead of "you are encouraged to". It is also possible to have implicit pinging for stuff which sends messages very frequently anyway. diff -r 3076f7d2292d -r 975557185f03 src/freenet/pluginmanager/FredPluginFCPMessageHandler.java --- a/src/freenet/pluginmanager/FredPluginFCPMessageHandler.java Tue Jan 20 17:22:00 2015 +0100 +++ b/src/freenet/pluginmanager/FredPluginFCPMessageHandler.java Tue Jan 20 17:59:37 2015 +0100 @@ -106,10 +106,7 @@ /** * <p>Is called to handle messages from your clients.<br/> * <b>Must not</b> block for very long and thus must only do small amounts of processing. - * <br/> - * You <b>must not</b> keep a hard reference to the passed {@link FCPPluginConnection} - * object outside of the scope of this function: This would prevent client plugins from - * being unloaded. See below for how to keep a reference to a client connection.</p> + * </p> * * <p>If you ...<br/> * - Need a long time to compute a reply.<br/> @@ -117,31 +114,28 @@ * the client after having exited this function; maybe even triggered by events at your * plugin, not by client messages.<br/> * Then you should:<br/> - * - Obtain the {@link UUID} of the client connection via {@link FCPPluginConnection# - * getID()}, store the {@link UUID}, and exit this message handling function.<br/> + * - Store the passed {@link FCPPluginConnection}. If you cannot store objects in memory, + * for example because you are using a database, you can get the {@link UUID} of the + * connection via {@link FCPPluginConnection#getID()}, store only that, and then in the + * future get back the connection using + * {@link PluginRespirator#getPluginConnectionByID(UUID)}.<br> * - Compute your reply in another thread.</br> - * - Once you're ready to send the reply, use - * {@link PluginRespirator#getPluginConnectionByID(UUID)} to obtain the original - * {@link FCPPluginConnection}, and then send the message using the send functions of the + * - Once you're ready to send the reply, send the message using the send functions of the * {@link FCPPluginConnection}.<br/> - * - If you keep client connection {@link UUID} for longer than sending a single reply, make - * sure to prevent excessive growth of your connection database upon client disconnection + * - Notice that there is no explicit disconnection mechanism. Clients can come and go as + * they please. The only way to be sure that a connection is alive is by checking whether + * the client replies to messages.<br> + * Thus, if you store client connections for longer than sending a single reply, make sure + * to prevent excessive growth of your connection database upon client disconnection * by implementing a garbage collection mechanism as follows:<br> * Periodically send a message at each connection and check if you get a reply within a * reasonable timeout to check whether the connection is still alive. Drop the connection - * if not.<br> - * Notice that there is no explicit disconnection mechanism. Clients can come and go as - * they please. The only way to be sure that a connection is alive is by checking whether - * the client replies to messages. You are encouraged to make a "Ping" message with a - * "Pong" response a requirement for your server's protocol.<br> + * if not. You may make a "Ping" message with a "Pong" response a requirement for your + * server's protocol.<br> * </p> * * @param connection * The connection of the client which sent the message.<br/><br/> - * You <b>must not</b> keep a hard reference to this object outside of the scope - * of this function: This would prevent client plugins from being unloaded. See - * the head of the documentation of this function for an explanation of how to - * store a pointer to a certain client connection.<br/><br/> * * You <b>must not</b> use its send functions for sending back the main reply. * Instead, use the return value for shipping the reply. (You are free to send # HG changeset patch # User xor-freenet <xor at freenetproject.org> # Date 1421774244 -3600 # Tue Jan 20 18:17:24 2015 +0100 # Node ID 37ef59f5f65f86cbcfc3894ee3aa5f6d5142a40a # Parent 975557185f03b534046300d7688933ce8ce596c8 FCPPluginConnectionImpl: Detect bogus reply message identifiers The FredPluginFCPMessageHandler instructs users to always construct reply messages in a way mich makes them have the same identifier as the original messagge. Thus, we shouldn't allow reply messages which have a differing identifier. diff -r 975557185f03 -r 37ef59f5f65f src/freenet/clients/fcp/FCPPluginConnectionImpl.java --- a/src/freenet/clients/fcp/FCPPluginConnectionImpl.java Tue Jan 20 17:59:37 2015 +0100 +++ b/src/freenet/clients/fcp/FCPPluginConnectionImpl.java Tue Jan 20 18:17:24 2015 +0100 @@ -787,6 +787,18 @@ reply = null; } + + if(!reply.identifier.equals(message.identifier)) { + Logger.error(messageHandler, "FredPluginFCPMessageHandler tried to send a" + + " reply with with different identifier than original message." + + " See JavaDoc of its member interfaces for how to do this properly." + + " connection = " + FCPPluginConnectionImpl.this + + "; original message SendDirection = " + direction + + "; original message = " + message + + "; reply = " + reply); + + reply = null; + } } else if(reply == null) { if(!message.isReplyMessage()) { // The message handler did not not ship a reply even though it would have # HG changeset patch # User xor-freenet <xor at freenetproject.org> # Date 1421774719 -3600 # Tue Jan 20 18:25:19 2015 +0100 # Node ID b4d2452d8d13fdad4eb93f3b3bcbfc5830dd6537 # Parent 37ef59f5f65f86cbcfc3894ee3aa5f6d5142a40a DefaultSendDirectionAdapter: Implement toString() As it is specified in FCPPluginConnection to contain debug information about the FCPPluginConnection, and FCPPluginConnectionImpl implements it to provide much information. diff -r 37ef59f5f65f -r b4d2452d8d13 src/freenet/clients/fcp/FCPPluginConnectionImpl.java --- a/src/freenet/clients/fcp/FCPPluginConnectionImpl.java Tue Jan 20 18:17:24 2015 +0100 +++ b/src/freenet/clients/fcp/FCPPluginConnectionImpl.java Tue Jan 20 18:25:19 2015 +0100 @@ -1111,6 +1111,15 @@ @Override public UUID getID() { return connectionRef.connectionID; } + + @Override public String toString() { + String prefix = "SendToClientAdapter for "; + try { + return prefix + getConnection(); + } catch(IOException e) { + return prefix + " FCPPluginConnectionImpl (" + e.getMessage() + ")"; + } + } } /** @@ -1147,6 +1156,10 @@ @Override public UUID getID() { return parent.getID(); } + + @Override public String toString() { + return "SendToServerAdapter for " + parent; + } } /** # HG changeset patch # User xor-freenet <xor at freenetproject.org> # Date 1421775531 -3600 # Tue Jan 20 18:38:51 2015 +0100 # Node ID 810ec77790f2aca7f900019ef380bae5367dff5d # Parent b4d2452d8d13fdad4eb93f3b3bcbfc5830dd6537 FCPPluginConnectionImpl: Fix NullPointerException diff -r b4d2452d8d13 -r 810ec77790f2 src/freenet/clients/fcp/FCPPluginConnectionImpl.java --- a/src/freenet/clients/fcp/FCPPluginConnectionImpl.java Tue Jan 20 18:25:19 2015 +0100 +++ b/src/freenet/clients/fcp/FCPPluginConnectionImpl.java Tue Jan 20 18:38:51 2015 +0100 @@ -786,9 +786,7 @@ + "; reply = " + reply); reply = null; - } - - if(!reply.identifier.equals(message.identifier)) { + } else if(!reply.identifier.equals(message.identifier)) { Logger.error(messageHandler, "FredPluginFCPMessageHandler tried to send a" + " reply with with different identifier than original message." + " See JavaDoc of its member interfaces for how to do this properly." # HG changeset patch # User xor-freenet <xor at freenetproject.org> # Date 1421775646 -3600 # Tue Jan 20 18:40:46 2015 +0100 # Node ID c44303d925deff911c63f0556ea89c33716c4cc3 # Parent 810ec77790f2aca7f900019ef380bae5367dff5d FCPPluginConnectionImpl: Detect non-reply replies The FredPluginFCPMessageHandler JavaDoc instructs users to always construct reply messages in a way which causes them to be marked as reply. Thus, we shouldn't allow reply messages which have !isReplyMessage(). diff -r 810ec77790f2 -r c44303d925de src/freenet/clients/fcp/FCPPluginConnectionImpl.java --- a/src/freenet/clients/fcp/FCPPluginConnectionImpl.java Tue Jan 20 18:38:51 2015 +0100 +++ b/src/freenet/clients/fcp/FCPPluginConnectionImpl.java Tue Jan 20 18:40:46 2015 +0100 @@ -786,6 +786,16 @@ + "; reply = " + reply); reply = null; + } else if(!reply.isReplyMessage()) { + Logger.error(messageHandler, "FredPluginFCPMessageHandler tried to send a" + + " non-reply message as reply. See JavaDoc of its member interfaces" + + " for how to do this properly." + + " connection = " + FCPPluginConnectionImpl.this + + "; original message SendDirection = " + direction + + "; original message = " + message + + "; reply = " + reply); + + reply = null; } else if(!reply.identifier.equals(message.identifier)) { Logger.error(messageHandler, "FredPluginFCPMessageHandler tried to send a" + " reply with with different identifier than original message." # HG changeset patch # User xor-freenet <xor at freenetproject.org> # Date 1421784049 -3600 # Tue Jan 20 21:00:49 2015 +0100 # Node ID 130f29438bccc10b6ebe0b07af407113b0e667b4 # Parent c44303d925deff911c63f0556ea89c33716c4cc3 PluginRespirator.getPluginConnectionByID(): Linkify "connection" diff -r c44303d925de -r 130f29438bcc src/freenet/pluginmanager/PluginRespirator.java --- a/src/freenet/pluginmanager/PluginRespirator.java Tue Jan 20 18:40:46 2015 +0100 +++ b/src/freenet/pluginmanager/PluginRespirator.java Tue Jan 20 21:00:49 2015 +0100 @@ -179,7 +179,7 @@ /** * Allows FCP server plugins, that is plugins which implement * {@link FredPluginFCPMessageHandler.ServerSideFCPMessageHandler}, to obtain an existing client - * connection by its {@link UUID} - if the client is still connected.<br><br> + * {@link FCPPluginConnection} by its {@link UUID} - if the client is still connected.<br><br> * * <b>Must not</b> be used by client plugins: They shall instead keep a hard reference to the * {@link FCPPluginConnection} in memory after they have received it from -- unpolitisch sein heiÃt politisch sein, ohne es zu merken. - ArneBab ( http://draketo.de ) -------------- next part -------------- An embedded and charset-unspecified text was scrubbed... Name: sync-fcp-diff-since-review-bertm-only-functional.diff URL: <https://emu.freenetproject.org/pipermail/devl/attachments/20150220/7b7726c2/attachment-0001.ksh>