> -----Ursprüngliche Nachricht-----
> Von: "Daniel Cheng" <[email protected]>
> Gesendet: 16.03.09 10:11:34
> An: Discussion of development issues <[email protected]>
> Betreff: Re: [freenet-dev] [freenet-cvs] r26044 
> -trunk/freenet/src/freenet/pluginmanager

> 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.
>

my suggestion: revert the api-spec-breaking (no rulez!) blocking calls and 
implement this on client/plugin side:

package plugins.Freetalk;

import freenet.pluginmanager.FredPluginTalker;
import freenet.pluginmanager.PluginNotFoundException;
import freenet.pluginmanager.PluginRespirator;
import freenet.pluginmanager.PluginTalker;
import freenet.support.SimpleFieldSet;
import freenet.support.api.Bucket;

public class BlockingTalker implements FredPluginTalker {
        
        private Result result = null;
        
        private Object waitObject = new Object();
        
        static class Result {
                final SimpleFieldSet sfs;
                final Bucket data;
                
                Result(SimpleFieldSet sfs, Bucket data) {
                        this.sfs = sfs;
                        this.data = data;
                }
        };
        
        Result blockingCall(PluginRespirator pr, SimpleFieldSet params, Bucket 
data) throws PluginNotFoundException {
                PluginTalker talker = pr.getPluginTalker(this, 
Freetalk.WOT_NAME, Freetalk.PLUGIN_TITLE);
                talker.send(params, data);
                
                while (result == null /* or timeout */) {
                        try {
                                waitObject.wait();
                        } catch (InterruptedException e) {
                        }
                }
                return result;
        }

        public void onReply(String pluginname, String indentifier, 
SimpleFieldSet params, Bucket data) {
                result = new Result(params, data);
                waitObject.notifyAll();
        }
} 

MfG saces

______________________________________________________________________________
Nur bis 16.03.! DSL-Komplettanschluss inkl. WLAN-Modem für nur 17,95 EURO/mtl.
 + 1 Monat gratis!* http://dsl.web.de/?ac=OM.AD.AD008K15039B7069a

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

Reply via email to