You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tapestry.apache.org by Geoff Longman <gl...@gmail.com> on 2006/02/27 14:50:34 UTC

[T5] Render queue and mixins

Howard,

You described a rendering queue and mixins recently.

Frankly I don't understand what you are getting at.

Care to elaborate? Thanks.

Geoff

--
The Spindle guy.          http://spindle.sf.net
Get help with Spindle:   
http://lists.sourceforge.net/mailman/listinfo/spindle-user
Blog:                     http://jroller.com/page/glongman
Feature Updates:          http://spindle.sf.net/updates

---------------------------------------------------------------------
To unsubscribe, e-mail: tapestry-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: tapestry-dev-help@jakarta.apache.org


Re: [T5] Render queue and mixins

Posted by Howard Lewis Ship <hl...@gmail.com>.
It's very aspect oriented; the join points are described by the
annotated methods which match up against transitions within the state
machine.

Now, I'm sitting in a hotel room in SF, coughing my guts out (really
bad cold!) so I can't elaborate properly.

To make it easier to visualize; pretend that all components and mixins
implemented this specific interface that had lots of methods like
beforeRender(), afterRender(), beforeRenderBody(), afterRenderBody()
etc.

Now, if the components and the mixins implement these interfaces, its
the Chain of Command Pattern. So, when you are transitioning from the
"before render" state to the "render template" state, you invoke the
beforeRender() method on each object (the component and any mixins). 
The order may matter, but I don't have all the details for that!

A lot of the times, the implementation of the method will be empty (do
nothing). That's ok.

As I see it, the implementation is remarkably like this!  The class
loader will scan the class for the annotations, and make the
component/mixin implement an (internal, invisible to the application
developer) interface, and set things up within the component to invoke
methods on those classes, after casting them to the interface.

How far you can bend a component's behavior by mixins will be defined
by how good a state machine we can devise.

On 2/27/06, Geoff Longman <gl...@gmail.com> wrote:
> So am I on the right track in saying that Jesse could "mix into" Form
> the abililty to submit via an XMLHttpRequest? (I'm sure Jesse would
> *love* that!).
>
> You can morph the behaviour of some else's component.
>
> And the mechanism for acomplishing this would be annotations. How
> would you annotate a class that you could potentially have never seen
> the source for? Do I annotate things in the page class as the point
> where an @Component annotation would be?
>
> Geoff
>
>
>
> On 2/27/06, Howard Lewis Ship <hl...@gmail.com> wrote:
> > In Tapestry 4, we define a component as a class that (primarily) can
> > render itself.
> >
> > Control over its output, including rendering its body and template,
> > are all encapsulated within a single method, renderComponent().
> >
> > This is a good start.
> >
> > However, for Tapestry 5, the definition gets more complex.
> >
> > Outputing the component's tag(s), attribute(s), template and body are
> > all different operations.  A state machine defines the steps and the
> > progression from one step to the next.
> >
> > These operations are represented as methods on the peer (*) class. The
> > lifecycle methods are marked with annotations that indicate when they
> > will be invoked.
> >
> > In my vision of T5, a "mixin" is a kind of partial component that is
> > "attached" to a ordinary component. It also contains parameters and
> > lifecycle methods. The component will invoke appropriate methods on
> > both the peer class and any mixin classes.
> >
> > The mixin may be part of a component's base implementation, or it may
> > be applied to a particular usage of a component.
> >
> > So, think of Tapestry 4's validators parameter. This could be thought
> > of as a mixin; it adds render-time behavior (generating JavaScript for
> > client-side validation) and adds submit-time behavior (enforcing a
> > contraint).
> >
> > With an appropriately rich state machine, and set of lifecycle methods
> > and annotations, it should not be necessary to to have a validators
> > parameter, just validator mixins.
> >
> > Other examples jump to mind: mixins that define security contraints or
> > transactional boundaries for a link or form.
> >
> > The question is the timing; in what order are the methods of the peer
> > and the mixin(s) executed, how are the results determined, how can the
> > order by defined.
> >
> >
> > (*) I'm open to better names for this.  ComponentBean?  Codebehind?
> >
> > On 2/27/06, Jesse Kuhnert <jk...@gmail.com> wrote:
> > > Only because howard might be stuck on a long flight or otherwise indisposed,
> > > I'll try another crack at it.
> > >
> > > You could probably think of mixins as having the ability to do multiple
> > > inheritance in java. The only difference being that we're moving away from
> > > interfaces/subclassing to more of a composition sort of pattern.
> > >
> > > For instance..The tacos logic that enhances all components via javassist
> > > does a few things to component classes.
> > >
> > > - ) Adds an injected hivemind service reference to the AjaxWebRequest.
> > >
> > > -) Extends the renderComponent() method to do some checks on whether or not
> > > the component should be renderd. (if requested in the ajax request, or if
> > > it's even a valid ajax request).
> > >
> > > This is all done more or less manually, using the javassist API through
> > > howards render enhancement stuff. So, instead of all this fun logic being
> > > defined in a nice easily testable class, it's mostly manually written java
> > > code inside of string blocks..ie:
> > >
> > > StringBuffer renderComponent = new StringBuffer("if (ajaxRequest) {
> > > dothisThing(); } ");
> > >
> > > It's a little more complicated than that, but that's the basic premise. It's
> > > an ok thing to do for internal API's, but isn't friendly to testing or more
> > > regular uses overall..
> > >
> > > The most ideal way to do it would instead be able to define what this actual
> > > class would look like in a real java class...We could have something like
> > > this:
> > >
> > > public class AjaxRenderEnhancement {
> > >           AjaxWebRequest ajaxRequest;
> > >
> > >           //normal hivemind injected service
> > >           public void setAjaxRequest(AjaxWebRequest ....);
> > >
> > >
> > >           public void renderComponent(IComponent component, IMarkupWriter
> > > writer, IRequestCycle cycle) {
> > >                if (ajaxRequest.isAjaxRequest()) {
> > >                      component.renderComponent(writer, cycle);
> > >                 }
> > >               else return;
> > >           }
> > > }
> > >
> > > This is more or less the end result of what all the ajax enhancement stuff
> > > would create. Now someone could take this code, which by itself can't do
> > > anything, and "mix it" in with the component I want to enhance...Like a
> > > PropertySelection component, or whatever you want. The AjaxWebRequest would
> > > be made a member of the PropertySelection class, and the renderComponent
> > > method would be added as well. (Signature is different).
> > >
> > > I don't actually know how he's going to implement it, so there are a lot of
> > > very large flaws I've written up...But that is my understanding of it.
> > >
> > > C# supports this construct as well..So does javascript. That's how dojo
> > > provides "super" class sort of functionality. There is a method
> > > dojo.lang.mixin() that gets called to merge two javascript object
> > > definitions together. Of course that language is much more dynamic, so it's
> > > perfectly legal to do something like this:
> > >
> > > function validateInput(inputField) {
> > >      if (!inputField.value) //validate
> > > }
> > >
> > > var myObject = new Object();
> > >
> > > At this point my "myObject" object isn't really capable of doing
> > > anything..But now we can do this:
> > >
> > > myObject.validateInput = validateInput;
> > >
> > > and then call:
> > >
> > > myObject.validateInput(document.getElementById("foo"));
> > >
> > > I'll leave the rendering queue to Howard as there are too many possibilities
> > > for me to try imagining...
> > >
> > >
> > > On 2/27/06, Geoff Longman < glongman@gmail.com> wrote:
> > > >
> > > > On 2/27/06, Jesse Kuhnert < jkuhnert@gmail.com> wrote:
> > > > <snip!>
> > > > >
> > > > > It can probably get a ~lot~ more dynamic and graceful than that, but the
> > > > > basic premise I think is that he'd be going in and automagically
> > > > connecting
> > > > > all of these things for you..Instead of having to manually specify a lot
> > > > of
> > > > > logic all over the place. The same would hold true for a lot of other
> > > > things
> > > > > as well I'm guessing.
> > > >
> > > > ok, without knowing if Howard's intent matches your description I'd be
> > > > loathe to call this mixins. Looks more like auto-wiring to me.
> > > >
> > > > Enhancement today adds methods and fields to the public interface of a
> > > > 'base' class but unless that added interface is there in the base
> > > > class (abstract method decl) then the added 'stuff' is visible only to
> > > > reflection based mechanisms (ognl as one example) and then only
> > > > because Tapestry does a little "bait & switch" by substituting the
> > > > enhanced class for the original one at runtime.
> > > >
> > > > But the following makes me doubt that autowire is all there is:
> > > >
> > > > >You will put your pages under com.example.root.pages and your
> > > > >component under com.example.root.components.  Further, you will put
> > > > >your mixins under com.examples.root.mixins.
> > > >
> > > > So a mixin appears to be a class - a class containing what?
> > > >
> > > > >
> > > > > rendering queue - Again, no idea what's actually in his head, but my
> > > > > layman's notion of it was that this would more or less be addressing the
> > > > > issue of not knowing about something until you get to it, and then more
> > > > or
> > > > > less it being too late to do something smarter by the time you've gotten
> > > > > there..
> > > >
> > > > ok. (and I'm not bashing you Jesse) how will this be accomplished?
> > > >
> > > > >
> > > > > This would enable css to be globally contributed into the Shell for
> > > > example.
> > > > > So, we know how the Form does the rewind cycles...It passes in a null
> > > > writer
> > > > > that basically still does the entire render, it just doesn't output
> > > > > anything..I think in this scenerio he would completely break out the
> > > > logic
> > > > > of rendering from the logic that sort of "moves the cycle forward".
> > > > ..Making
> > > > > it very very efficient to do the form rewind sort of logic if the actual
> > > > > rendering is made into a seperate thing.
> > > >
> > > > That's a goal worth persuing. I still don't get it though. (boy I feel
> > > > dumb today).
> > > >
> > > > >
> > > > > This would also make about 10 billion other things much better. Like
> > > > direct
> > > > > component renders, etc....
> > > > >
> > > > > That's a layman's view on it though. I'm sure there is more too it but I
> > > > > think that is the overall ~reason~ for the queue, even if not what the
> > > > > actual details would contain.
> > > >
> > > > I think I'm just lacking a clear explanation.
> > > >
> > > > It worries me that even though I have been using Tapestry for many
> > > > years this new stuff is sailing right over my head.
> > > >
> > > > Perhaps I'm too tied to java and static thinking. The closest I've
> > > > been to a dynamic language is ruby. and not really even that as the
> > > > closest I've been to ruby is the word "ruby" - a stone in one of my
> > > > mother's rings!
> > > >
> > > > Geoff
> > > >
> > > > --
> > > > The Spindle guy.          http://spindle.sf.net
> > > > Get help with Spindle:
> > > > http://lists.sourceforge.net/mailman/listinfo/spindle-user
> > > > Blog:                     http://jroller.com/page/glongman
> > > > Feature Updates:          http://spindle.sf.net/updates
> > > >
> > > > ---------------------------------------------------------------------
> > > > To unsubscribe, e-mail: tapestry-dev-unsubscribe@jakarta.apache.org
> > > > For additional commands, e-mail: tapestry-dev-help@jakarta.apache.org
> > > >
> > > >
> > >
> > >
> >
> >
> > --
> > Howard M. Lewis Ship
> > Independent J2EE / Open-Source Java Consultant
> > Creator, Jakarta Tapestry
> > Creator, Jakarta HiveMind
> >
> > Professional Tapestry training, mentoring, support
> > and project work.  http://howardlewisship.com
> >
> > ---------------------------------------------------------------------
> > To unsubscribe, e-mail: tapestry-dev-unsubscribe@jakarta.apache.org
> > For additional commands, e-mail: tapestry-dev-help@jakarta.apache.org
> >
> >
>
>
> --
> The Spindle guy.          http://spindle.sf.net
> Get help with Spindle:
> http://lists.sourceforge.net/mailman/listinfo/spindle-user
> Blog:                     http://jroller.com/page/glongman
> Feature Updates:          http://spindle.sf.net/updates
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: tapestry-dev-unsubscribe@jakarta.apache.org
> For additional commands, e-mail: tapestry-dev-help@jakarta.apache.org
>
>


--
Howard M. Lewis Ship
Independent J2EE / Open-Source Java Consultant
Creator, Jakarta Tapestry
Creator, Jakarta HiveMind

Professional Tapestry training, mentoring, support
and project work.  http://howardlewisship.com

---------------------------------------------------------------------
To unsubscribe, e-mail: tapestry-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: tapestry-dev-help@jakarta.apache.org


Re: [T5] Render queue and mixins

Posted by Geoff Longman <gl...@gmail.com>.
So am I on the right track in saying that Jesse could "mix into" Form
the abililty to submit via an XMLHttpRequest? (I'm sure Jesse would
*love* that!).

You can morph the behaviour of some else's component.

And the mechanism for acomplishing this would be annotations. How
would you annotate a class that you could potentially have never seen
the source for? Do I annotate things in the page class as the point
where an @Component annotation would be?

Geoff



On 2/27/06, Howard Lewis Ship <hl...@gmail.com> wrote:
> In Tapestry 4, we define a component as a class that (primarily) can
> render itself.
>
> Control over its output, including rendering its body and template,
> are all encapsulated within a single method, renderComponent().
>
> This is a good start.
>
> However, for Tapestry 5, the definition gets more complex.
>
> Outputing the component's tag(s), attribute(s), template and body are
> all different operations.  A state machine defines the steps and the
> progression from one step to the next.
>
> These operations are represented as methods on the peer (*) class. The
> lifecycle methods are marked with annotations that indicate when they
> will be invoked.
>
> In my vision of T5, a "mixin" is a kind of partial component that is
> "attached" to a ordinary component. It also contains parameters and
> lifecycle methods. The component will invoke appropriate methods on
> both the peer class and any mixin classes.
>
> The mixin may be part of a component's base implementation, or it may
> be applied to a particular usage of a component.
>
> So, think of Tapestry 4's validators parameter. This could be thought
> of as a mixin; it adds render-time behavior (generating JavaScript for
> client-side validation) and adds submit-time behavior (enforcing a
> contraint).
>
> With an appropriately rich state machine, and set of lifecycle methods
> and annotations, it should not be necessary to to have a validators
> parameter, just validator mixins.
>
> Other examples jump to mind: mixins that define security contraints or
> transactional boundaries for a link or form.
>
> The question is the timing; in what order are the methods of the peer
> and the mixin(s) executed, how are the results determined, how can the
> order by defined.
>
>
> (*) I'm open to better names for this.  ComponentBean?  Codebehind?
>
> On 2/27/06, Jesse Kuhnert <jk...@gmail.com> wrote:
> > Only because howard might be stuck on a long flight or otherwise indisposed,
> > I'll try another crack at it.
> >
> > You could probably think of mixins as having the ability to do multiple
> > inheritance in java. The only difference being that we're moving away from
> > interfaces/subclassing to more of a composition sort of pattern.
> >
> > For instance..The tacos logic that enhances all components via javassist
> > does a few things to component classes.
> >
> > - ) Adds an injected hivemind service reference to the AjaxWebRequest.
> >
> > -) Extends the renderComponent() method to do some checks on whether or not
> > the component should be renderd. (if requested in the ajax request, or if
> > it's even a valid ajax request).
> >
> > This is all done more or less manually, using the javassist API through
> > howards render enhancement stuff. So, instead of all this fun logic being
> > defined in a nice easily testable class, it's mostly manually written java
> > code inside of string blocks..ie:
> >
> > StringBuffer renderComponent = new StringBuffer("if (ajaxRequest) {
> > dothisThing(); } ");
> >
> > It's a little more complicated than that, but that's the basic premise. It's
> > an ok thing to do for internal API's, but isn't friendly to testing or more
> > regular uses overall..
> >
> > The most ideal way to do it would instead be able to define what this actual
> > class would look like in a real java class...We could have something like
> > this:
> >
> > public class AjaxRenderEnhancement {
> >           AjaxWebRequest ajaxRequest;
> >
> >           //normal hivemind injected service
> >           public void setAjaxRequest(AjaxWebRequest ....);
> >
> >
> >           public void renderComponent(IComponent component, IMarkupWriter
> > writer, IRequestCycle cycle) {
> >                if (ajaxRequest.isAjaxRequest()) {
> >                      component.renderComponent(writer, cycle);
> >                 }
> >               else return;
> >           }
> > }
> >
> > This is more or less the end result of what all the ajax enhancement stuff
> > would create. Now someone could take this code, which by itself can't do
> > anything, and "mix it" in with the component I want to enhance...Like a
> > PropertySelection component, or whatever you want. The AjaxWebRequest would
> > be made a member of the PropertySelection class, and the renderComponent
> > method would be added as well. (Signature is different).
> >
> > I don't actually know how he's going to implement it, so there are a lot of
> > very large flaws I've written up...But that is my understanding of it.
> >
> > C# supports this construct as well..So does javascript. That's how dojo
> > provides "super" class sort of functionality. There is a method
> > dojo.lang.mixin() that gets called to merge two javascript object
> > definitions together. Of course that language is much more dynamic, so it's
> > perfectly legal to do something like this:
> >
> > function validateInput(inputField) {
> >      if (!inputField.value) //validate
> > }
> >
> > var myObject = new Object();
> >
> > At this point my "myObject" object isn't really capable of doing
> > anything..But now we can do this:
> >
> > myObject.validateInput = validateInput;
> >
> > and then call:
> >
> > myObject.validateInput(document.getElementById("foo"));
> >
> > I'll leave the rendering queue to Howard as there are too many possibilities
> > for me to try imagining...
> >
> >
> > On 2/27/06, Geoff Longman < glongman@gmail.com> wrote:
> > >
> > > On 2/27/06, Jesse Kuhnert < jkuhnert@gmail.com> wrote:
> > > <snip!>
> > > >
> > > > It can probably get a ~lot~ more dynamic and graceful than that, but the
> > > > basic premise I think is that he'd be going in and automagically
> > > connecting
> > > > all of these things for you..Instead of having to manually specify a lot
> > > of
> > > > logic all over the place. The same would hold true for a lot of other
> > > things
> > > > as well I'm guessing.
> > >
> > > ok, without knowing if Howard's intent matches your description I'd be
> > > loathe to call this mixins. Looks more like auto-wiring to me.
> > >
> > > Enhancement today adds methods and fields to the public interface of a
> > > 'base' class but unless that added interface is there in the base
> > > class (abstract method decl) then the added 'stuff' is visible only to
> > > reflection based mechanisms (ognl as one example) and then only
> > > because Tapestry does a little "bait & switch" by substituting the
> > > enhanced class for the original one at runtime.
> > >
> > > But the following makes me doubt that autowire is all there is:
> > >
> > > >You will put your pages under com.example.root.pages and your
> > > >component under com.example.root.components.  Further, you will put
> > > >your mixins under com.examples.root.mixins.
> > >
> > > So a mixin appears to be a class - a class containing what?
> > >
> > > >
> > > > rendering queue - Again, no idea what's actually in his head, but my
> > > > layman's notion of it was that this would more or less be addressing the
> > > > issue of not knowing about something until you get to it, and then more
> > > or
> > > > less it being too late to do something smarter by the time you've gotten
> > > > there..
> > >
> > > ok. (and I'm not bashing you Jesse) how will this be accomplished?
> > >
> > > >
> > > > This would enable css to be globally contributed into the Shell for
> > > example.
> > > > So, we know how the Form does the rewind cycles...It passes in a null
> > > writer
> > > > that basically still does the entire render, it just doesn't output
> > > > anything..I think in this scenerio he would completely break out the
> > > logic
> > > > of rendering from the logic that sort of "moves the cycle forward".
> > > ..Making
> > > > it very very efficient to do the form rewind sort of logic if the actual
> > > > rendering is made into a seperate thing.
> > >
> > > That's a goal worth persuing. I still don't get it though. (boy I feel
> > > dumb today).
> > >
> > > >
> > > > This would also make about 10 billion other things much better. Like
> > > direct
> > > > component renders, etc....
> > > >
> > > > That's a layman's view on it though. I'm sure there is more too it but I
> > > > think that is the overall ~reason~ for the queue, even if not what the
> > > > actual details would contain.
> > >
> > > I think I'm just lacking a clear explanation.
> > >
> > > It worries me that even though I have been using Tapestry for many
> > > years this new stuff is sailing right over my head.
> > >
> > > Perhaps I'm too tied to java and static thinking. The closest I've
> > > been to a dynamic language is ruby. and not really even that as the
> > > closest I've been to ruby is the word "ruby" - a stone in one of my
> > > mother's rings!
> > >
> > > Geoff
> > >
> > > --
> > > The Spindle guy.          http://spindle.sf.net
> > > Get help with Spindle:
> > > http://lists.sourceforge.net/mailman/listinfo/spindle-user
> > > Blog:                     http://jroller.com/page/glongman
> > > Feature Updates:          http://spindle.sf.net/updates
> > >
> > > ---------------------------------------------------------------------
> > > To unsubscribe, e-mail: tapestry-dev-unsubscribe@jakarta.apache.org
> > > For additional commands, e-mail: tapestry-dev-help@jakarta.apache.org
> > >
> > >
> >
> >
>
>
> --
> Howard M. Lewis Ship
> Independent J2EE / Open-Source Java Consultant
> Creator, Jakarta Tapestry
> Creator, Jakarta HiveMind
>
> Professional Tapestry training, mentoring, support
> and project work.  http://howardlewisship.com
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: tapestry-dev-unsubscribe@jakarta.apache.org
> For additional commands, e-mail: tapestry-dev-help@jakarta.apache.org
>
>


--
The Spindle guy.          http://spindle.sf.net
Get help with Spindle:   
http://lists.sourceforge.net/mailman/listinfo/spindle-user
Blog:                     http://jroller.com/page/glongman
Feature Updates:          http://spindle.sf.net/updates

---------------------------------------------------------------------
To unsubscribe, e-mail: tapestry-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: tapestry-dev-help@jakarta.apache.org


RE: [T5] Render queue and mixins

Posted by Mark Stang <ms...@pingidentity.com>.
Howard,
If you are looking for an open-source "rich state machine" look at:

   http://www.superinterface.com/ewfsm.htm

It might not be as light weight as you would like, but it does all the things you want from a state machine...

regards,

mark


-----Original Message-----
From: Howard Lewis Ship [mailto:hlship@gmail.com]
Sent: Mon 2/27/2006 5:30 PM
To: Tapestry development
Subject: Re: [T5] Render queue and mixins
 
In Tapestry 4, we define a component as a class that (primarily) can
render itself.

Control over its output, including rendering its body and template,
are all encapsulated within a single method, renderComponent().

This is a good start.

However, for Tapestry 5, the definition gets more complex.

Outputing the component's tag(s), attribute(s), template and body are
all different operations.  A state machine defines the steps and the
progression from one step to the next.

These operations are represented as methods on the peer (*) class. The
lifecycle methods are marked with annotations that indicate when they
will be invoked.

In my vision of T5, a "mixin" is a kind of partial component that is
"attached" to a ordinary component. It also contains parameters and
lifecycle methods. The component will invoke appropriate methods on
both the peer class and any mixin classes.

The mixin may be part of a component's base implementation, or it may
be applied to a particular usage of a component.

So, think of Tapestry 4's validators parameter. This could be thought
of as a mixin; it adds render-time behavior (generating JavaScript for
client-side validation) and adds submit-time behavior (enforcing a
contraint).

With an appropriately rich state machine, and set of lifecycle methods
and annotations, it should not be necessary to to have a validators
parameter, just validator mixins.

Other examples jump to mind: mixins that define security contraints or
transactional boundaries for a link or form.

The question is the timing; in what order are the methods of the peer
and the mixin(s) executed, how are the results determined, how can the
order by defined.


(*) I'm open to better names for this.  ComponentBean?  Codebehind?

On 2/27/06, Jesse Kuhnert <jk...@gmail.com> wrote:
> Only because howard might be stuck on a long flight or otherwise indisposed,
> I'll try another crack at it.
>
> You could probably think of mixins as having the ability to do multiple
> inheritance in java. The only difference being that we're moving away from
> interfaces/subclassing to more of a composition sort of pattern.
>
> For instance..The tacos logic that enhances all components via javassist
> does a few things to component classes.
>
> - ) Adds an injected hivemind service reference to the AjaxWebRequest.
>
> -) Extends the renderComponent() method to do some checks on whether or not
> the component should be renderd. (if requested in the ajax request, or if
> it's even a valid ajax request).
>
> This is all done more or less manually, using the javassist API through
> howards render enhancement stuff. So, instead of all this fun logic being
> defined in a nice easily testable class, it's mostly manually written java
> code inside of string blocks..ie:
>
> StringBuffer renderComponent = new StringBuffer("if (ajaxRequest) {
> dothisThing(); } ");
>
> It's a little more complicated than that, but that's the basic premise. It's
> an ok thing to do for internal API's, but isn't friendly to testing or more
> regular uses overall..
>
> The most ideal way to do it would instead be able to define what this actual
> class would look like in a real java class...We could have something like
> this:
>
> public class AjaxRenderEnhancement {
>           AjaxWebRequest ajaxRequest;
>
>           //normal hivemind injected service
>           public void setAjaxRequest(AjaxWebRequest ....);
>
>
>           public void renderComponent(IComponent component, IMarkupWriter
> writer, IRequestCycle cycle) {
>                if (ajaxRequest.isAjaxRequest()) {
>                      component.renderComponent(writer, cycle);
>                 }
>               else return;
>           }
> }
>
> This is more or less the end result of what all the ajax enhancement stuff
> would create. Now someone could take this code, which by itself can't do
> anything, and "mix it" in with the component I want to enhance...Like a
> PropertySelection component, or whatever you want. The AjaxWebRequest would
> be made a member of the PropertySelection class, and the renderComponent
> method would be added as well. (Signature is different).
>
> I don't actually know how he's going to implement it, so there are a lot of
> very large flaws I've written up...But that is my understanding of it.
>
> C# supports this construct as well..So does javascript. That's how dojo
> provides "super" class sort of functionality. There is a method
> dojo.lang.mixin() that gets called to merge two javascript object
> definitions together. Of course that language is much more dynamic, so it's
> perfectly legal to do something like this:
>
> function validateInput(inputField) {
>      if (!inputField.value) //validate
> }
>
> var myObject = new Object();
>
> At this point my "myObject" object isn't really capable of doing
> anything..But now we can do this:
>
> myObject.validateInput = validateInput;
>
> and then call:
>
> myObject.validateInput(document.getElementById("foo"));
>
> I'll leave the rendering queue to Howard as there are too many possibilities
> for me to try imagining...
>
>
> On 2/27/06, Geoff Longman < glongman@gmail.com> wrote:
> >
> > On 2/27/06, Jesse Kuhnert < jkuhnert@gmail.com> wrote:
> > <snip!>
> > >
> > > It can probably get a ~lot~ more dynamic and graceful than that, but the
> > > basic premise I think is that he'd be going in and automagically
> > connecting
> > > all of these things for you..Instead of having to manually specify a lot
> > of
> > > logic all over the place. The same would hold true for a lot of other
> > things
> > > as well I'm guessing.
> >
> > ok, without knowing if Howard's intent matches your description I'd be
> > loathe to call this mixins. Looks more like auto-wiring to me.
> >
> > Enhancement today adds methods and fields to the public interface of a
> > 'base' class but unless that added interface is there in the base
> > class (abstract method decl) then the added 'stuff' is visible only to
> > reflection based mechanisms (ognl as one example) and then only
> > because Tapestry does a little "bait & switch" by substituting the
> > enhanced class for the original one at runtime.
> >
> > But the following makes me doubt that autowire is all there is:
> >
> > >You will put your pages under com.example.root.pages and your
> > >component under com.example.root.components.  Further, you will put
> > >your mixins under com.examples.root.mixins.
> >
> > So a mixin appears to be a class - a class containing what?
> >
> > >
> > > rendering queue - Again, no idea what's actually in his head, but my
> > > layman's notion of it was that this would more or less be addressing the
> > > issue of not knowing about something until you get to it, and then more
> > or
> > > less it being too late to do something smarter by the time you've gotten
> > > there..
> >
> > ok. (and I'm not bashing you Jesse) how will this be accomplished?
> >
> > >
> > > This would enable css to be globally contributed into the Shell for
> > example.
> > > So, we know how the Form does the rewind cycles...It passes in a null
> > writer
> > > that basically still does the entire render, it just doesn't output
> > > anything..I think in this scenerio he would completely break out the
> > logic
> > > of rendering from the logic that sort of "moves the cycle forward".
> > ..Making
> > > it very very efficient to do the form rewind sort of logic if the actual
> > > rendering is made into a seperate thing.
> >
> > That's a goal worth persuing. I still don't get it though. (boy I feel
> > dumb today).
> >
> > >
> > > This would also make about 10 billion other things much better. Like
> > direct
> > > component renders, etc....
> > >
> > > That's a layman's view on it though. I'm sure there is more too it but I
> > > think that is the overall ~reason~ for the queue, even if not what the
> > > actual details would contain.
> >
> > I think I'm just lacking a clear explanation.
> >
> > It worries me that even though I have been using Tapestry for many
> > years this new stuff is sailing right over my head.
> >
> > Perhaps I'm too tied to java and static thinking. The closest I've
> > been to a dynamic language is ruby. and not really even that as the
> > closest I've been to ruby is the word "ruby" - a stone in one of my
> > mother's rings!
> >
> > Geoff
> >
> > --
> > The Spindle guy.          http://spindle.sf.net
> > Get help with Spindle:
> > http://lists.sourceforge.net/mailman/listinfo/spindle-user
> > Blog:                     http://jroller.com/page/glongman
> > Feature Updates:          http://spindle.sf.net/updates
> >
> > ---------------------------------------------------------------------
> > To unsubscribe, e-mail: tapestry-dev-unsubscribe@jakarta.apache.org
> > For additional commands, e-mail: tapestry-dev-help@jakarta.apache.org
> >
> >
>
>


--
Howard M. Lewis Ship
Independent J2EE / Open-Source Java Consultant
Creator, Jakarta Tapestry
Creator, Jakarta HiveMind

Professional Tapestry training, mentoring, support
and project work.  http://howardlewisship.com

---------------------------------------------------------------------
To unsubscribe, e-mail: tapestry-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: tapestry-dev-help@jakarta.apache.org




Re: [T5] Render queue and mixins

Posted by Howard Lewis Ship <hl...@gmail.com>.
In Tapestry 4, we define a component as a class that (primarily) can
render itself.

Control over its output, including rendering its body and template,
are all encapsulated within a single method, renderComponent().

This is a good start.

However, for Tapestry 5, the definition gets more complex.

Outputing the component's tag(s), attribute(s), template and body are
all different operations.  A state machine defines the steps and the
progression from one step to the next.

These operations are represented as methods on the peer (*) class. The
lifecycle methods are marked with annotations that indicate when they
will be invoked.

In my vision of T5, a "mixin" is a kind of partial component that is
"attached" to a ordinary component. It also contains parameters and
lifecycle methods. The component will invoke appropriate methods on
both the peer class and any mixin classes.

The mixin may be part of a component's base implementation, or it may
be applied to a particular usage of a component.

So, think of Tapestry 4's validators parameter. This could be thought
of as a mixin; it adds render-time behavior (generating JavaScript for
client-side validation) and adds submit-time behavior (enforcing a
contraint).

With an appropriately rich state machine, and set of lifecycle methods
and annotations, it should not be necessary to to have a validators
parameter, just validator mixins.

Other examples jump to mind: mixins that define security contraints or
transactional boundaries for a link or form.

The question is the timing; in what order are the methods of the peer
and the mixin(s) executed, how are the results determined, how can the
order by defined.


(*) I'm open to better names for this.  ComponentBean?  Codebehind?

On 2/27/06, Jesse Kuhnert <jk...@gmail.com> wrote:
> Only because howard might be stuck on a long flight or otherwise indisposed,
> I'll try another crack at it.
>
> You could probably think of mixins as having the ability to do multiple
> inheritance in java. The only difference being that we're moving away from
> interfaces/subclassing to more of a composition sort of pattern.
>
> For instance..The tacos logic that enhances all components via javassist
> does a few things to component classes.
>
> - ) Adds an injected hivemind service reference to the AjaxWebRequest.
>
> -) Extends the renderComponent() method to do some checks on whether or not
> the component should be renderd. (if requested in the ajax request, or if
> it's even a valid ajax request).
>
> This is all done more or less manually, using the javassist API through
> howards render enhancement stuff. So, instead of all this fun logic being
> defined in a nice easily testable class, it's mostly manually written java
> code inside of string blocks..ie:
>
> StringBuffer renderComponent = new StringBuffer("if (ajaxRequest) {
> dothisThing(); } ");
>
> It's a little more complicated than that, but that's the basic premise. It's
> an ok thing to do for internal API's, but isn't friendly to testing or more
> regular uses overall..
>
> The most ideal way to do it would instead be able to define what this actual
> class would look like in a real java class...We could have something like
> this:
>
> public class AjaxRenderEnhancement {
>           AjaxWebRequest ajaxRequest;
>
>           //normal hivemind injected service
>           public void setAjaxRequest(AjaxWebRequest ....);
>
>
>           public void renderComponent(IComponent component, IMarkupWriter
> writer, IRequestCycle cycle) {
>                if (ajaxRequest.isAjaxRequest()) {
>                      component.renderComponent(writer, cycle);
>                 }
>               else return;
>           }
> }
>
> This is more or less the end result of what all the ajax enhancement stuff
> would create. Now someone could take this code, which by itself can't do
> anything, and "mix it" in with the component I want to enhance...Like a
> PropertySelection component, or whatever you want. The AjaxWebRequest would
> be made a member of the PropertySelection class, and the renderComponent
> method would be added as well. (Signature is different).
>
> I don't actually know how he's going to implement it, so there are a lot of
> very large flaws I've written up...But that is my understanding of it.
>
> C# supports this construct as well..So does javascript. That's how dojo
> provides "super" class sort of functionality. There is a method
> dojo.lang.mixin() that gets called to merge two javascript object
> definitions together. Of course that language is much more dynamic, so it's
> perfectly legal to do something like this:
>
> function validateInput(inputField) {
>      if (!inputField.value) //validate
> }
>
> var myObject = new Object();
>
> At this point my "myObject" object isn't really capable of doing
> anything..But now we can do this:
>
> myObject.validateInput = validateInput;
>
> and then call:
>
> myObject.validateInput(document.getElementById("foo"));
>
> I'll leave the rendering queue to Howard as there are too many possibilities
> for me to try imagining...
>
>
> On 2/27/06, Geoff Longman < glongman@gmail.com> wrote:
> >
> > On 2/27/06, Jesse Kuhnert < jkuhnert@gmail.com> wrote:
> > <snip!>
> > >
> > > It can probably get a ~lot~ more dynamic and graceful than that, but the
> > > basic premise I think is that he'd be going in and automagically
> > connecting
> > > all of these things for you..Instead of having to manually specify a lot
> > of
> > > logic all over the place. The same would hold true for a lot of other
> > things
> > > as well I'm guessing.
> >
> > ok, without knowing if Howard's intent matches your description I'd be
> > loathe to call this mixins. Looks more like auto-wiring to me.
> >
> > Enhancement today adds methods and fields to the public interface of a
> > 'base' class but unless that added interface is there in the base
> > class (abstract method decl) then the added 'stuff' is visible only to
> > reflection based mechanisms (ognl as one example) and then only
> > because Tapestry does a little "bait & switch" by substituting the
> > enhanced class for the original one at runtime.
> >
> > But the following makes me doubt that autowire is all there is:
> >
> > >You will put your pages under com.example.root.pages and your
> > >component under com.example.root.components.  Further, you will put
> > >your mixins under com.examples.root.mixins.
> >
> > So a mixin appears to be a class - a class containing what?
> >
> > >
> > > rendering queue - Again, no idea what's actually in his head, but my
> > > layman's notion of it was that this would more or less be addressing the
> > > issue of not knowing about something until you get to it, and then more
> > or
> > > less it being too late to do something smarter by the time you've gotten
> > > there..
> >
> > ok. (and I'm not bashing you Jesse) how will this be accomplished?
> >
> > >
> > > This would enable css to be globally contributed into the Shell for
> > example.
> > > So, we know how the Form does the rewind cycles...It passes in a null
> > writer
> > > that basically still does the entire render, it just doesn't output
> > > anything..I think in this scenerio he would completely break out the
> > logic
> > > of rendering from the logic that sort of "moves the cycle forward".
> > ..Making
> > > it very very efficient to do the form rewind sort of logic if the actual
> > > rendering is made into a seperate thing.
> >
> > That's a goal worth persuing. I still don't get it though. (boy I feel
> > dumb today).
> >
> > >
> > > This would also make about 10 billion other things much better. Like
> > direct
> > > component renders, etc....
> > >
> > > That's a layman's view on it though. I'm sure there is more too it but I
> > > think that is the overall ~reason~ for the queue, even if not what the
> > > actual details would contain.
> >
> > I think I'm just lacking a clear explanation.
> >
> > It worries me that even though I have been using Tapestry for many
> > years this new stuff is sailing right over my head.
> >
> > Perhaps I'm too tied to java and static thinking. The closest I've
> > been to a dynamic language is ruby. and not really even that as the
> > closest I've been to ruby is the word "ruby" - a stone in one of my
> > mother's rings!
> >
> > Geoff
> >
> > --
> > The Spindle guy.          http://spindle.sf.net
> > Get help with Spindle:
> > http://lists.sourceforge.net/mailman/listinfo/spindle-user
> > Blog:                     http://jroller.com/page/glongman
> > Feature Updates:          http://spindle.sf.net/updates
> >
> > ---------------------------------------------------------------------
> > To unsubscribe, e-mail: tapestry-dev-unsubscribe@jakarta.apache.org
> > For additional commands, e-mail: tapestry-dev-help@jakarta.apache.org
> >
> >
>
>


--
Howard M. Lewis Ship
Independent J2EE / Open-Source Java Consultant
Creator, Jakarta Tapestry
Creator, Jakarta HiveMind

Professional Tapestry training, mentoring, support
and project work.  http://howardlewisship.com

---------------------------------------------------------------------
To unsubscribe, e-mail: tapestry-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: tapestry-dev-help@jakarta.apache.org


Re: [T5] Render queue and mixins

Posted by Jesse Kuhnert <jk...@gmail.com>.
Only because howard might be stuck on a long flight or otherwise indisposed,
I'll try another crack at it.

You could probably think of mixins as having the ability to do multiple
inheritance in java. The only difference being that we're moving away from
interfaces/subclassing to more of a composition sort of pattern.

For instance..The tacos logic that enhances all components via javassist
does a few things to component classes.

- ) Adds an injected hivemind service reference to the AjaxWebRequest.

-) Extends the renderComponent() method to do some checks on whether or not
the component should be renderd. (if requested in the ajax request, or if
it's even a valid ajax request).

This is all done more or less manually, using the javassist API through
howards render enhancement stuff. So, instead of all this fun logic being
defined in a nice easily testable class, it's mostly manually written java
code inside of string blocks..ie:

StringBuffer renderComponent = new StringBuffer("if (ajaxRequest) {
dothisThing(); } ");

It's a little more complicated than that, but that's the basic premise. It's
an ok thing to do for internal API's, but isn't friendly to testing or more
regular uses overall..

The most ideal way to do it would instead be able to define what this actual
class would look like in a real java class...We could have something like
this:

public class AjaxRenderEnhancement {
          AjaxWebRequest ajaxRequest;

          //normal hivemind injected service
          public void setAjaxRequest(AjaxWebRequest ....);


          public void renderComponent(IComponent component, IMarkupWriter
writer, IRequestCycle cycle) {
               if (ajaxRequest.isAjaxRequest()) {
                     component.renderComponent(writer, cycle);
                }
              else return;
          }
}

This is more or less the end result of what all the ajax enhancement stuff
would create. Now someone could take this code, which by itself can't do
anything, and "mix it" in with the component I want to enhance...Like a
PropertySelection component, or whatever you want. The AjaxWebRequest would
be made a member of the PropertySelection class, and the renderComponent
method would be added as well. (Signature is different).

I don't actually know how he's going to implement it, so there are a lot of
very large flaws I've written up...But that is my understanding of it.

C# supports this construct as well..So does javascript. That's how dojo
provides "super" class sort of functionality. There is a method
dojo.lang.mixin() that gets called to merge two javascript object
definitions together. Of course that language is much more dynamic, so it's
perfectly legal to do something like this:

function validateInput(inputField) {
     if (!inputField.value) //validate
}

var myObject = new Object();

At this point my "myObject" object isn't really capable of doing
anything..But now we can do this:

myObject.validateInput = validateInput;

and then call:

myObject.validateInput(document.getElementById("foo"));

I'll leave the rendering queue to Howard as there are too many possibilities
for me to try imagining...


On 2/27/06, Geoff Longman < glongman@gmail.com> wrote:
>
> On 2/27/06, Jesse Kuhnert < jkuhnert@gmail.com> wrote:
> <snip!>
> >
> > It can probably get a ~lot~ more dynamic and graceful than that, but the
> > basic premise I think is that he'd be going in and automagically
> connecting
> > all of these things for you..Instead of having to manually specify a lot
> of
> > logic all over the place. The same would hold true for a lot of other
> things
> > as well I'm guessing.
>
> ok, without knowing if Howard's intent matches your description I'd be
> loathe to call this mixins. Looks more like auto-wiring to me.
>
> Enhancement today adds methods and fields to the public interface of a
> 'base' class but unless that added interface is there in the base
> class (abstract method decl) then the added 'stuff' is visible only to
> reflection based mechanisms (ognl as one example) and then only
> because Tapestry does a little "bait & switch" by substituting the
> enhanced class for the original one at runtime.
>
> But the following makes me doubt that autowire is all there is:
>
> >You will put your pages under com.example.root.pages and your
> >component under com.example.root.components.  Further, you will put
> >your mixins under com.examples.root.mixins.
>
> So a mixin appears to be a class - a class containing what?
>
> >
> > rendering queue - Again, no idea what's actually in his head, but my
> > layman's notion of it was that this would more or less be addressing the
> > issue of not knowing about something until you get to it, and then more
> or
> > less it being too late to do something smarter by the time you've gotten
> > there..
>
> ok. (and I'm not bashing you Jesse) how will this be accomplished?
>
> >
> > This would enable css to be globally contributed into the Shell for
> example.
> > So, we know how the Form does the rewind cycles...It passes in a null
> writer
> > that basically still does the entire render, it just doesn't output
> > anything..I think in this scenerio he would completely break out the
> logic
> > of rendering from the logic that sort of "moves the cycle forward".
> ..Making
> > it very very efficient to do the form rewind sort of logic if the actual
> > rendering is made into a seperate thing.
>
> That's a goal worth persuing. I still don't get it though. (boy I feel
> dumb today).
>
> >
> > This would also make about 10 billion other things much better. Like
> direct
> > component renders, etc....
> >
> > That's a layman's view on it though. I'm sure there is more too it but I
> > think that is the overall ~reason~ for the queue, even if not what the
> > actual details would contain.
>
> I think I'm just lacking a clear explanation.
>
> It worries me that even though I have been using Tapestry for many
> years this new stuff is sailing right over my head.
>
> Perhaps I'm too tied to java and static thinking. The closest I've
> been to a dynamic language is ruby. and not really even that as the
> closest I've been to ruby is the word "ruby" - a stone in one of my
> mother's rings!
>
> Geoff
>
> --
> The Spindle guy.          http://spindle.sf.net
> Get help with Spindle:
> http://lists.sourceforge.net/mailman/listinfo/spindle-user
> Blog:                     http://jroller.com/page/glongman
> Feature Updates:          http://spindle.sf.net/updates
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: tapestry-dev-unsubscribe@jakarta.apache.org
> For additional commands, e-mail: tapestry-dev-help@jakarta.apache.org
>
>

Re: [T5] Render queue and mixins

Posted by Geoff Longman <gl...@gmail.com>.
On 2/27/06, Jesse Kuhnert <jk...@gmail.com> wrote:
<snip!>
>
> It can probably get a ~lot~ more dynamic and graceful than that, but the
> basic premise I think is that he'd be going in and automagically connecting
> all of these things for you..Instead of having to manually specify a lot of
> logic all over the place. The same would hold true for a lot of other things
> as well I'm guessing.

ok, without knowing if Howard's intent matches your description I'd be
loathe to call this mixins. Looks more like auto-wiring to me.

Enhancement today adds methods and fields to the public interface of a
'base' class but unless that added interface is there in the base
class (abstract method decl) then the added 'stuff' is visible only to
reflection based mechanisms (ognl as one example) and then only
because Tapestry does a little "bait & switch" by substituting the
enhanced class for the original one at runtime.

But the following makes me doubt that autowire is all there is:

>You will put your pages under com.example.root.pages and your
>component under com.example.root.components.  Further, you will put
>your mixins under com.examples.root.mixins.

So a mixin appears to be a class - a class containing what?

>
> rendering queue - Again, no idea what's actually in his head, but my
> layman's notion of it was that this would more or less be addressing the
> issue of not knowing about something until you get to it, and then more or
> less it being too late to do something smarter by the time you've gotten
> there..

ok. (and I'm not bashing you Jesse) how will this be accomplished?

>
> This would enable css to be globally contributed into the Shell for example.
> So, we know how the Form does the rewind cycles...It passes in a null writer
> that basically still does the entire render, it just doesn't output
> anything..I think in this scenerio he would completely break out the logic
> of rendering from the logic that sort of "moves the cycle forward". ..Making
> it very very efficient to do the form rewind sort of logic if the actual
> rendering is made into a seperate thing.

That's a goal worth persuing. I still don't get it though. (boy I feel
dumb today).

>
> This would also make about 10 billion other things much better. Like direct
> component renders, etc....
>
> That's a layman's view on it though. I'm sure there is more too it but I
> think that is the overall ~reason~ for the queue, even if not what the
> actual details would contain.

I think I'm just lacking a clear explanation.

It worries me that even though I have been using Tapestry for many
years this new stuff is sailing right over my head.

Perhaps I'm too tied to java and static thinking. The closest I've
been to a dynamic language is ruby. and not really even that as the
closest I've been to ruby is the word "ruby" - a stone in one of my
mother's rings!

Geoff

--
The Spindle guy.          http://spindle.sf.net
Get help with Spindle:   
http://lists.sourceforge.net/mailman/listinfo/spindle-user
Blog:                     http://jroller.com/page/glongman
Feature Updates:          http://spindle.sf.net/updates

---------------------------------------------------------------------
To unsubscribe, e-mail: tapestry-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: tapestry-dev-help@jakarta.apache.org


Re: [T5] Render queue and mixins

Posted by Jesse Kuhnert <jk...@gmail.com>.
I'm probably not the best person for describing what he might be thinking,
but here are some thoughts. .

mixins - http://en.wikipedia.org/wiki/Mixins

More or less allows you to dynamically add methods/implementation of things
to classes at runtime. Howard's already been doing this in a way with the
render enhancement workers, but I'm guessing this is a more direct approach
based on annotations. So, if you define a listener method in your class that
you want to be invoked when the "PropertySelection" component value has
changed on the client you might in theory be able to do something like:

@EventListener(component="myPropertySelect", event="onChange",
validateForm="false")
public void selectSomethingBasedOnProperty(Object foo) {
....
}

It can probably get a ~lot~ more dynamic and graceful than that, but the
basic premise I think is that he'd be going in and automagically connecting
all of these things for you..Instead of having to manually specify a lot of
logic all over the place. The same would hold true for a lot of other things
as well I'm guessing.

rendering queue - Again, no idea what's actually in his head, but my
layman's notion of it was that this would more or less be addressing the
issue of not knowing about something until you get to it, and then more or
less it being too late to do something smarter by the time you've gotten
there..

This would enable css to be globally contributed into the Shell for example.
So, we know how the Form does the rewind cycles...It passes in a null writer
that basically still does the entire render, it just doesn't output
anything..I think in this scenerio he would completely break out the logic
of rendering from the logic that sort of "moves the cycle forward". ..Making
it very very efficient to do the form rewind sort of logic if the actual
rendering is made into a seperate thing.

This would also make about 10 billion other things much better. Like direct
component renders, etc....

That's a layman's view on it though. I'm sure there is more too it but I
think that is the overall ~reason~ for the queue, even if not what the
actual details would contain.

On 2/27/06, Geoff Longman <gl...@gmail.com> wrote:
>
> Howard,
>
> You described a rendering queue and mixins recently.
>
> Frankly I don't understand what you are getting at.
>
> Care to elaborate? Thanks.
>
> Geoff
>
> --
> The Spindle guy.          http://spindle.sf.net
> Get help with Spindle:
> http://lists.sourceforge.net/mailman/listinfo/spindle-user
> Blog:                     http://jroller.com/page/glongman
> Feature Updates:          http://spindle.sf.net/updates
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: tapestry-dev-unsubscribe@jakarta.apache.org
> For additional commands, e-mail: tapestry-dev-help@jakarta.apache.org
>
>