You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@cocoon.apache.org by Antonio Gallardo <ag...@agssa.net> on 2004/04/04 06:45:49 UTC

Groovy support in Cocoon

Hi:

Hi:

Some of us wanted to see Groovy support in Cocoon. Now we can "play" a
little with Groovy using the recently added support for Groovy script
generator under the BSF block. More info about how to use it is here:

http://cocoon.apache.org/2.1/userdocs/generators/script-generator.html

SITEMAP CONFIGURATION FOR GROOVY:
======================

In components section add:

<map:generator name="script"
    src="org.apache.cocoon.generation.ScriptGenerator"
    logger="sitemap.generation.scriptgenerator">
  <!-- Groovy support -->
  <add-languages>
    <language name="groovy" src="org.codehaus.groovy.bsf.GroovyEngine">
      <extension>groovy</extension>
      <extension>gy</extension>
    </language>
  </add-languages>
</map:generator>

I hope this will have a good welcome in the Cocoon Community.

Best Regards,

Antonio Gallardo

Re: Groovy support in Cocoon

Posted by Stephan Michels <st...@apache.org>.
Am So, den 04.04.2004 schrieb Christopher Oliver um 20:32:
> Stefano Mazzocchi wrote:
> >
> > Next I would like to see is a groovy implementation of flow ;-)
> >
> It should be _fairly_ straightforward. The only tricky part I see is 
> controlling the byte-code transformation. All methods in the call-chain 
> leading from the method invoked by Interpreter.callFunction()  to 
> sendPageAndWait() or any other method that creates a continuation must 
> be instrumented. The current implementation only instruments classes 
> that implement the interface "Continuable". In the case of scripting 
> languages like Groovy, Jython, or Rhino, pretty much the entire 
> interpreter and all classes generated from scripts will need to be 
> instrumented. Any callbacks from non-instrumented code to instrumented 
> code will break the continuation.

Yes, that's correct, the complete stacktrace must be 'instrumented' to
restore the continuation. I thought about it a long time to get
an idea how fix this problem, but I get no idea :-/

BTW, I must add a flag to the Continuation Class, to mark the
continuation as disabled for calling uninstrumented code.

> One approach might be to instrument the build system to rename class 
> files that require instrumentation to have a special extension 
> (".iclass" or whatever) making them invisible to normal class loaders 
> but recognizable to the class loader that performs the byte-code 
> transformation.

Are you talking about instrumenting at compile time?

> Another possible approach is to provide a configuration to the class 
> loader using wildcard specifications (e.g. "groovy.*", etc) to allow it 
> to identify which classes to instrument.

Yes, I think it's a good idea. It's same problem like specifying the
pointcuts in AOP.

Stephan.


Re: Groovy support in Cocoon

Posted by Stephan Michels <st...@apache.org>.
Am Mo, den 05.04.2004 schrieb Christopher Oliver um 19:18:
> After thinking about this a few more minutes over coffee, I like the 
> idea of constructing the continuation stack as the JVM stack is unwound 
> (that way "normal" code doesn't encounter any overhead other than the 
> tests for isRestoring() and isCapturing(). So perhaps what we could do 
> when Continuation.getCurrentContinuation() is called is to unwind the 
> JVM stack, constructing the continuation stack, and then immediately 
> restore it returning the newly created continuation object (which will 
> contain a copy of the continuation stack we just created). If the 
> continuation object is invoked we will again unwind the current JVM 
> stack, but this time there's no need to capture it.

Yes, the hole idea was to leave the code as it is and only test after
every invocation if the Continuation goes into the state "capturing".
And you can check at the compile time if the destination object is
"continuable". So you must only check isCapturing() after method calls
which are "continuable".

But there is a pitfall, see

        calls                            calls
MyFlow -------> MyClass(uninstrumented) -------> MyFlow -->
Continuation.suspend()

In this case the complete stacktrace can't be restored. So I must
add a flag to signal that I can't suspend the continuation. But
this should be easily implemented.

To come back to BSF and Groovy, I think a class like a ContinationProxy
should do the work.

ContinuableBSFInterpreter -> Groovy -> ContinationProxy -> Groovy Class

The ContinuationProxy can assign a new Continuation to the thread
and invoke the Groovy Class.

Stephan.


Re: Groovy support in Cocoon

Posted by Christopher Oliver <re...@verizon.net>.
After thinking about this a few more minutes over coffee, I like the 
idea of constructing the continuation stack as the JVM stack is unwound 
(that way "normal" code doesn't encounter any overhead other than the 
tests for isRestoring() and isCapturing(). So perhaps what we could do 
when Continuation.getCurrentContinuation() is called is to unwind the 
JVM stack, constructing the continuation stack, and then immediately 
restore it returning the newly created continuation object (which will 
contain a copy of the continuation stack we just created). If the 
continuation object is invoked we will again unwind the current JVM 
stack, but this time there's no need to capture it.

Chris


Christopher Oliver wrote:

> Stephan Michels wrote:
>
>> Am Mo, den 05.04.2004 schrieb Christopher Oliver um 4:42:
>>  
>>
>>> The current implementation needs some work to qualify as 
>>> "generalized Java continuations". It would be nice to make it work 
>>> more like Scheme continuations:
>>>
>>> 1) When you access the "current" continuation, it captures the call 
>>> stack up to but not including the current method (and makes a 
>>> (shallow) copy of it). The current method continues as normal.   
>>
>>
>> What to you mean with "continues as normal". The current impl. stops the
>> execution of the method with null as return value, if the cuntinuation
>> is suspended. Then the continuation captures the object of the method
>> call and the current frame.
>>  
>>
> OK, IIUC there are three modes of execution of the instrumented code:
>
> 1) isCapturing
> During this mode the JVM call stack is unwound and its state captured 
> in the continuation call stack.
> 2) isRestoring
> During this mode a saved call stack in a continuation is recreated on 
> the JVM stack.
> 3) !isCapturing && !isRestoring
> This is the "normal" execution of the JVM  - no modifications are made 
> to the JVM call stack or to the continuation call stack.
>
> This is achieved by inserting code before each invoke instruction to 
> copy local variables from the continuation stack to the JVM stack and 
> to reset the program counter to the value saved in the continuation 
> stack if "isRestoring" is true, and by inserting code after each 
> invoke instruction to copy the values of local variables from the JVM 
> call stack as well as the program counter into the continuation call 
> stack if "isCapturing" is true.
>
> To make continuations more "Scheme-like" it must be possible to 
> construct a continuation without modifying the JVM call stack (thus 
> the current method invocation can "continue as normal").
>
> To make this possible the byte-code transformer could work like this:
>
> 1) Insert code before an invoke instruction to push local vars and the 
> pc onto the continuation stack if (!isRestoring && !isCapturing)
> 2) Insert code after an invoke instruction to pop those values from 
> the continuation stack if (!isRestoring && !isCapturing)
> 3) If (isRestoring == true) the pre-invoke code would work as it does 
> now.
> 4) If (isCapturing == true) the post-invoke code would simply cause 
> the current method invocation to return to its caller without 
> modifying the continuation stack - since it is already set up from 
> (1). When the JVM stack is completely unwound another continuation 
> will take the place of this one and that new continuation would be in 
> "isRestoring" mode until it is recreated on the JVM stack at which 
> point it would enter (!isRestoring && !isCapturing) mode.
>
> The user interface to this might look something like this:
>
> public class Continuation {
>        // Empty continuation for use as an escape procedure
>        public static final Continuation SUICIDE;
>
>        // Invoke a captured continuation - it will replace the current 
> continuation. I.e. the current JVM call stack will be unwound, the 
> call stack saved in this object will be recreated on the JVM call 
> stack, and the method invocation in which this object was created will 
> return with "returnValue".
>        public void invoke(Object returnValue);
>        // Get the current continuation -
>        public static Continuation getCurrentContinuation();
>        // Entry point to the instrumented code (precondition: cannot 
> be called recursively and method.getDeclaringClass() must be 
> instrumented)
>        public static Object invoke(Object obj, Method method, Object[] 
> args);
> }
>
>
> Below is some pseudo-code that shows how this would work with Cocoon:
>
> public class JavaInterpreter {
>        // ...
>        public void callFunction(String function, List params, 
> Redirector redirector)
>            throws Exception {
>            if (!initialized)
>                initialize();
>
>            Method method = (Method) methods.get(function);
>            Request request = 
> ContextHelper.getRequest(this.avalonContext);
>            Session session = request.getSession(true);
>            HashMap userScopes = (HashMap) 
> session.getAttribute(USER_GLOBAL_SCOPE);
>            if (userScopes == null)
>               userScopes = new HashMap();
>
>            Object flow = (Object) 
> userScopes.get(method.getDeclaringClass());
>
>            if (flow == null) {
>                if (getLogger().isDebugEnabled())
>                   getLogger().debug("create new instance of 
> \""+method.getDeclaringClass()+"\"");
>
>            flow =  method.getDeclaringClass().newInstance();
>            userScopes.put(method.getDeclaringClass(), flow);
>            int size = params == null ? 0 : params.size();
>            Object[] args = new Object[size];
>            for (int i = 0; i < size; i++) {
>                    Interpreter.Argument arg = 
> (Interpreter.Argument)params.get(i);
>                    args[i] = arg.value;
>            }
>            Continuation.invoke(flow, method, args);
>        }
>
>        public void handleContinuation(String id, List params, 
> Redirector redirector)
>            throws Exception {
>            if (!initialized)
>                initialize();
>
>            WebContinuation wk = 
> continuationsMgr.lookupWebContinuation(id);
>            Continuation k = (Continuation) wk.getContinuation();
>             k.invoke(wk);
>         }
>
> }
>
> public class Cocoon {
>     // ...
>     public WebContinuation sendPageAndWait(String uri, Object biz, 
> long ttl) {
>              Continuation kont = Continuation.getCurrentContinuation();
>              WebContinuation wk = 
> continuationsMgr.createWebContinuation(kont,
>                                           parentWebContinuation,
>                                           ttl,
>                                           null);
>               sendPage(uri, biz);
>               Continuation.SUICIDE.invoke(null);
>               return wk; // never reached
>     }
>
>      public void sendPage(String uri, Object biz) {
>           // ...
>      }
> }
>
>
> Chris
>


Re: Scheme Continuations vs Brakes Continuations was Re: Groovy support in Cocoon

Posted by Christopher Oliver <re...@verizon.net>.
Stephan Michels wrote:

>Am Mo, den 05.04.2004 schrieb Christopher Oliver um 22:44:
>  
>
>>>Why don't use (Object obj, Method method, Object[] args) in the
>>>constructor of the continuation object.
>>>      
>>>
>>That's a possible alternative, but makes prevents making Continuation an 
>>abstract class.
>>    
>>
>
>Why should the continuation be abstract? The idea of the brakes people
>was to create something similar to java.lang.Thread
>
>  
>
Primarily to hide the implementation details, but this is not a big issue.

> <snip>
>
>>This behavior is as in Scheme.
>>    
>>
>
>Hmmm, not every intuitive. So your f() has the same role like
>Continuation.suspend() ?
>
>  
>
Yes. Although it may seem unintuitive at first glance, there is a long 
and well-known history of continuations in Scheme. We should try to 
follow that model if possible, IMO.

BTW, I started playing around with BCEL and your code (mostly debugging 
VerifyErrors whenever I try to add anything... ;)). One serious problem 
I noticed is that we can never allow calls through reflection in the 
call chain that leads to creation of a continuation - because 
java.lang.reflect.Method.invoke() is not and cannot be instrumented. I 
know Rhino has the capability to generate "Invoker" classes at runtime 
to replace reflection calls with direct compiled calls 
(http://lxr.mozilla.org/mozilla/source/js/rhino/src/org/mozilla/javascript/Invoker.java). 
These "Invoker" classes _could_ be instrumented and therefore used in a 
continuation. However, some changes to Rhino would be required I think, 
because these classes are loaded by a Rhino-internal class loader so 
there's no opportunity to instrument them. I don't know if Groovy or 
Jython use reflection. If so, a similar approach to Rhino's "Invoker" 
could be used there also.

Regards,

Chris

Re: Scheme Continuations vs Brakes Continuations was Re: Groovy support in Cocoon

Posted by Stephan Michels <st...@apache.org>.
Am Mo, den 05.04.2004 schrieb Christopher Oliver um 22:44:
> >Why don't use (Object obj, Method method, Object[] args) in the
> >constructor of the continuation object.
>
> That's a possible alternative, but makes prevents making Continuation an 
> abstract class.

Why should the continuation be abstract? The idea of the brakes people
was to create something similar to java.lang.Thread

Thread t = new Thread(new Runnable() {
  void run() {
    sendPage("a");
    wait();
    sendPage("b");
  }
}); 
t.start();


> >Continuation.SUICIDE.invoke(null); ?
> >
> >*you see many question marks over my head*
> >
> >I hope you have patience with me :)
> >
> >  
> >
> The idea of SUICIDE is that it has the effect of unwinding the stack but 
> not executing any further code and directly returns to the entry point 
> (i.e. it is the continuation of the end of some code ). For example (in JS):
> 
> var suicide;
> 
> function f() {
>    suicide = arguments.continuation;
> }
> 
> f();  // <== since there's no code to execute after f(), invoking 
> suicide later will have the effect of simply terminating the script.
> // end of script
> 
> 
> In the current Rhino implementation creating a Continuation in a 
> top-level script has the same effect (since what comes after the end of 
> the script is - nothing).
> 
> This behavior is as in Scheme.

Hmmm, not every intuitive. So your f() has the same role like
Continuation.suspend() ?

With call of suspend() the Continuation goes from the State "restoring"
into State "!restoring & !capturing", and in cases of the 
state "!restoring & !capturing" into the state "capturing".

Stephan.


Re: Scheme Continuations vs Brakes Continuations was Re: Groovy support in Cocoon

Posted by Christopher Oliver <re...@verizon.net>.
Stephan Michels wrote:

>First, I'm glad to hear more input ;-) Your mail took some time
>to parse it.
>
>Am Mo, den 05.04.2004 schrieb Christopher Oliver um 18:47:
>  
>
>>OK, IIUC there are three modes of execution of the instrumented code:
>>
>>1) isCapturing
>>During this mode the JVM call stack is unwound and its state captured in 
>>the continuation call stack.
>>2) isRestoring
>>During this mode a saved call stack in a continuation is recreated on 
>>the JVM stack.
>>3) !isCapturing && !isRestoring
>>This is the "normal" execution of the JVM  - no modifications are made 
>>to the JVM call stack or to the continuation call stack.
>>    
>>
>
>Correct.
>
>  
>
>>This is achieved by inserting code before each invoke instruction to 
>>copy local variables from the continuation stack to the JVM stack and to 
>>reset the program counter to the value saved in the continuation stack 
>>if "isRestoring" is true, and by inserting code after each invoke 
>>instruction to copy the values of local variables from the JVM call 
>>stack as well as the program counter into the continuation call stack if 
>>"isCapturing" is true.
>>    
>>
>
>Yes, but the code for the restore procedure is at the begining of the
>method not the before the invocation, but anyway..
>  
>
Yes, of course. Sorry for not being more accurate.

>I need some pseudo code for myself ;-) Current situation:
>
>void myFlow() {
>  if (continuation.isRestoring()) {
>     continuation.getStack().popLocalVariables();
>     continuation.getStack().popOperandStack();
>     continuation.getStack().popReference(); // used for the  
>                                        //method invocation
>     push(null) as many null object as the method invovation need for 
>                the parameters
>     goto continuation.getStack().popLastProcessCounter();
>  }
>
>  [...]
>
>label 1:
>  invoke MySubFlow.bla();
>
>  if (continuation.isCapturing() {
>     remove the return value (is unimportant)
>     continuation.getStack().pushLocalVariables();
>     continuation.getStack().pushOperandStack();
>     continuation.getStack().pushLastProcessCounter(label 1);
>     continuation.getStack().pushReference(this);
>     return null or void;
>  }
>
>  [...]
>}
>
>  
>
OK.

>>To make continuations more "Scheme-like" it must be possible to 
>>construct a continuation without modifying the JVM call stack (thus the 
>>current method invocation can "continue as normal").
>>
>>To make this possible the byte-code transformer could work like this:
>>1) Insert code before an invoke instruction to push local vars and the 
>>pc onto the continuation stack if (!isRestoring && !isCapturing)
>>2) Insert code after an invoke instruction to pop those values from the 
>>continuation stack if (!isRestoring && !isCapturing)
>>3) If (isRestoring == true) the pre-invoke code would work as it does now.
>>4) If (isCapturing == true) the post-invoke code would simply cause the 
>>current method invocation to return to its caller without modifying the 
>>continuation stack - since it is already set up from (1). When the JVM 
>>stack is completely unwound another continuation will take the place of 
>>this one and that new continuation would be in "isRestoring" mode until 
>>it is recreated on the JVM stack at which point it would enter 
>>(!isRestoring && !isCapturing) mode.
>>    
>>
>
>Okay to recapitulate IIUC. Your proposal:
>
>void myFlow() {
>  if (continuation.isRestoring()) {
>     continuation.getStack().popLocalVariables();
>     continuation.getStack().popOperandStack();
>     goto continuation.getStack().popLastProcessCounter();
>  }
>
>  [...]
>
>  continuation.getStack().pushLocalVariables();
>  continuation.getStack().pushOperandStack();
>  continuation.getStack().pushLastProcessCounter(label 1);
>
>label 1:
>  invoke MySubFlow.bla();
>
>  if (continuation.isCapturing() {
>     return null or void;
>  } else {
>     continuation.getStack().popLocalVariables();
>     continuation.getStack().popOperandStack();
>     continuation.getStack().popLastProcessCounter();
>  }
>
>  [...]
>}
>
>Yes, this has the benefit to call "uninstrumented" code, but
>the complete frame must be captured and restored for every invocation.
>
>  
>
See my second message regarding this.

>>The user interface to this might look something like this:
>>
>>public class Continuation {
>>        // Empty continuation for use as an escape procedure
>>        public static final Continuation SUICIDE;
>>    
>>
>
>I didn't get the role of SUICIDE.
>
>  
>
>>        // Invoke a captured continuation - it will replace the current 
>>continuation. I.e. the current JVM call stack will be unwound, the call 
>>stack saved in this object will be recreated on the JVM call stack, and 
>>the method invocation in which this object was created will return with 
>>"returnValue".
>>        public void invoke(Object returnValue);
>>    
>>
>
>Do you want to use the "returnValue" to return the WebContinuation in
>sendPageAndWait() ? The problem I see is that you suspend the thread
>at a method invocation not at the end of the method.
>
>  
>
>>        // Get the current continuation -
>>        public static Continuation getCurrentContinuation();
>>        // Entry point to the instrumented code (precondition: cannot be 
>>called recursively and method.getDeclaringClass() must be instrumented)
>>        public static Object invoke(Object obj, Method method, Object[] 
>>args);
>>}
>>    
>>
>
>Why don't use (Object obj, Method method, Object[] args) in the
>constructor of the continuation object.
>
>  
>
That's a possible alternative, but makes prevents making Continuation an 
abstract class.

>Continuation.SUICIDE.invoke(null); ?
>
>*you see many question marks over my head*
>
>I hope you have patience with me :)
>
>  
>
The idea of SUICIDE is that it has the effect of unwinding the stack but 
not executing any further code and directly returns to the entry point 
(i.e. it is the continuation of the end of some code ). For example (in JS):

var suicide;

function f() {
   suicide = arguments.continuation;
}

f();  // <== since there's no code to execute after f(), invoking 
suicide later will have the effect of simply terminating the script.
// end of script


In the current Rhino implementation creating a Continuation in a 
top-level script has the same effect (since what comes after the end of 
the script is - nothing).

This behavior is as in Scheme.

Chris

Scheme Continuations vs Brakes Continuations was Re: Groovy support in Cocoon

Posted by Stephan Michels <st...@apache.org>.
First, I'm glad to hear more input ;-) Your mail took some time
to parse it.

Am Mo, den 05.04.2004 schrieb Christopher Oliver um 18:47:
> OK, IIUC there are three modes of execution of the instrumented code:
> 
> 1) isCapturing
> During this mode the JVM call stack is unwound and its state captured in 
> the continuation call stack.
> 2) isRestoring
> During this mode a saved call stack in a continuation is recreated on 
> the JVM stack.
> 3) !isCapturing && !isRestoring
> This is the "normal" execution of the JVM  - no modifications are made 
> to the JVM call stack or to the continuation call stack.

Correct.

> This is achieved by inserting code before each invoke instruction to 
> copy local variables from the continuation stack to the JVM stack and to 
> reset the program counter to the value saved in the continuation stack 
> if "isRestoring" is true, and by inserting code after each invoke 
> instruction to copy the values of local variables from the JVM call 
> stack as well as the program counter into the continuation call stack if 
> "isCapturing" is true.

Yes, but the code for the restore procedure is at the begining of the
method not the before the invocation, but anyway..

I need some pseudo code for myself ;-) Current situation:

void myFlow() {
  if (continuation.isRestoring()) {
     continuation.getStack().popLocalVariables();
     continuation.getStack().popOperandStack();
     continuation.getStack().popReference(); // used for the  
                                        //method invocation
     push(null) as many null object as the method invovation need for 
                the parameters
     goto continuation.getStack().popLastProcessCounter();
  }

  [...]

label 1:
  invoke MySubFlow.bla();

  if (continuation.isCapturing() {
     remove the return value (is unimportant)
     continuation.getStack().pushLocalVariables();
     continuation.getStack().pushOperandStack();
     continuation.getStack().pushLastProcessCounter(label 1);
     continuation.getStack().pushReference(this);
     return null or void;
  }

  [...]
}

> To make continuations more "Scheme-like" it must be possible to 
> construct a continuation without modifying the JVM call stack (thus the 
> current method invocation can "continue as normal").
> 
> To make this possible the byte-code transformer could work like this:
> 1) Insert code before an invoke instruction to push local vars and the 
> pc onto the continuation stack if (!isRestoring && !isCapturing)
> 2) Insert code after an invoke instruction to pop those values from the 
> continuation stack if (!isRestoring && !isCapturing)
> 3) If (isRestoring == true) the pre-invoke code would work as it does now.
> 4) If (isCapturing == true) the post-invoke code would simply cause the 
> current method invocation to return to its caller without modifying the 
> continuation stack - since it is already set up from (1). When the JVM 
> stack is completely unwound another continuation will take the place of 
> this one and that new continuation would be in "isRestoring" mode until 
> it is recreated on the JVM stack at which point it would enter 
> (!isRestoring && !isCapturing) mode.

Okay to recapitulate IIUC. Your proposal:

void myFlow() {
  if (continuation.isRestoring()) {
     continuation.getStack().popLocalVariables();
     continuation.getStack().popOperandStack();
     goto continuation.getStack().popLastProcessCounter();
  }

  [...]

  continuation.getStack().pushLocalVariables();
  continuation.getStack().pushOperandStack();
  continuation.getStack().pushLastProcessCounter(label 1);

label 1:
  invoke MySubFlow.bla();

  if (continuation.isCapturing() {
     return null or void;
  } else {
     continuation.getStack().popLocalVariables();
     continuation.getStack().popOperandStack();
     continuation.getStack().popLastProcessCounter();
  }

  [...]
}

Yes, this has the benefit to call "uninstrumented" code, but
the complete frame must be captured and restored for every invocation.

> The user interface to this might look something like this:
> 
> public class Continuation {
>         // Empty continuation for use as an escape procedure
>         public static final Continuation SUICIDE;

I didn't get the role of SUICIDE.

>         // Invoke a captured continuation - it will replace the current 
> continuation. I.e. the current JVM call stack will be unwound, the call 
> stack saved in this object will be recreated on the JVM call stack, and 
> the method invocation in which this object was created will return with 
> "returnValue".
>         public void invoke(Object returnValue);

Do you want to use the "returnValue" to return the WebContinuation in
sendPageAndWait() ? The problem I see is that you suspend the thread
at a method invocation not at the end of the method.

>         // Get the current continuation -
>         public static Continuation getCurrentContinuation();
>         // Entry point to the instrumented code (precondition: cannot be 
> called recursively and method.getDeclaringClass() must be instrumented)
>         public static Object invoke(Object obj, Method method, Object[] 
> args);
> }

Why don't use (Object obj, Method method, Object[] args) in the
constructor of the continuation object.

Something like that:

// Start continuation
Continuation c = new Continuation(Object obj, Method method, Object[]
args)
c.invoke();

if (c.isSusended()) {
  // Continue the continuation
  c = new Continuation(c);
  c.continue();
}


> public class Cocoon {
>      // ...
>      public WebContinuation sendPageAndWait(String uri, Object biz, long 
> ttl) {
>               Continuation kont = Continuation.getCurrentContinuation();
>               WebContinuation wk = 
> continuationsMgr.createWebContinuation(kont,
>                                            parentWebContinuation,
>                                            ttl,
>                                            null);
>                sendPage(uri, biz);
>                Continuation.SUICIDE.invoke(null);
>                return wk; // never reached
>      }

Continuation.SUICIDE.invoke(null); ?

*you see many question marks over my head*

I hope you have patience with me :)

Stephan Michels.


Re: Groovy support in Cocoon

Posted by Christopher Oliver <re...@verizon.net>.
Stephan Michels wrote:

>Am Mo, den 05.04.2004 schrieb Christopher Oliver um 4:42:
>  
>
>>The current implementation needs some work to qualify as "generalized 
>>Java continuations". It would be nice to make it work more like Scheme 
>>continuations:
>>
>>1) When you access the "current" continuation, it captures the call 
>>stack up to but not including the current method (and makes a (shallow) 
>>copy of it). The current method continues as normal. 
>>    
>>
>
>What to you mean with "continues as normal". The current impl. stops the
>execution of the method with null as return value, if the cuntinuation
>is suspended. Then the continuation captures the object of the method
>call and the current frame.
>  
>
OK, IIUC there are three modes of execution of the instrumented code:

1) isCapturing
During this mode the JVM call stack is unwound and its state captured in 
the continuation call stack.
2) isRestoring
During this mode a saved call stack in a continuation is recreated on 
the JVM stack.
3) !isCapturing && !isRestoring
This is the "normal" execution of the JVM  - no modifications are made 
to the JVM call stack or to the continuation call stack.

This is achieved by inserting code before each invoke instruction to 
copy local variables from the continuation stack to the JVM stack and to 
reset the program counter to the value saved in the continuation stack 
if "isRestoring" is true, and by inserting code after each invoke 
instruction to copy the values of local variables from the JVM call 
stack as well as the program counter into the continuation call stack if 
"isCapturing" is true.

To make continuations more "Scheme-like" it must be possible to 
construct a continuation without modifying the JVM call stack (thus the 
current method invocation can "continue as normal").

To make this possible the byte-code transformer could work like this:

1) Insert code before an invoke instruction to push local vars and the 
pc onto the continuation stack if (!isRestoring && !isCapturing)
2) Insert code after an invoke instruction to pop those values from the 
continuation stack if (!isRestoring && !isCapturing)
3) If (isRestoring == true) the pre-invoke code would work as it does now.
4) If (isCapturing == true) the post-invoke code would simply cause the 
current method invocation to return to its caller without modifying the 
continuation stack - since it is already set up from (1). When the JVM 
stack is completely unwound another continuation will take the place of 
this one and that new continuation would be in "isRestoring" mode until 
it is recreated on the JVM stack at which point it would enter 
(!isRestoring && !isCapturing) mode.

The user interface to this might look something like this:

public class Continuation {
        // Empty continuation for use as an escape procedure
        public static final Continuation SUICIDE;

        // Invoke a captured continuation - it will replace the current 
continuation. I.e. the current JVM call stack will be unwound, the call 
stack saved in this object will be recreated on the JVM call stack, and 
the method invocation in which this object was created will return with 
"returnValue".
        public void invoke(Object returnValue);
        // Get the current continuation -
        public static Continuation getCurrentContinuation();
        // Entry point to the instrumented code (precondition: cannot be 
called recursively and method.getDeclaringClass() must be instrumented)
        public static Object invoke(Object obj, Method method, Object[] 
args);
}


Below is some pseudo-code that shows how this would work with Cocoon:

public class JavaInterpreter {
        // ...
        public void callFunction(String function, List params, 
Redirector redirector)
            throws Exception {
            if (!initialized)
                initialize();

            Method method = (Method) methods.get(function);
            Request request = ContextHelper.getRequest(this.avalonContext);
            Session session = request.getSession(true);
            HashMap userScopes = (HashMap) 
session.getAttribute(USER_GLOBAL_SCOPE);
            if (userScopes == null)
               userScopes = new HashMap();

            Object flow = (Object) 
userScopes.get(method.getDeclaringClass());

            if (flow == null) {
                if (getLogger().isDebugEnabled())
                   getLogger().debug("create new instance of 
\""+method.getDeclaringClass()+"\"");

            flow =  method.getDeclaringClass().newInstance();
            userScopes.put(method.getDeclaringClass(), flow);
            int size = params == null ? 0 : params.size();
            Object[] args = new Object[size];
            for (int i = 0; i < size; i++) {
                    Interpreter.Argument arg = 
(Interpreter.Argument)params.get(i);
                    args[i] = arg.value;
            }
            Continuation.invoke(flow, method, args);
        }

        public void handleContinuation(String id, List params, 
Redirector redirector)
            throws Exception {
            if (!initialized)
                initialize();

            WebContinuation wk = continuationsMgr.lookupWebContinuation(id);
            Continuation k = (Continuation) wk.getContinuation();
             k.invoke(wk);
         }

}

public class Cocoon {
     // ...
     public WebContinuation sendPageAndWait(String uri, Object biz, long 
ttl) {
              Continuation kont = Continuation.getCurrentContinuation();
              WebContinuation wk = 
continuationsMgr.createWebContinuation(kont,
                                           parentWebContinuation,
                                           ttl,
                                           null);
               sendPage(uri, biz);
               Continuation.SUICIDE.invoke(null);
               return wk; // never reached
     }

      public void sendPage(String uri, Object biz) {
           // ...
      }
}


Chris

Re: Groovy support in Cocoon

Posted by Stephan Michels <st...@apache.org>.
Am Mo, den 05.04.2004 schrieb Christopher Oliver um 4:42:
> The current implementation needs some work to qualify as "generalized 
> Java continuations". It would be nice to make it work more like Scheme 
> continuations:
> 
> 1) When you access the "current" continuation, it captures the call 
> stack up to but not including the current method (and makes a (shallow) 
> copy of it). The current method continues as normal. 

What to you mean with "continues as normal". The current impl. stops the
execution of the method with null as return value, if the cuntinuation
is suspended. Then the continuation captures the object of the method
call and the current frame.

> The reason for 
> making a copy is to prevent further modification of the captured 
> continuation stack as the method call stack unwinds (see below).
> 2) To resume a continuation you invoke it - like a method call through 
> reflection - and you can pass an object to this call (which becomes the 
> return value of the method where the continuation was created).

Yes, but you need all the objects of every stack trace elements to
restore the stack trace. Not only the last one.

> 3) Before the continuation is resumed another copy of the stack is made 
> (the original continuation stack is treated as an immutable object). 
> This makes it possible to invoke the continuation more than once.

Yes.

> It's possible to make the stack copying occur lazily as an optimization 
> (in case another continuation is invoked the method at the top of the 
> stack never returns so copying the remaining frames isn't necessary).

? Sorry, I didn't get it :-/

Can you elaborate this a bit more, how you want to make work like in
Scheme?


Re: Groovy support in Cocoon

Posted by Christopher Oliver <re...@verizon.net>.
The current implementation needs some work to qualify as "generalized 
Java continuations". It would be nice to make it work more like Scheme 
continuations:

1) When you access the "current" continuation, it captures the call 
stack up to but not including the current method (and makes a (shallow) 
copy of it). The current method continues as normal. The reason for 
making a copy is to prevent further modification of the captured 
continuation stack as the method call stack unwinds (see below).
2) To resume a continuation you invoke it - like a method call through 
reflection - and you can pass an object to this call (which becomes the 
return value of the method where the continuation was created).
3) Before the continuation is resumed another copy of the stack is made 
(the original continuation stack is treated as an immutable object). 
This makes it possible to invoke the continuation more than once.

It's possible to make the stack copying occur lazily as an optimization 
(in case another continuation is invoked the method at the top of the 
stack never returns so copying the remaining frames isn't necessary).

Chris

Brian McCallister wrote:

> I will be surprised if continuations based around the Cocoon javaflow  
> implementation don't leak into Groovy CVS based on the amount of  
> chatter in #groovy about continuations.
>
> I know James wants this very much, and hacked out a way to do it via  
> exceptions once (and hacked is the correct word), but has been 
> waiting  for generalized Java continuations rather than hack it into 
> the  language.
>
> -Brian
>
> On Apr 4, 2004, at 2:32 PM, Christopher Oliver wrote:
>
>> Stefano Mazzocchi wrote:
>>
>>> Antonio Gallardo wrote:
>>>
>>>> Hi:
>>>>
>>>> Hi:
>>>>
>>>> Some of us wanted to see Groovy support in Cocoon. Now we can 
>>>> "play"  a
>>>> little with Groovy using the recently added support for Groovy script
>>>> generator under the BSF block. More info about how to use it is here:
>>>>
>>>> http://cocoon.apache.org/2.1/userdocs/generators/script- 
>>>> generator.html
>>>>
>>>> SITEMAP CONFIGURATION FOR GROOVY:
>>>> ======================
>>>>
>>>> In components section add:
>>>>
>>>> <map:generator name="script"
>>>>     src="org.apache.cocoon.generation.ScriptGenerator"
>>>>     logger="sitemap.generation.scriptgenerator">
>>>>   <!-- Groovy support -->
>>>>   <add-languages>
>>>>     <language name="groovy"  
>>>> src="org.codehaus.groovy.bsf.GroovyEngine">
>>>>       <extension>groovy</extension>
>>>>       <extension>gy</extension>
>>>>     </language>
>>>>   </add-languages>
>>>> </map:generator>
>>>>
>>>> I hope this will have a good welcome in the Cocoon Community.
>>>>
>>>> Best Regards,
>>>>
>>>> Antonio Gallardo
>>>>
>>>
>>> Next I would like to see is a groovy implementation of flow ;-)
>>>
>> It should be _fairly_ straightforward. The only tricky part I see is  
>> controlling the byte-code transformation. All methods in the  
>> call-chain leading from the method invoked by  
>> Interpreter.callFunction()  to sendPageAndWait() or any other method  
>> that creates a continuation must be instrumented. The current  
>> implementation only instruments classes that implement the interface  
>> "Continuable". In the case of scripting languages like Groovy, 
>> Jython,  or Rhino, pretty much the entire interpreter and all classes 
>> generated  from scripts will need to be instrumented. Any callbacks 
>> from  non-instrumented code to instrumented code will break the  
>> continuation.
>>
>> One approach might be to instrument the build system to rename class  
>> files that require instrumentation to have a special extension  
>> (".iclass" or whatever) making them invisible to normal class 
>> loaders  but recognizable to the class loader that performs the 
>> byte-code  transformation.
>>
>> Another possible approach is to provide a configuration to the class  
>> loader using wildcard specifications (e.g. "groovy.*", etc) to allow  
>> it to identify which classes to instrument.
>>
>> Chris
>>
>
>
>
>


Re: Groovy support in Cocoon

Posted by Antonio Gallardo <ag...@agssa.net>.
Brian McCallister dijo:
> I will be surprised if continuations based around the Cocoon javaflow
> implementation don't leak into Groovy CVS based on the amount of
> chatter in #groovy about continuations.
>
> I know James wants this very much, and hacked out a way to do it via
> exceptions once (and hacked is the correct word), but has been waiting
> for generalized Java continuations rather than hack it into the
> language.

Glad to hear that!

When the continuation will be part of the standard libs or language in
Groovy and/or Java, then we can refactor the current continuation code in
Cocoon. Until then we need to find our own way. Is this OK?

Best Regards,

Antonio Gallardo


Re: Groovy support in Cocoon

Posted by Brian McCallister <br...@apache.org>.
I will be surprised if continuations based around the Cocoon javaflow  
implementation don't leak into Groovy CVS based on the amount of  
chatter in #groovy about continuations.

I know James wants this very much, and hacked out a way to do it via  
exceptions once (and hacked is the correct word), but has been waiting  
for generalized Java continuations rather than hack it into the  
language.

-Brian

On Apr 4, 2004, at 2:32 PM, Christopher Oliver wrote:

> Stefano Mazzocchi wrote:
>
>> Antonio Gallardo wrote:
>>
>>> Hi:
>>>
>>> Hi:
>>>
>>> Some of us wanted to see Groovy support in Cocoon. Now we can "play"  
>>> a
>>> little with Groovy using the recently added support for Groovy script
>>> generator under the BSF block. More info about how to use it is here:
>>>
>>> http://cocoon.apache.org/2.1/userdocs/generators/script- 
>>> generator.html
>>>
>>> SITEMAP CONFIGURATION FOR GROOVY:
>>> ======================
>>>
>>> In components section add:
>>>
>>> <map:generator name="script"
>>>     src="org.apache.cocoon.generation.ScriptGenerator"
>>>     logger="sitemap.generation.scriptgenerator">
>>>   <!-- Groovy support -->
>>>   <add-languages>
>>>     <language name="groovy"  
>>> src="org.codehaus.groovy.bsf.GroovyEngine">
>>>       <extension>groovy</extension>
>>>       <extension>gy</extension>
>>>     </language>
>>>   </add-languages>
>>> </map:generator>
>>>
>>> I hope this will have a good welcome in the Cocoon Community.
>>>
>>> Best Regards,
>>>
>>> Antonio Gallardo
>>>
>>
>> Next I would like to see is a groovy implementation of flow ;-)
>>
> It should be _fairly_ straightforward. The only tricky part I see is  
> controlling the byte-code transformation. All methods in the  
> call-chain leading from the method invoked by  
> Interpreter.callFunction()  to sendPageAndWait() or any other method  
> that creates a continuation must be instrumented. The current  
> implementation only instruments classes that implement the interface  
> "Continuable". In the case of scripting languages like Groovy, Jython,  
> or Rhino, pretty much the entire interpreter and all classes generated  
> from scripts will need to be instrumented. Any callbacks from  
> non-instrumented code to instrumented code will break the  
> continuation.
>
> One approach might be to instrument the build system to rename class  
> files that require instrumentation to have a special extension  
> (".iclass" or whatever) making them invisible to normal class loaders  
> but recognizable to the class loader that performs the byte-code  
> transformation.
>
> Another possible approach is to provide a configuration to the class  
> loader using wildcard specifications (e.g. "groovy.*", etc) to allow  
> it to identify which classes to instrument.
>
> Chris
>




Re: Groovy support in Cocoon

Posted by Christopher Oliver <re...@verizon.net>.
Stefano Mazzocchi wrote:

> Antonio Gallardo wrote:
>
>> Hi:
>>
>> Hi:
>>
>> Some of us wanted to see Groovy support in Cocoon. Now we can "play" a
>> little with Groovy using the recently added support for Groovy script
>> generator under the BSF block. More info about how to use it is here:
>>
>> http://cocoon.apache.org/2.1/userdocs/generators/script-generator.html
>>
>> SITEMAP CONFIGURATION FOR GROOVY:
>> ======================
>>
>> In components section add:
>>
>> <map:generator name="script"
>>     src="org.apache.cocoon.generation.ScriptGenerator"
>>     logger="sitemap.generation.scriptgenerator">
>>   <!-- Groovy support -->
>>   <add-languages>
>>     <language name="groovy" src="org.codehaus.groovy.bsf.GroovyEngine">
>>       <extension>groovy</extension>
>>       <extension>gy</extension>
>>     </language>
>>   </add-languages>
>> </map:generator>
>>
>> I hope this will have a good welcome in the Cocoon Community.
>>
>> Best Regards,
>>
>> Antonio Gallardo
>>
>
> Next I would like to see is a groovy implementation of flow ;-)
>
It should be _fairly_ straightforward. The only tricky part I see is 
controlling the byte-code transformation. All methods in the call-chain 
leading from the method invoked by Interpreter.callFunction()  to 
sendPageAndWait() or any other method that creates a continuation must 
be instrumented. The current implementation only instruments classes 
that implement the interface "Continuable". In the case of scripting 
languages like Groovy, Jython, or Rhino, pretty much the entire 
interpreter and all classes generated from scripts will need to be 
instrumented. Any callbacks from non-instrumented code to instrumented 
code will break the continuation.

One approach might be to instrument the build system to rename class 
files that require instrumentation to have a special extension 
(".iclass" or whatever) making them invisible to normal class loaders 
but recognizable to the class loader that performs the byte-code 
transformation.

Another possible approach is to provide a configuration to the class 
loader using wildcard specifications (e.g. "groovy.*", etc) to allow it 
to identify which classes to instrument.

Chris 

Re: Groovy support in Cocoon

Posted by Antonio Gallardo <ag...@agssa.net>.
Stefano Mazzocchi dijo:
> Next I would like to see is a groovy implementation of flow ;-)

Wait a few hours. I will try to make it work now....

Best Regards,

Antonio Gallardo

Re: Groovy support in Cocoon

Posted by Stefano Mazzocchi <st...@apache.org>.
Antonio Gallardo wrote:

> Hi:
> 
> Hi:
> 
> Some of us wanted to see Groovy support in Cocoon. Now we can "play" a
> little with Groovy using the recently added support for Groovy script
> generator under the BSF block. More info about how to use it is here:
> 
> http://cocoon.apache.org/2.1/userdocs/generators/script-generator.html
> 
> SITEMAP CONFIGURATION FOR GROOVY:
> ======================
> 
> In components section add:
> 
> <map:generator name="script"
>     src="org.apache.cocoon.generation.ScriptGenerator"
>     logger="sitemap.generation.scriptgenerator">
>   <!-- Groovy support -->
>   <add-languages>
>     <language name="groovy" src="org.codehaus.groovy.bsf.GroovyEngine">
>       <extension>groovy</extension>
>       <extension>gy</extension>
>     </language>
>   </add-languages>
> </map:generator>
> 
> I hope this will have a good welcome in the Cocoon Community.
> 
> Best Regards,
> 
> Antonio Gallardo
> 

Next I would like to see is a groovy implementation of flow ;-)

-- 
Stefano.


Re: Groovy support in Cocoon (the future)

Posted by Antonio Gallardo <ag...@agssa.net>.
Tim Larson dijo:
> On Sat, Apr 03, 2004 at 10:45:49PM -0600, Antonio Gallardo wrote:
>> Some of us wanted to see Groovy support in Cocoon. Now we can "play" a
>> little with Groovy using the recently added support for Groovy script
>> generator under the BSF block. More info about how to use it is here:
> <snip/>
>> I hope this will have a good welcome in the Cocoon Community.
>
> As promised, here is your virtual tall glass of crystal-clear distilled
> mountain water.  I only filled it one third full, since we still need
> to figure out how to use this as an experiment flowscript engine and as
> an experimental way of writing Cocoon block code such as for CForms ;^)

Hi Tim:

Thanks, I think it is too much reward for almost nothing work! :-D

In fact I just added some libs, changed a little the BSF code (there was a
bug) and a dumb sample. That is almost nothing.

Groovy Actions
==============

This would be easy, in fact the support is already there. We just need to
make sure the BSF script action can work with Groovy. I am 99% sure this
will be as a picnic.

Groovy XSP support?
===================

Given the fact there exist Java and Javascript support for XSP, maybe we
can also add support for Groovy. I an not sure if this is good idea, since
XSP is no more interesting to us. Need we extended the life of XSP? ;-)

Groovy script tranformers?
==========================

Given the fact that Groovy can parse and emit SAX2 events. I wonder if
this will be a great "+" for Cocoon.

Another related concern is if we need to use the current BSF. Groovy is
able to generate directly SAX2 events. Currently, we are returning a XML
content inside a StringBuffer (see the output variable in
o.a.c.generation.ScriptGenerator.generate()). Maybe we can refactor the
current generator and "detect" if the script can send SAX2 events or not.
No sure, but we must look at it too.

Also I tought about a using Groovy script generator for dynamic list for
CForms. Just call the generator that retrieve data from a SQL connection,
format it and send the SAX2 events. How this sound?

Groovy Flow Engine
==================

The final dream! The idea is to create yet another Flow Engine using
Groovy. This will be a killer since we can got the best of both worlds:
The simplicity of Javascript with a better integration with Java.

Other Improvement
=================

Another fact is Groovy RI is currently using asm.jar and we can reach the
same using Apache BCEL project. The reason behind the asm.jar usage is
that it is far more smaller than bcel.jar. But giving the fact we are
actually using bcel inside the code, will be fine to refactor the current
Groovy RI to use bcel.jar.

Also, seems I think we can improve the performance of the BSF block.

Integration with Cocoon
=======================

In a future, i will be glad to be able write some parts of Cocoon using
Groovy. Since Groovy can be compiled to Java bytecode. I think this can be
done just integrating in the Cocoon build system support for Groovy. In
this area there is already Ant support for compiling Groovy code:
http://groovy.codehaus.org/compiling.html

WDYT?

Best Regards,

Antonio Gallardo


Re: Groovy support in Cocoon

Posted by Tim Larson <ti...@keow.org>.
On Sat, Apr 03, 2004 at 10:45:49PM -0600, Antonio Gallardo wrote:
> Some of us wanted to see Groovy support in Cocoon. Now we can "play" a
> little with Groovy using the recently added support for Groovy script
> generator under the BSF block. More info about how to use it is here:
<snip/>
> I hope this will have a good welcome in the Cocoon Community.

As promised, here is your virtual tall glass of crystal-clear distilled
mountain water.  I only filled it one third full, since we still need
to figure out how to use this as an experiment flowscript engine and as
an experimental way of writing Cocoon block code such as for CForms ;^)

--Tim Larson