tapestry-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Richard Lewis-Shell" <rlewissh...@mac.com>
Subject Re: dynamic library
Date Tue, 23 Dec 2003 19:57:00 GMT
i really like the idea of genuinely dynamic components/pages.  nice work
eric!

----- Original Message ----- 
From: "Erik Hatcher" <erik@ehatchersolutions.com>
To: <tapestry-dev@jakarta.apache.org>
Sent: Wednesday, December 24, 2003 8:44 AM
Subject: dynamic library


> In my efforts to design a dynamic front-end where the UI is built from
> a database-driven specification of what fields should be presented, I
> am exploring the possibility of using a completely dynamic "library"
> (in the Tapestry sense) which serves up dynamically defined
> "components" (again in the Tapestry sense).  I'm happy to report that
> it is working!
>
> In part of my explanation, I'll be complaining about some pieces of
> Tapestry, but I first want to again thank Howard and the other Tapestry
> developers that built this thing - it has proven to be extremely
> flexible and powerful.
>
> I'm going to describe what I have done, in order to benefit others, but
> also to solicit feedback on ways to improve and build upon what I have
> done.  In fact, this dynamic library could be made into something
> worthy of contributing back to Tapestry.
>
>  From a custom BaseEngine extension, I already had an overridden
> createSpecificationSource providing a custom subclass of
> DefaultSpecificationSource; from there, I overrode
> getLibrarySpecification.  If the library name is "dyna.library", I
> returned a custom DynaLibrarySpecification, otherwise delegated to the
> super class to carry on as normal.
>
> In my .application file I added <library id="dyna"
> specification-path="dyna.library"/>, and the path of course is
> arbitrary and keyed off of in getLibrarySpecification above.  Maybe
> there is a way to even more dynamically add a library to an
> application?  If so, how? (I didn't even explore this route yet, but
> perhaps I can do away with some code if done implicitly).
>
> My DynaLibrarySpecification is a bare-bones implementation of
> ILibrarySpecification directly - with most methods doing nothing or
> returning null.  This brings me to my first complaint.  In digging into
> extending Tapestry in sophisticated ways, it is great there are
> interfaces for everything, but in several cases the interfaces have far
> too many methods on them.  For example, in this case,
> ILibrarySpecification has methods really only used by
> LibrarySpecification for populating via Digester.  It seems to me that
> only methods for retrieving information from a library really belong on
> the interface (or action methods, of course), but setter/adder methods
> do not belong there.  These setter/adder methods really only belong on
> the implementation that is designed to be populated from an XML file.
> Am I correct that methods like setDescription really aren't needed on
> the interface?  (in fact, nothing specifically calls that except for
> Digester currently).
>
> One other complaint - there are lots of places where a List is
> returned.  Yes, it is explicitly documented that these should return
> empty lists, not null, but why not allow null to be returned?  (this is
> not a big deal, just a minor nit causing me more work to implement a
> bunch of otherwise dummy methods).
>
> I still have not quite mastered exactly how to use IResourceLocation,
> but the only real reason to implement my own ILibrarySpecification was
> to return a custom IResourceLocation, DynaResourceLocation in this
> case, from getSpecificationLocation.  I had to make
> DynaResourceLocation a bit more clever than it seems necessary.... when
> using an @Insert component from a dynamically generated template, for
> example, the framework calls to construct a DynaResourceLocation using
> getRelativeLocation - which seemed odd to me so I first tried returning
> null, but that causes an NPE elsewhere in the framework, so I had to
> move some smarts to getResourceURL to return null if it is not a
> recognized component (this causes the framework to search further and
> find @Insert in the framework namespace).
>
> No back to my custom subclass of DefaultSpecificationSource - I
> overrode getComponentSpecification and if the location is an instanceof
> my DynaResourceLocation I return back a custom
> DynaComponentSpecification, which is a raw implementation of
> IComponentSpecification.  Once again, all of the setters here...
> geez!!!!  For my prototyping, I just returned the class name of my
> DynaComponent (an empty BaseComponent subclass) from
> getComponentClassName.  To add a parameter to my dynamic components, I
> just hacked a quick and dirty implementation of getParameter with a
> mostly empty IParameterSpecification (once again, those darn setters on
> the interface!) and getParameterNames.
>
> Wait, but that is not all... since my dynamic component extends from
> BaseComponent, it needs a template.  So my custom engine overrides
> createTemplateSource and returns custom subclass of
> DefaultTemplateSource.  For prototyping purposes, I just did a quick
> check on the "dyna" namespace in an overridden getTemplate method and
> hacked a template in a String, then parsed it just like
> DefaultTemplateSource does (this required some cut and paste of the
> ParserDelegate from DefaultTemplateSource since it was private).
>
> Voila!
>
> In a test page, I put this:
>
> <dyna:FooBar attribute="blah"/>
>
> There is no FooBar.html or FooBar.jwc.  The "attribute" is added
> dynamically through the component specification I mentioned above (with
> getParameterNames and getParameter).  The template data is a String:
>
> String template = "<b>FooBar!!!!  <span key=\"someKey\"/>  <span
> jwcid=\"@Insert\" value=\"ognl:attribute\"/>";
>
> I added the <span key="..."/> in just to see how message resources
> worked, which required me to update my custom subclass of
> DefaultComponentMessagesSource to handle the "dyna" namespace by
> passing through to our database rather than looking for a
> FooBar.properties file.  And the @Insert forced me to do some things
> with DynaResourceLocation, which I've already mentioned.
>
> Voila!  Dynamically generated components and templates!
>
> I'm quite impressed that (despite how complex it looks above) it was
> not too bad to implement this.  Do folks think this is something that
> should be added into Tapestry itself somehow?  To be honest, I'm not
> sure how to package it up to be generically useful, and the core
> already supports this dynamic stuff - but having an easier way to have
> a non-file-based template/specification would be cool.  I've currently
> only focused on components, but the same could easily be done with
> pages.
>
> But, now the questions continue.... how do I go about utilizing these
> dynamic components, um, "dynamically"??   Do I need to build a dynamic
> page as well?  But how do you add components to it dynamically?  (I
> haven't tried, so maybe this is not too hard either).  I could, I
> suppose, create an HTML template for a page dynamically and parse it.
> I'm looking for how to take this further.  Here is the use case - I'm
> going to have a database tell me what elements to present - each of
> these will correspond to a component type.  How do I do an @Foreach
> over all elements and inject these components on the fly?
>
> Erik
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: tapestry-dev-unsubscribe@jakarta.apache.org
> For additional commands, e-mail: tapestry-dev-help@jakarta.apache.org
>
>



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


Mime
View raw message