On Mon, Mar 16, 2009 at 2:51 PM, xor <[email protected]> wrote:
>
>
>> -----Original Message-----
>> From: [email protected]
>> [mailto:[email protected]] On Behalf Of Daniel Cheng
>> Sent: Monday, March 16, 2009 1:19 AM
>> To: [email protected]
>> Subject: Re: [freenet-dev] [freenet-cvs] r26044
>> -trunk/freenet/src/freenet/pluginmanager
>>
>> On Sun, Mar 15, 2009 at 11:35 PM,  <[email protected]> wrote:
>> > Author: xor
>> > Date: 2009-03-15 15:35:03 +0000 (Sun, 15 Mar 2009) New
>> Revision: 26044
>> >
>> > Added:
>> >   trunk/freenet/src/freenet/pluginmanager/PluginTalkerBlocking.java
>> > Modified:
>> >   trunk/freenet/src/freenet/pluginmanager/PluginTalker.java
>> > Log:
>> > Implement a blocking PluginTalker. This is to be used if
>> the result of a FCP call is needed by the caller directly,
>> i.e. in UI functions. For example, when creating an identity
>> using the Freetalk web interface, we need to show the user
>> directly whether the attempt to create it was successful.
>> >
>> > Modified: trunk/freenet/src/freenet/pluginmanager/PluginTalker.java
>> > ===================================================================
>> > --- trunk/freenet/src/freenet/pluginmanager/PluginTalker.java
>> > 2009-03-14 16:03:52 UTC (rev 26043)
>> > +++ trunk/freenet/src/freenet/pluginmanager/PluginTalker.java
>> > +++ 2009-03-15 15:35:03 UTC (rev 26044)
>> > @@ -15,15 +15,19 @@
>> >  */
>> >  public class PluginTalker {
>> >
>> > -       Node node;
>> > -       private PluginReplySender replysender;
>> > +       protected Node node;
>> > +       protected PluginReplySender replysender;
>> >
>> > -       private int access;
>> > +       protected int access;
>> >
>> > -       FredPluginFCP plugin;
>> > +       protected FredPluginFCP plugin;
>> > +       protected String pluginName;
>> > +       protected String connectionIdentifier;
>> >
>> > -       PluginTalker(FredPluginTalker fpt, Node node2, String
>> > pluginname2, String identifier2) throws PluginNotFoundException {
>> > +       public PluginTalker(FredPluginTalker fpt, Node
>> node2, String
>> > + pluginname2, String identifier2) throws PluginNotFoundException {
>> >                node = node2;
>> > +               pluginName = pluginname2;
>> > +               connectionIdentifier = identifier2;
>> >                plugin = findPlugin(pluginname2);
>> >                access = FredPluginFCP.ACCESS_DIRECT;
>> >                replysender = new
>> PluginReplySenderDirect(node2, fpt,
>> > pluginname2, identifier2); @@ -31,12 +35,14 @@
>> >
>> >        public PluginTalker(Node node2, FCPConnectionHandler
>> handler,
>> > String pluginname2, String identifier2, boolean access2) throws
>> > PluginNotFoundException {
>> >                node = node2;
>> > +               pluginName = pluginname2;
>> > +               connectionIdentifier = identifier2;
>> >                plugin = findPlugin(pluginname2);
>> >                access = access2 ? FredPluginFCP.ACCESS_FCP_FULL :
>> > FredPluginFCP.ACCESS_FCP_RESTRICTED;
>> >                replysender = new PluginReplySenderFCP(handler,
>> > pluginname2, identifier2);
>> >        }
>> >
>> > -       private FredPluginFCP findPlugin(String pluginname2) throws
>> > PluginNotFoundException {
>> > +       protected FredPluginFCP findPlugin(String
>> pluginname2) throws
>> > + PluginNotFoundException {
>> >
>> >                Logger.normal(this, "Searching fcp plugin: " +
>> > pluginname2);
>> >                FredPluginFCP plug =
>> > node.pluginManager.getFCPPlugin(pluginname2);
>> >
>> > Added:
>> > trunk/freenet/src/freenet/pluginmanager/PluginTalkerBlocking.java
>> > ===================================================================
>> > ---
>> trunk/freenet/src/freenet/pluginmanager/PluginTalkerBlocking.j
>> ava
>> > (rev 0)
>> > +++
>> trunk/freenet/src/freenet/pluginmanager/PluginTalkerBlocking.java
>> > +++ 2009-03-15 15:35:03 UTC (rev 26044)
>> > @@ -0,0 +1,93 @@
>> > +/* 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.pluginmanager;
>> > +
>> > +import freenet.node.Node;
>> > +import freenet.support.Logger;
>> > +import freenet.support.SimpleFieldSet; import
>> > +freenet.support.api.Bucket;
>> > +
>> > +/**
>> > + * A PluginTalker which has a sendBlocking() function
>> which directly returns the result of the FCP call to the caller.
>> > + * This can be used to simplify code which uses FCP very
>> much, especially UI code which needs the result of FCP calls directly.
>> > + *
>> > + * @author xor
>> > + */
>> > +public class PluginTalkerBlocking extends PluginTalker {
>> > +
>> > +       public PluginTalkerBlocking(FredPluginTalker
>> myPluginTalker,
>> > + Node myNode, String myPluginName, String myConnectionIdentifier)
>> > +               throws PluginNotFoundException {
>> > +               super(myPluginTalker, myNode, myPluginName,
>> > + myConnectionIdentifier);
>> > +               // TODO Auto-generated constructor stub
>> > +       }
>> > +
>> > +       public static class Result {
>> > +               public SimpleFieldSet params;
>> > +               public Bucket data;
>> > +
>> > +               public Result(SimpleFieldSet myParams,
>> Bucket myData)
>> > + {
>> > +                       params = myParams;
>> > +                       data = myData;
>> > +               }
>> > +       }
>> > +
>> > +       protected class PluginReplySenderBlocking extends
>> > + PluginReplySender {
>> > +
>> > +               protected final PluginReplySender
>> > + nonBlockingReplySender;
>> > +               protected volatile Result mResult;
>> > +
>> > +               public PluginReplySenderBlocking() {
>> > +                       super(pluginName, connectionIdentifier);
>> > +                       nonBlockingReplySender = replysender;
>> > +               }
>> > +
>> > +               @Override
>> > +               public synchronized void
>> send(SimpleFieldSet params,
>> > + Bucket bucket) {
>> > +                       if(mResult == null) {
>> > +                               mResult = new
>> Result(params, bucket);
>> > +                               notifyAll();
>> > +                       } else {
>> > +                               Logger.error(this,
>> > + "PluginTalkerBlocking is being used with a FCP call which
>> results in
>> > + more than 1 reply");
>> > +                               nonBlockingReplySender.send(params,
>> > + bucket);
>> > +                       }
>>
>> If the user ask for blocking, throw a exception if it can't.
>> Don't fallback to async -- the client asked for blocking for a reason.
>
> The exception unfortunately could not be thrown to the caller of
> sendBlocking() because it is the plugin which receives the message which
> calls send() twice or more and after the first send(), the "Result"-object
> is returned to the caller of sendBlocking(), so when the plugin calls send()
> a second time, sendBlocking() will already have returned.
>
> Would it be useful to throw the exception at the plugin? I do not think so.
> It is legal in FCP to call send() more than once when handling a FCP
> message, isn't it?

The real question is : Who need blocking send, and why?

If we *really* have to do it synchronously, we should have notify the
the caller.
If not, why bother to write this at all?

>>
>> > +               }
>> > +
>> > +               public Result getResult() {
>> > +                       while(mResult == null) {
>> > +                               try {
>> > +                                       wait();
>>
>> this would throw Illegal Monitor State Exception make it synchronized,
>>
>> > +                               } catch (InterruptedException e) {
>> > +                               }
>> > +                       }
>> > +
>> > +                       return mResult;
>> > +               }
>> > +
>> > +       }
>> > +
>> > +       /**
>> > +        * When using sendBlocking(), please make sure that
>> you only ever call it for FCP functions which only send() a
>> single result!
>> > +        * Results which are sent by the plugin after the
>> first result
>> > + are dispatched to the asynchronous onReply() function of your
>> > +        * FredPluginTalker, however this behavior is
>> deprecated and not guranteed to work.
>> > +        */
>> > +       public Result sendBlocking(final SimpleFieldSet plugparams,
>> > + final Bucket data2) {
>> > +               final PluginReplySenderBlocking replySender = new
>> > + PluginReplySenderBlocking();
>> > +
>> > +               node.executor.execute(new Runnable() {
>> > +
>>
>> Why spawn a thread, if all you want is blocking behaviour?
>
> Hmmmm yea this is right, it doesn't really make sense. The code was
> copy-pasted from the non-blocking version, thats the reason.
> I am just wondering right now whether it still might make sense to execute
> it in a separate thread... well, it would allow us to give the caller of
> sendBlocking() a timeout value. Further, we wouldn't be mixing the execution
> of plugins into single threads, each thread would clearly belong to one
> plugin - I don't know whether this has any more advantages than feeling more
> clean?

With this addition,
our executor things have grow to (almost) the same complexity of
java.until.concurrent.ExecutorService ...

The Future / Callable interface may look strange at the first look,
but it is designed by the Doug Lea (*THE* java thread and memory model
guy) with maximum performance and least need or manual
synchronization..

The blocking + timeout in java.util.concurrent.ExecurorService is:

Future<Result> ft  = executor.submit(  callable );
Result r = ft.get( timeout ,  TimeUnit.SECOND );
if (r != null )
    ....

Please have a look at it.
If you can live with that interface, I will port
freenet.support.Executor to use them.

--
_______________________________________________
Devl mailing list
[email protected]
http://emu.freenetproject.org/cgi-bin/mailman/listinfo/devl

Reply via email to