Showing posts with label tapestry. Show all posts
Showing posts with label tapestry. Show all posts

Monday, January 16, 2012

Tynamo committer, new Tynamo module:tapestry-jdo

The Announcement: 
First of all the announcement : as a new commiter to Tynamo, I have just released a new module, Tapestry-JDO, which allows Tapestry users to build applications based on JDO using familiar (from Hibernate and JPA integrations) Tapestry idioms for persistence manager injection and transaction management (using @CommitAfter). The official announcement is on the Tynamo Blog

The History
How that came about...

I've been a Tapestry user for a few years, usually lurking on the mailing lists and answering a question here and there , wherever I could contribute. I've always enjoyed Tapestry's approach to building web apps : pages, components, and annotation driven magic has been quite enjoyable, and the out of the box live class reloading make the experience pleasant and productive. At first I somewhat loathed the heavy emphasis on annotations to drive the framework magic; however, having dealt w/ the Grails' way of doing it for a few years, it now seems a bit  preferable for being more clear and explicit.

Fast forward a few years, Google announced the App Engine (GAE) and I was totally blown away of how they turned the world of java web app hosting on its head. Prior to GAE, Java web app hosting was both expensive and inconvenient - who would want to build publicly facing java apps, no wonder PHP ruled the roost . Of the two persistence APIs on the App Engine, JDO was the more familiar one, having spent a few years on the job working w/ JDO. Prior to GAE's choice to use JDO as a persistence API (at least in my world) it seemed like a dead end. Hibernate and JPA had taken the world by storm, and nobody seemed to care about JDO any longer. Another reason why JDO seemed interesting on the App Engine is that from its very inception JDO claimed that it was not necessarily married to relational databases. While back in the day that seemed to me like a not-so-interesting design goal, when GAE chose it as one of the options it seemed to make so much more sense to use that, as the backend store of GAE is non relational. Today, with the rise of  NoSQL, it really starts clicking (e.g. DataNucleus MongoDB  support) - all of a sudden, the same skillset that you've developed from the relational ORM days, you can apply in non-relational contexts - sweet !

So,  along the way I built a couple of apps to run on the App Engine - a site for  math problem solving assistance service and an artwork portfolio site . Neither of the apps were particularly complicated or difficult to build from a development point of view, but had just enough interaction w/ the back end where I had to deal w/ JDO directly - e.g. getting persistence managers, starting sessions, committing, all that. As much as I find Spring to be a useful tool in the toolbox, booting up a full blown spring container just too much for a simple web app. Additionally, the existence of tapestry-ioc makes Spring redundant and way too verbose for many of its possible usages within a simple web app. On the other hand, without Spring, manual transaction management is a royal PITA and I was looking for a better of way doing it. My first stab was to set up a Spring  dependency (w/o a spring container) to just get the Transaction manager classes and wire them up in Tapestry IOC. It worked pretty decently but the integration was just a kludge, not to mention the few megabytes that the four classes from Spring I used brought down with them.

Having been on the Tapestry mailing lists, the Tynamo project has continued to impress me with the suite of modules that the project kept releasing to fill needs in the tapestry community - e.g. jpa, security, routing, openid authentication, and more. Thus, when I started wondering where to look for an example of how to build the JDO support, Tynamo was the first candidate. So, I grabbed  Tynamo-JPA, moved some things around replaced all the usages of the JPA Entity Manager w/ JDO's PersistenceManager, touched every piece of code in the module and before you know it I had a working basic setup that allowed me to inject a PersistenceManager and use a @CommitAfter annotation to set up some automatic transaction management for myself. With that basic implementation I was able to finish the project that I was working on and everything looked great.

Then, came the question of what to do w/ my changes. It seemed that something like this might be a valuable contribution to the Tapestry community, yet I didn't quite feel like setting up a project somewhere . So, I figured, since I heavily borrowed from Tynamo in the implementation, why not ask them if they would be interested in having the module be a part of their project. On first thought it seemed like a long shot, my scrappy JDO module couldn't possibly fit within the pure awesomeness of Tynamo. Yet, I figured, it's worth a shot.  Shortly after I asked if they wanted it, they said yes, I zipped up the source and sent it out. I didn't necessarily plan on becoming a committer on the project, but before I knew it , Kalle had added me to the list and given me access to SVN, and posted an announcement on the blog about a new member of the project. I was a bit surprised by the warm welcome I received - I certainly felt that my contribution was appreciated.

To make the long story short, a few months later, major code and javadoc cleanup, fixing the tests and stepping through the Tynamo / Codehaus release process, the cat is out of the bag - the module is released, the announcements are out. I hope this new module is useful to someone.

Enjoy ! 

Wednesday, November 30, 2011

My Scala (and Tapestry 5) experience

Since both a couple of coworkers asked me about Scala in the last few weeks, I thought these might be interesting to read through (something that emerged over the last few days)

  •  http://codahale.com/downloads/email-to-donald.txt
  •  http://codahale.com/the-rest-of-the-story/


I have obviously not used Scala to the extent that the guy describes, but I can testify at how annoying it is the constant translation between Java and Scala (especially, since my small app, , was using Tapestry 5, which is obviously a Java framework). The conversion between the two was made worse (at least for me, a total Scala newb) by the following:

  • Classes with the same names but completely or subtly different usages and intents . The fact that the Scala library used the same class names as the Java library (java.lang.Long and scala.Long) , the default imports use them, and there are some magical conversions that occur between the eponymous types. On a few occasions I was totally baffled about something not working only to find that in the end, the code was getting the wrong type . Thus, in a bunch of my classes, I ended up explicitly having to import the Java classes that the framework expected to work with , e.g. 
      
    import java.util.{List => JList }
    import org.slf4j.Logger
    import scala.collection.JavaConversions._

    class FooPage {


    @Property
    private var catPieces:JList[ArtPiece] = _


    // explicitly declaring the returning types as the Java types
    def onPassivate():JList[String]= {
    // and using the Scala provided conversions
    return seqAsJavaList(List(category,subCategory))
    }

    }

    and then explicitly use the java specific types. A similar but different situation exists with java.util.List and the scala List classes (e.g.  scala.collections.immutable.List) although they have the same name they have a completely different purpose (e.g. the Scala list is not necessarily intended to be created, and manipulated like the Java list); the equivalent of the java list is the recommended Scala ListBuffer
  • Null handling -  because I was interacting w/ a Java framework, there was an expectation that nulls are OK and at different places, the framework does expect methods to return nulls in order to behave in certain ways. Scala goes for the whole Option pattern (where you aren't supposed to use nulls to make it all better) and has some conversion (that I obviously, don't fully understand) between null and these types. However, because of the interaction w/ the Java framework, I had to learn how to deal with both. It kinda sucked.
  • Tapestry 5 and Scala interactions -  because Tapestry 5 pushes the envelope on being a Java framework w/ a whole bunch of annotation processing, class transformations, etc. , in some cases there were clashes between the T5 approach and Scala. In some respects, Tapestry 5 manages to be a respectable and succinct Java framework by adding a whole bunch of metaprogramming features, which when used with Scala make the scala code less attractive, e.g: 
    • Page properties that would otherwise be set up as private fields in regular Tapestry 5, now have to be declared as private fields and initialized. If you didn't declare them as private, then T5 would complain (since pages can't have non-private members as it is managed by T5) , e.g. :
        
      class Foo {
      @Inject
      var logger:Logger = _

      @Inject
      var pm:PersistenceManager = _
      }
    • Sometimes the T5 and Scala approaches seemed to clash in ways that make things complicated. For example, in the persistent objects in the class, I often annotated the private fields w/ @BeanProperty (so that Scala generates proper getters/setters for those fields).
        
      import scala.reflect.BeanProperty
      import javax.jdo.annotations.Persistent;
      class PersistentFoo {
      @BeanProperty
      @Persistent
      var title = ""

      }
      Yet, when I accidentally did the same for some page properties at weird points the application would start failing (on application reload with Tapestry's live class reloading) until in pages I replaced the approach w/ Tapestry's @Property annotation (although they're supposed to do the same it's quirky w/ BeanProperty)
        
      import org.apache.tapestry5.annotations.Property;

      class FooPage {
      @Property
      private var category:String = _

      }


When I was working on the app, a few times I had to just stop for a day because I couldn't figure out how to do something massively simple (e.g. how to succinctly join a list of Strings into a comma separated string - stuff that would have taken me 30 seconds to do in Java, 2 seconds in Groovy and the proposed Scala solutions seemed like massive overkill). I originally started wanting to write some tests in Scala for this app, because I thought, "wouldn't it be nice to have something a little more flexible and less verbose than Java", but that still has nice static typing. Later I decided to try the whole Scala+T5 approach, and I have to admit I was pretty mad at myself when I would get stuck .

Obviously, many of my problems described above were due to my own weak Scala-foo (e.g. I had read through at least 2-3 books in order to be brave enough to try this just to learn that until I try things hands on, it doesn't stick too well), and other issues that I had were due to the interaction w/ the specific Java framework that I chose (Tapestry 5). Yet, in some ways, the experience was somewhat disappointing - having worked w/ Groovy for the last few years there is a massive difference in the approaches of the two languages. Where Groovy would often sacrifice some "internal beauty" in order to make a Java developer's life sweet and pleasant, e.g. :

  • Joining a list of strings
     
    [1,2,3].join(",");
  • string formatting using $ inside of strings
     
    "Blah blah $fooVar"
  • Null safe dereference
     
    foo?.bar
... whereas Scala somehow gets stuck in an ideological mode e.g.


One part of my setup that worked very  well and I enjoyed quite a bit was the Continuous Compilation and Tapestry's Live Class Reloading. Whereas for prior Tapestry pure-Java projects I had to rely on IDE magic to do some Compile-on-Save so that Tapestry can reload the changed classes, w/ the Scala setup it was much nicer.  I set up a Maven project w/ the Scala Maven plugin , and then kick off the scala:cc goal  to make it compile the changed page classes into my project. Thus, I had a completely IDE-independent setup that gave me a live-reloading experience on-par (and possibly beyond) the reloading experience with Grails.

In the end, after I managed to work through some of the issues described above, it ended up being a pretty reasonable set up and I was able to make pretty decent progress in getting the app out the door (for my wife's birthday). At the same time, I wasn't really able to leverage any cool Scala features that would magically boost my productivity, or make the codebase significantly cleaner or smaller (in some respects, it feels like the Scala based code is more verbose because of all the conversions and casting into Java types). I feel that if I knew more about Scala and was more knowledgeable about Tapestry internals, I might be able to write a Tapestr5 - Scala adapter layer that would plug into some of T5's extensions points to make it work more naturally with Tapestry (e.g. working w/ Scala lists in views, different handling of null values, etc). As a learning experience - I learned a lot, both about things that were interesting and useful (a bit of functional programming, Java/Scala integration), and some things that I really didn't want to know that much about (how Scala and T5 munge the Java classes to make the things tick).

In any event, the advice to people who like to try this kind of integration would be to allow yourself plenty of time for learning and experimentation w/ Scala and not giving up too early ( as I was almost ready to do on a few occasions). Fanf's blog has a few blog entries and a project on GitHub that is  an excellent starting point.


Wednesday, May 13, 2009

RAD w/ Tapestry 5, NetBeans 6.7, Maven, and Jetty : Really !!!

One of the major upsides of using Tapestry 5 is the much touted live class and template reloading. Up until recently, if you followed my previous post on working with Tapestry 5 and NetBeans, you probably ended w/ a workable solution, but still not ideal , as the live template and class reloading wasn't exactly working as expected. As a result, whenever you wanted to see the changes that you made in the live app (after running mvn jetty:run) you had to do the following:


mvn compile resources:resources
.........
-----------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 18 seconds
[INFO] Finished at: Wed May 13 03:16:32 EDT 2009
[INFO] Final Memory: 16M/71M





The issue here was that NetBeans (in 6.1 and prior) did not support CopyOnSave or CompileOnSave properly in Maven projects (it did for NetBeans native projects, so if you had set up a NetBeans native project w/ explicit jar dependencies, etc it would work fine). The effect of running the above command was to compile your changes, and copy the compiled classes and modified resources into your <outputDirectory> (typically target/classes) . So, the 18 seconds above are not exactly something to lose sleep over, but it's still not the same like having the immediate Grails(or Rails)-like immediate feedback loop (that is, "Ctrl-S->Alt-Tab to browser->F5", which is "Save->Switch to Browser->Refresh").

In any case, help is on the way.




In the most recent version of NetBeans (in the 6.7 daily builds ), the issues w/ CopyOnSave support has been fixed (well, almost fixed, see the NetBeans IssuZilla issue), and now it transparently copies your modified resource files to target/[app-name]/WEB-INF/classes. Thus, with just a minor tweak, you can accomplish a Tapestry 5 Nirvana.



  1. First, set up a new Maven project by File->New Project->Select Maven project type. Follow my previous instructions on creating the actual project. Just a side note, for some reason the latest production T5 version (5.1) doesn't show up on the list of available archetypes in NetBeans.


  2. Running the app is easy, the default project comes w/ the Jetty plugin set up, so you can just run "mvn jetty:run" on the console.


  3. Alternatively, map a custom Maven goal in NetBeans by right clicking on the project, going to Custom-Goals and mapping jetty:run . See the screenshots for some extra help







  4. The default project setup comes with an Index page living in the web app context. Now that you ran Jetty, you should be able to just make changes to the template, and see them immediately. The secret here is that Jetty runs by default out of src/main/webapp, so T5 picks up the changes out of the box, no additional support by the IDE is needed.

    The problem here is that if you tried making changes to your page class (e.g. Index.java), they're not being picked up. Jetty runs from the classes in target/classes. The idea here is that we want to IDE to autocompile the changes, drop them into target/classes and have T5 pick up the new page classes. As mentioned at the beginning of the post, if you just ran the maven build again (e.g. mvn compiler:compile), but we need something better.

    OK, so, go to the project properties, go to the Build-Compile section. In the panel, select from the "Compile on Save" (COS) dropdown the "for both application and test execution".




    The trick to remember here is that this only works for "supported servers" (e.g. I know that at least Tomcat and Glassfish are in that list) where the IDE would compile the new classes, and re-deploy them on the server. Jetty is not one of these supported servers, and in order for the Compile-on-save goodness to work, the IDE needs to know you ran the app so that it can activate COS. Now, although you probably don't want to run the app in Tomcat , go ahead and run the app, select to run it in Tomcat. Now that you ran the app in Tomcat, NetBeans activated COS for this app, and now if you make new changes to your Index.java, NetBeans copies out the compiled classes to target/classes, and Jetty picks up the changes. After you run the app, you can just stop Tomcat (and the COS feature will continue working).



  5. This is pretty close to perfect. Trouble is, if you have any page templates under src/main/resources, you're still out of luck, as the resources don't get copied out into target/classes after you do the initial jetty:run. But don't despair, there is just one more step that will get us there.



  6. Add the following to your pom.xml


    <outputDirectory>${project.build.directory}/${project.build.finalName}/WEB-INF/classes</outputDirectory>








Now, this is a bit of a hack. Basically, we're telling maven to use the target/[app-name]/WEB-INF/classes to do the initial and any subsequent builds, which is where both the classes from src/main (and whereever else) and src/main/resources end up. The trick here is that this is the same directory that "mvn package" uses, and it is also the same directory that NetBeans uses for the Compile-on-save functionality. Basically, when you make changes to your page template sin src/main/resources (and after you've run your app in Tomcat once), NetBeans continues to compile the classes and copy the modified resources from src/main/resources and drop them into the target/[app-name]/WEB-INF/classes.




Considering that this is indeed a a hack, I filed a patch for NetBeans to properly support this T5 setup in Maven project. However, what got into 6.7 is only the fix to properly copy resources into target/[app-name]/WEB-INF/classes (and not in target/classes). The develoeper on the issue has some other ideas on how this should go, hopefully the full fix will go into the NetBeans version after 6.7. In the meantime, either use this little hack, or I'll probably try to repackage my fix as a standalone plugin to support this out of the box.

Wednesday, May 14, 2008

Tapestry5 NetBeans Quickstart

I have been following the development of Tapestry 5 closely for the last couple of months, and I even got the first Tapestry 5 book that came out. I'm a big Tapestry fan, and I've been looking forward to the new Tapestry 5 release. I even lucked out and had a chance to talk to Howard in person:



One of the cool things that keeps drawing me towards Tapestry is the goal to make it really easy and intuitive to work with. One of the goals that I remember hearing for Tapestry 5 was to make it that easy, that it would compete more w/ Grails & Rails and not so much w/ traditional Java Web app frameworks (e.g. Struts, Struts2, etc)

However, when I first took a look at Tapestry 5, I was a little disappointed by the six line Maven command that one had to type in when starting a new project (e.g. see http://tapestry.apache.org/tapestry5/tutorial1/first.html):

mvn archetype:create
-DarchetypeGroupId=org.apache.tapestry
-DarchetypeArtifactId=quickstart
-DgroupId=org.apache.tapestry
-DartifactId=tutorial1
-DpackageName=org.apache.tapestry.tutorial


Compare that with Grails:


grails create-app

Welcome to Grails 1.0 - http://grails.org/
Licensed under Apache Standard License 2.0
Grails home is set to: /usr/local/java/grails
Application name not specified. Please enter:
FooApp
---------------
[propertyfile] Updating property file: /home/polrtex/temp/FooApp/application.properties
Created Grails Application at /home/polrtex/temp/FooApp



It is true that one doesn't create an application all that often, and copy-and-pasting
these initial 5-6 lines would not be that big of a deal. However, for a newcomer, the Tapestry 5 experience has to be really smooth and starting a new app should be a breeze.

So, you would say, what does this have to do with NetBeans ?

Here it comes. As usual, NetBeans rocks everyone's socks, by lowering the entry barrier into starting an application. Here are the first steps (equivalent to the first two pages of the Tapestry tutorial : http://tapestry.apache.org/tapestry5/tutorial1/env.html). Here is what you need to do:
( Assuming that you already have a good install of NetBeans 6.1).

  1. Install the NetBeans Maven plugin by going into Tools -> Plugins . Type "maven" in the upper-left corner search box and install the plugin. The result should look something like this:
  2. Create a new Maven project
  3. Expand the "Archetypes from remote Maven repositories" and scroll down to find the Tapestry5 quickstart archetype . You might want to pay close attention to the description and select the latest archetypes (in my case, for 5.0.11)
  4. Now that you have the nice wizard, fill out the configuration attributes to specify the group id, the location of the project, the name of the project, etc.
  5. When you hit Finish, Maven will start downloading all the dependencies and setting up your project.
  6. Your new and shiny project is ready to go. Go into the project Properties and select your desired server to deploy to:
  7. Run the project from the project context menu and you're up and running !!!!



One very cool option that makes the Tapestry 5 setup almost identical to the Grails setup is the ability to run the application in Jetty by going to the command line and running:
mvn jetty:run

The upside of doing this is that after you run it, there is no deployment step. Tapestry supports reloading of the page templates as well as the page classes. As a result, whenever you make a change to a page, you can save it, refresh the browser and see the changes . Similarly, when you make a change to a class, compile it and the changes are immediately visible to the application. Such a setup really cuts down on waiting for the app to deploy.

So now, looking back a little bit, this setup is indeed very competitive w/ the Grails setup. In Grails, you would download the Grails distribution, and then would run the "grails create-app" command to create the new project. Grails would then prompt you for some properties (e.g. project name) and you're done. For Tapestry, it's quite similar; however, instead of downloading the Tapestry distribution, you would simply download Maven2 (or in the case of NetBeans, you would install the NetBeans plugin). Even better for Tapestry, if you already have Maven install, then starting a new app becomes a zero cost operation : you just specify the command line args (or better yet, use NetBeans to create the new app) and you're on your way, all dependencies already in place.

So, so far it's a tie between Grails and Tapestry. Grals vs Tapestry = 1:1

Enjoy your shiny and new Tapestry 5 app in NetBeans !!!

Friday, September 14, 2007

Grapestry view and controller resolvers

This is a posting that I had started quite a while ago (right when I was starting w/ Grapestry), and I never posted it. Anyway, I thought that the content might be useful to someone trying to use hivemind with Tapestry 4. It would be very interesting when I will get a chance to try the same using the new and shiny Tapestry 5.

--------------------

The first couple of steps from the Grapestry wish list is to make the templates and pages be located in the same spot where the standard Grails gsp-s and controllers are (e.g. in grails-app/views and grails-app/controllers respectively).

First to set up the stage to what I'll talk about. For starters, I knew that HiveMind is what makes Tapestry tick. Secondly, I knew that Tapestry is very flexible and customizable, and I expected to fairly easy be able to make it look in all the right places.

So, first stop was the Tapestry User Guide configuration section. At the bottom of the page it says that there is a "configuration point" for org.apache.tapestry. specification-resolver-delegate and org.apache.tapestry. template-source-delegate - the explanations seem to point out that this is exactly what I need. So, I start thinking : how hard could it be to implement a couple of interfaces to just point to the directories I want and have it do it's magic. Well, it turns out, not as easy as it sounds.


  1. So, for the template resolver, I only need to implement this one interface, that should be easy

    public ComponentTemplate findTemplate(IRequestCycle cycle, IComponent component, Locale locale) { }






  2. Alright, I got right on it. Now, I only need to figure out how to produce a ComponentTemplate. I start digging through the Tapestry core source code, So, the constructor for ComponentTemplate looks like this:


    public ComponentTemplate(char[] templateData, TemplateToken[] tokens) {}


    OK, I can figure out how to produce a char array from a file, but these TemplateToken-s... At this point, I started realizing that this is not something that I should try to figure out from the top of my head, but rather go out and find an example that already implements the ITemplateSourceDelegate interface, surely somebody has done this before.



  3. So, I start digging around for an example. This is where it started getting scary. The first couple of links that come up talk about how nobody has really posted a good example of how this is done. Overall, the problem is that there is a boatload of "helper" objects (e.g. DefaultParserDelegate, TemplateParser, ComponentSpecificationResolverImpl, etc. the list goes for quite a bit) that you need to create before you can actually create an instance of this ComponentTemplate. On one hand, it all makes sense: Tapestry is a very modular framework, and you could potentially replace each one of it's pieces with some other component that implements the contract. On the downside, if you don't know much about the guts of Tapestry (e.g. for someone like me), digging into the guts is not that much fun.



  4. So, I say, I'll give the code that was posted on the mailing list, that should certainly work, especially since the responders say that they do work. Great, I copy-paste-compile.. and when I run my test Tapestry app (with a similar structure to a grails app - e.g. with WEB-INF/grails-app/views, etc)... a NullPointerException.. Luckily, Tapestry is open source, I dig into the source and I realize that I get the NPE when it's trying to log something.. So, do I need to inject a log into every object that I create ???



  5. This is when I realized that I just need to use the facilities that Tapestry uses to inject it's dependencies - namely, Hivemind. The thing is, I know nothing about it.. After reading up about it, it turns out that it uses these configuration points that you can use as well. So, my task moved from "copy and paste an example from the mailing list" to "figure out how this HiveMind thing works and then make it work for my ITemplateSourceDelegate implementation. I have read 2 books on Tapestry, but neither of them says anything about HiveMind (I admit, one was older, on Tapestry 3.0, the other one more focused on Tapestry itself, not its infrastructure). So, here is what I ended up using for my hivemind config file:
    <module id="id" version="0.0.1" package="package">
    <implementation service-id="tapestry.page.SpecificationResolverDelegate">
    <invoke-factory>
    <construct class="com.troymaxventures.grapestry.framework.ViewsSpecificationResolverDelegate">
    <set property="pagePath" value="grails-app/controllers"/>
    <set property="componentPath" value="grails-app/views"/>
    </construct>
    </invoke-factory>
    </implementation>

    <implementation service-id="tapestry.parse.TemplateSourceDelegate">
    <invoke-factory>
    <construct class="com.troymaxventures.grapestry.framework.ViewsTemplateSourceDelegate">
    <set property="grailsAppPath" value="WEB-INF"/>
    <set-service property="parser" service-id="tapestry.parse.TemplateParser" />
    <set-object property="contextRoot" value="infrastructure:contextRoot" />
    <set-service property="componentSpecificationResolver" service-id="tapestry.page.ComponentSpecificationResolver" />
    <set-object property="componentPropertySource" value="infrastructure:componentPropertySource" />
    <set-object property="rootOverride" value="app-property:grapestry-webapp-root-override" />
    </construct>
    </invoke-factory>
    </implementation>
    </module>


This hivemind configuration almost works for what I needed it to do in Grapestry. Unfortunately, it didn't get too far as the Grails test / development configurations work slightly differently than in production.

The general conclusion on the technology / Hivemind : it definitely seems like a cool dependency injection solution, especially in the way that it can dynamically aggregate modules and create a configuration on the fly (e.g. compared to Spring, where you have to explicitly say what goes into the config and how the different configs will interact). However, as with anything else, the high level of decomposition, where each class does only one job, and the many dependencies between the classes, make it sometimes difficult to figure out : e.g. if for a simple change like this, you have to track down 10 dependencies, that might have dependencies on their own, it sometimes makes you wish that the software you're trying to use wasn't as clean.

Friday, September 7, 2007

Grapestry progress and wishlist

I've been making some progress in making the Grapestry Grails plugin more integrated into Grails. Overall, it hasn't been quite a walk in the park, mostly due to the way Tapestry works. Here are a couple of things that would really be nice-to-have before Grapestry can really be usable as a Grails plugin:


  1. Tapestry templates (pages and components) should show up directly under the grails-app/views directory. Overall, the idea is that that's where Grails GSPs typically show up, and it would be most natural for Grapestry to do the same

  2. Tapestry page and component classes should live directly under grails-app/controllers. Overall, in Grails, the controllers are what process the requests. Since the page and component classes have the corresponding duty in Tapestry, so it would make sense to keep them there

  3. Since Grails emphasizes convention over configuration, creating pages should default to no page specification files. Everything that a page spec does should be accomplished using annotations (totally acceptable in regular Tapestry)

  4. Add groovy scripts and templates that would set up a default page template and page classes, e.g. something like 'grails create-grapestry-page' and 'grails create-grapestry-component'

  5. Add scaffolding similar to the one that exists in Grails controllers. It seems totally possible that there could be default methods like 'list', 'edit', etc on a grapestry page that would do the equivalent job of the Grails controllers with dynamic or static scaffolding

  6. Have some NetBeans support (hopefully coming in NetBeans 6.0) for Grails and Tapestry to make editing the Tapestry components in Groovy at least on par with doing them in Java



I did make some progress in accomplishing the first couple of bullets above. I kinda thought I had that down; however, it turns out that the "Development" grails configuration doesn't quite obey the same rules (it uses some resouce loaders that load resources directly from the ${app_dir}/grails-app/view and controllers directory), so I'm working on some workarounds for that.

Just yesterday, I got the Grails plugin account, but I still need to take a look at a standard grails plugin structure before I put anything out there.

Sunday, August 26, 2007

Grails + Tapestry = Grapestry ? Part 1 (of n)

I've been quite intrigued by the approach Grails takes to developing web apps. It really is very nice that Grails offers and end-to-end solution that provides the framework for the front end, services, and back end.

At the same time, I've been a big Tapestry fan, as it seems that it is the best web framework that I know about. I did read up about how Grails handles the front end, and although it provides decent support for developing the front end (with some cool integration into the whole Grails framework), but still not as nice as what Tapestry has. After all, the Grails front end is just a part of the puzzle; whereas, with Tapestry, that is it's primary goal (not to mention the whole difference between developing a "page-oriented" application with Grails compared with developing an application with a component based framework like Tapestry).

The bottom line is that Tapestry is perfect for quickly developing the front end of the app, and Grails is excellent in quickly developing everything else. The primary draw of Grails is it's use of GORM; yet, the whole integration with Spring, is also very nice. So, bottom line is, I need to have a Tapestry front end and a Grails back end.

I kinda had this idea in my head for a while, but the lucky event was that I stumbled on a blog post by Grame Rocher about integrating Wicket into Grails. It seemed straightforward enough, I asked him if he thought if Tapestry would be much different, he said "no", so, I thought, "Great, I'm going to rock on and build a cool Tapestry plugin for Grails".

As usual, it's easier said than done. It's probably been a couple of weeks since I've been able to get even close to having Grails and Tapestry work together. So, here are the steps, that I took along the way. When I come close to rounding this up, I'll probably release it somewhere (dev.java.net, sourceforge, google code, I'll have to see, I'm open to suggestions). Btw, my preliminary name for the plugin is Grapestry, it's temporary, but I have this idea about a logo that has a big juicy grape on top of a cake or something like that (get it, "Grape Pastry"? :-) ) . Btw, just to mention that the work so far really did take about half an hour to do (just like Graeme said). The "other stuff" is what took me much longer that I thought it would: maybe another couple of hours to understand where each grails-app subdirectory ends up when the app is packaged, a couple of hours on researching existing Grails plugin and figuring out how the whole Grails magic works , and then a LARGE number of hours actually doing the integration between Tapestry and Grails (the stuff that I'm going to blog about in the next posting)...

So, first things first. I followed Graeme's instructions on how to set up a plugin and how to do the basic plugin setup.

  1. Do the grails create-plugin to set up the basic directory structure, etc.

  2. Add the jars from the tapestry distribution into the plugin lib directory. Interesting problem that I had to deal with there was that Grails (the actual distribution, inside of $GRAILS_HOME/lib) had some common jars with Tapestry. Unfortunately, Tapestry 4.1.2 required later versions of those jars, so I had to copy those particular jars from the tapestry distribution into $GRAILS_HOME/lib, and remove (or temporarily rename the jars inside of the Grails lib directory). From the feedback that I got on the Grails forum, it seems like Grails doesn't have a way to dealing with dependency conflicts between what the plugin requires and what Grails requires. I am slightly negatively surprised by this, as Grails comes with a whole bundle of dependencies (it's 20+ Megs), and the chance that Grails might conflict with another jar version seems quite high. Oh, well, moving on for now, this is just one more item on my Grapestry ToDo list

  3. I edited the canned Groovy file that configures the plugin, and gives it a chance to do it's modifications inside of web.xml, the spring config, and whatever else (there are a bunch of ToDos here as well, I'll write more about this later). A couple of things to point out in the source:

    • The ejection of the controllers plugin : I'm not sure if this is necessary, it implies that if someone is using this plugin, they are totally not interested in using the Grails standard action handling. It seems that most Grails plugins are complementary to Grails, so, is this the right way to go ? I don't know, I'm not convinced.... Also, it seems that if this is a correct assumption, the whole Grails web layer (e.g. controllers, taglibs, AJAX) can be ripped out since it will not be necessary any more, all handled by Tapestry

    • The setup inside of web.xml is pretty standard, it's just a translation of a standard Tapestry web.xml into the Groovy xml builder format

    • The other interesting method that will most likely get some action is the doWithApplicationContext and doWithDynamicMethods. I looked at the controllers plugin, and that's where a lot of the Grails magic happens (e.g. dynamic scaffolding, a lot of default methods, etc), all things that are a must for my Grapestry plugin.





    class Grapestry2GrailsPlugin {
    def version = 0.1
    def dependsOn = [:]
    // This removes the Grails standard controllers plugin, which means that standard Grails actions and such would not work anymore.
    def evicts=['controllers']

    def doWithSpring = {
    // TODO Implement runtime spring config (optional)
    }
    def doWithApplicationContext = { applicationContext ->
    // TODO Implement post initialization spring config (optional)
    }
    def doWithWebDescriptor = { xml ->
    def servlets = xml.servlet[0]

    servlets + {
    servlet {
    'servlet-name'('tapestryapplication')
    'servlet-class'('org.apache.tapestry.ApplicationServlet')

    'init-param' {
    'param-name'('org.apache.tapestry.disable-caching')
    'param-value'('true')
    }


    'init-param' {
    'param-name'('org.apache.tapestry.application-specification')
    'param-value'('tapestryapplication.application')

    }


    'load-on-startup'(1)
    }
    }


    def mappings = xml.'servlet-mapping'[0]
    mappings + {
    'servlet-mapping' {
    'servlet-name'('tapestryapplication')
    'url-pattern'('/app')
    }
    'servlet-mapping' {
    'servlet-name'('tapestryapplication')
    'url-pattern'('*.html')
    }
    'servlet-mapping' {
    'servlet-name'('tapestryapplication')
    'url-pattern'('*.direct')
    }
    'servlet-mapping' {
    'servlet-name'('tapestryapplication')
    'url-pattern'('*.sdirect')
    }
    'servlet-mapping' {
    'servlet-name'('tapestryapplication')
    'url-pattern'('*.svc')
    }
    'servlet-mapping' {
    'servlet-name'('tapestryapplication')
    'url-pattern'('/assets/*')
    }
    }

    def filter = xml.filter[0]

    filter + {
    'filter-name'('redirect')
    'filter-class'('org.apache.tapestry.RedirectFilter')
    }

    def filterMapping = xml.'filter-mapping'[0]
    filterMapping + {
    'filter-name'('redirect')
    'url-pattern'('/')
    }



    }



    def doWithDynamicMethods = { ctx ->
    // TODO Implement additions to web.xml (optional)
    }
    def onChange = { event ->
    // TODO Implement code that is executed when this class plugin class is changed
    // the event contains: event.application and event.applicationContext objects
    }
    def onApplicationChange = { event ->
    // TODO Implement code that is executed when any class in a GrailsApplication changes
    // the event contain: event.source, event.application and event.applicationContext objects
    }
    }




  4. The next step is to actually, build some Tapestry artifacts to get the puppy going: a Tapestry page in Groovy, a page specification, and an html template

    • First, the Tapestry page implementation. Not much to talk about, just one persistent property to make sure that the annotations work, one simple action that makes sure that event dispatching works OK, and that one last action to make sure that GORM style object retrieval, etc works. Here is the pudding:

      package com.troymaxventures.grapestry.pages;

      /**
      *
      * @author akochnev
      */
      import org.apache.tapestry.annotations.Persist;
      import org.apache.tapestry.html.BasePage;



      public abstract class Home extends BasePage {
      @Persist
      public abstract int getCounter();
      public abstract void setCounter(int counter);


      public void doClick(int increment) {
      int counter = getCounter();

      counter += increment;

      setCounter(counter);
      }

      public void doClear() {
      setCounter(0);
      }

      public void saveSomething() {
      /*
      def b = new Foo(name:"Foo",url:"http://foo.bar.baz")
      b.save()

      println "Saved Bookmark2: " + Foo.get(1)
      */
      println "Called saveSomething"
      }
      }




    • The Tapestry page template , just some trivial markup with something to call into Tapestry:


      <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

      <html>
      <head>
      <title>My First Tapestry Page</title>
      </head>
      <body>

      <h1>My First Tapestry Page 3</h1>


      Date: <div jwcid="@Insert" value="ognl:new java.util.Date()">June 26 2005</div>
      <p>
      The current value is:
      <span style="font-size:xx-large"><span jwcid="@Insert" value="ognl:counter">37</span></span>
      </p>

      <p>
      <a href="#" jwcid="clear@DirectLink" listener="listener:doClear">clear counter</a>
      </p>

      <p>
      <a href="#" jwcid="@PageLink" page="Home">refresh</a>
      </p>

      <p>
      <a href="#" jwcid="by1@DirectLink" listener="listener:doClick" parameters="ognl:1">increment counter by 1</a>
      </p>

      <p>
      <a href="#" jwcid="by5@DirectLink" listener="listener:doClick" parameters="ognl:5">increment counter by 5</a>
      </p>

      <p>
      <a href="#" jwcid="by10@DirectLink" listener="listener:doClick" parameters="ognl:10">increment counter by 10</a>
      </p>

      <p>
      <a href="#" jwcid="saveSomething@DirectLink" listener="listener:saveSomething" >Save Something</a>
      </p>
      </body>
      </html>





    • Finally, the page spec:



      <?xml version="1.0" encoding="UTF-8"?>
      <!DOCTYPE page-specification PUBLIC "-//Apache Software Foundation//Tapestry Specification 4.0//EN"
      "http://jakarta.apache.org/tapestry/dtd/Tapestry_4_0.dtd">
      <page-specification class="com.troymaxventures.grapestry.pages.Home" >
      <!--property name="counter" persist="true" /-->
      </page-specification>








  5. Add a tapestryapplication.application application specification file to the web-app/WEB-INF folder, here's what it looks like for me:

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE application PUBLIC "-//Apache Software Foundation//Tapestry Specification 4.0//EN"
    "http://jakarta.apache.org/tapestry/dtd/Tapestry_4_0.dtd">
    <application name="tapestryapplication">
    <meta key="org.apache.tapestry.page-class-packages" value="com.troymaxventures.grapestry.pages"/>
    </application>





  6. OK, so far so good, this is all the right stuff we need to get it up and running. I was initially not looking forward to the magic that I'd have to do in order to get Tapestry work with the Groovy classloaders (as the Groovestry project (that might be dead) seems to do). Fortunately, Grails takes care of all that by compiling the Groovy classes into Good-Old-Java .class files, and so Tapestry doesn't have to know that the page is done in Groovy. Beautiful, isn't it ?

    I'm just going to wave my hands at this a little bit and just say that temporarily, we'll place the Home.java class in the com.troymaxventures.grapestry.pages package (and also mentioned in a tapestryapplication.application application config file). We'll also drop the Home.page specification, and the Home.html template into the $GRAPESTRY_HOME/web-app/WEB-INF directory. I know, that doesn't sound particularly fitting to the Grails philosophy of putting pages in the grails-app/views and controllers in grails-app/controllers , but there will be more on that in another blog post.



  7. Finally, do 'grails run-app' on the command line to get the app running, and go to http://localhost:8080/grapestry/app . That should pop a window that looks like this:


    Beauty divine !!! The standard Tapestry app should work, you should be able to click on some links, and see the persistent counter being updated.


Sunday, August 20, 2006

Tapestry NetBeans Plugin

This is repost of my original post - since it was linked by Geertjan and NetBeans weekly news at two different URLs, here it goes...:

I've read up a bit on Tapestry and I've followed Geertjan's blog for quite a while now. I've been a NetBeans fan for quite a while now (since 3.5), and Geertjan's blog has been really eye opening in what is possible with NetBeans. So, a while back, he was really excited about Wicket, and he started working on a plugin for developing Wicket apps in NetBeans. It appears that in the last few months, with the help of Petr they've built quite a nice set up to support Wicket in NetBeans.

What that means about me is that I will try to do something similar, but with Tapestry. What I will try to do is to develop a plugin that will support Tapestry development in NetBeans. Geertjan has already done most of the work here as he has covered a lot of the topics that are required to build a nice web framework support plugin for NetBeans. At the same time, as he seems to point out in one of his latest entries, the information that is required to build such a plugin is either scattered all over the net (or the NetBeans.org site), or is in the source code for his Wicket support plugin . Now that I'm trying to organize my thoughts about this project better, I start noticing that he's also done a great job of documenting his work and his progress along the way. However, I guess giving it a second run wouldn't hurt anyone.

I will probably try to put up a post that would list the proposed features for such a plugin. However, the idea is that the plugin should make working with Tapestry easier, maybe even to the point of not having to know all the nitty-gritty details of exactly how Tapestry works. It should probably have all the nice features of the Wicket plugin, translated into the Tapestry world.

One thing that I've considered in the past is to dig into the Spindle project (which is an Eclipse Tapestry support plugin which has an Eclipse specific and an Eclipse agnostic part) and try to adapt it to work for NetBeans. Now, the thing is that part of my goals includes learning the NetBeans APIs along the way. So, while sometime down the road, looking into using the Spindle implementation and putting up a NetBeans frontend to it would make sense, it appears that for now it would make the most sense to see about implementing the basics in NetBeans only...

I will also probably post more details on the steps required to accomplish this; however, after a few hours of playing around with NetBeans, the tutorials on the site, Geertjan's tutorials, as well as the NetBeans APIs, I've put together the first few things for the plugin... Here are a couple of screenshots that just give me an enormous adrenaline rush...


First, a blank Tapestry project, set up and ready to go (I wish I knew how to do this a while back at work, as with both Tapestry and JSF/Facelets I've always kept referring to a sample project that I know it works when I've done new projects...):


Geertjan is probably going to laugh at this one as this is dirt simple to do, but damn, it is nice to be able t accomplish this.




The next one is showing how the Tapestry framework is added to the list of supported frameworks in a standard NetBeans web project. I admit right off the bat that I took all the code from the Wicket plugin and replaced all references to Wicket with references to Tapestry. I still need to remove some of the config options here that really have nothing to do with Tapestry, but this is a very nice start (I was initially having some trouble getting the framework support in - I spent a good number of hours until I found out exactly how to register the framework in the IDE).





The last one is a list of a couple of new file types added to a project. Most likely, I will have to restrict them to Tapestry projects only, but it's a nice start again. THere is more work to be done to maybe create a graphical customizer for a Tapestry page, but still.. I'm pumped.. :-)


Tuesday, July 25, 2006

Tapestry Overview

When I was primarily doing struts and jsp development, I remember reading all these stellar Tapestry reviews and feedback, and was really planning to look into it a little further. In a few instances, I did look into the regular examples that were out there; however, at the time, I was not particularly impressed with it (that was before I looked at JSF). I mean that the syntax seemed to be pretty straightforward; however, there were all of these page and component definition descriptors that seemed to make things so much more verbose ( in a retrospect, I have to admit that at the time I was definitely not getting the idea of what a component oriented framework was all about).

So, maybe a year ago, I was a bit bored with what I'd been learning at the time ( I was kinda stuck in a rut and didn't seem to be learning much beyond the standard Struts/JSP stuff). So, I decided to learn about JSF, since it was a Java standard that seems to be pickup up speed pretty nicely. So, I sat down , read a couple of books on JSF and implemented a couple of projects with it at work and at school. It was definitely an improvement over Struts and a good learning experience. However, along the way I got to learn a couple of the not-so-savory sides of it as well. One of my biggest compaints is that it really smelled of a framework that was designed by a committed : the really simple stuff worked really nicely, it was easy to pick up and learn about; however, as soon as you started doing something not trivial (and I do mean it, not simple, but definitely not difficult stuff - e.g. selecting a row from a data table), you were immediately going up the creek... Although the framework was supposed to abstract you from the http implementation, I found myself having to deal with sessions, http requests and params, almost the same as struts... Somewhere along the way, I encountered Facelets, which was definitely an improvement over the standard JSF implementation and it was then when I realized how nice it was to have plain html implementation of the view using an extra html property for the tag to indicate framework components.

So, about a month ago, after listening to a JavaPosse interview of Howard Lewis Ship I finally decided to really give Tapestry a go. And so far, my impression is "WOW, what a refreshing and nice way to develop web apps". Although, there are a couple of things to learn from the get-go about how to start writing a Tapestry web app, after the initial slight learning curve, writing an app is really, really nice and easy. Especially now that with Tapestry 4.0 the xml descriptors can be by Tapestry annotations inside the actual page or component class makes it a less verbose.. Overall, the impression is that Tapestry came out of a practical need and evolved fulfilling all of these practical needs to make web app development more predictable and productive. Additionally, unlike JSF, Tapestry is not trying to do too many things in addition to simplifying web app development (e.g. JSF is trying to be able to have different view implementation by switching view handlers to do html, wml, and telnet). Thus, Tapestry is not unnecessarily complicated by 'possible' problems that one might have to solve when implementing web apps.

In summary, I will probably try to see what else Tapestry has to offer. So far, I really haven't have had to deal with any of the standard http/web protocols and it has been so wonderfully handled by the framework. The other day, just in a few hours, I was able to reimplement a struts app with Tapestry in a few hours. Additionally, what would have been really messy to implement before was really easy now and I found myself implementing new features that I had been thinking about in a very long time but never went ahead with it because of the mess I'd have to deal with had I had to do it in Struts. The only problem that I have encountered so far was that when I was deploying a tapestry app in JBoss 4.0.4RC1, it was giving me some errors due to the hivemind libraries being loaded multiple times (not a problem in Tomcat, as JBoss has a funny way of handling classloading). Finally, the 4.1 Tapestry release, promises a whole bunch of AJAX features that only vendor specific JSF implementation like Oracle ADF seem to offer ) and I'm really looking forward to seeing what it will bring to the table.

Thursday, July 20, 2006

Tapestry NetBeans plugin

I've read up a bit on Tapestry and I've followed Geertjan's blog for quite a while now. I've been a NetBeans fan for quite a while now (since 3.5), and Geertjan's blog has been really eye opening in what is possible with NetBeans. So, a while back, he was really excited about Wicket, and he started working on a plugin for developing Wicket apps in NetBeans. It appears that in the last few months, with the help of Petr they've built quite a nice set up to support Wicket in NetBeans.

What that means about me is that I will try to do something similar, but with Tapestry. What I will try to do is to develop a plugin that will support Tapestry development in NetBeans. Geertjan has already done most of the work here as he has covered a lot of the topics that are required to build a nice web framework support plugin for NetBeans. At the same time, as he seems to point out in one of his latest entries, the information that is required to build such a plugin is either scattered all over the net (or the NetBeans.org site), or is in the source code for his Wicket support plugin . Now that I'm trying to organize my thoughts about this project better, I start noticing that he's also done a great job of documenting his work and his progress along the way. However, I guess giving it a second run wouldn't hurt anyone.

I will probably try to put up a post that would list the proposed features for such a plugin. However, the idea is that the plugin should make working with Tapestry easier, maybe even to the point of not having to know all the nitty-gritty details of exactly how Tapestry works. It should probably have all the nice features of the Wicket plugin, translated into the Tapestry world.

One thing that I've considered in the past is to dig into the Spindle project (which is an Eclipse Tapestry support plugin which has an Eclipse specific and an Eclipse agnostic part) and try to adapt it to work for NetBeans. Now, the thing is that part of my goals includes learning the NetBeans APIs along the way. So, while sometime down the road, looking into using the Spindle implementation and putting up a NetBeans frontend to it would make sense, it appears that for now it would make the most sense to see about implementing the basics in NetBeans only...

I will also probably post more details on the steps required to accomplish this; however, after a few hours of playing around with NetBeans, the tutorials on the site, Geertjan's tutorials, as well as the NetBeans APIs, I've put together the first few things for the plugin... Here are a couple of screenshots that just give me an enormous adrenaline rush...


First, a blank Tapestry project, set up and ready to go (I wish I knew how to do this a while back at work, as with both Tapestry and JSF/Facelets I've always kept referring to a sample project that I know it works when I've done new projects...):


Geertjan is probably going to laugh at this one as this is dirt simple to do, but damn, it is nice to be able t accomplish this.




The next one is showing how the Tapestry framework is added to the list of supported frameworks in a standard NetBeans web project. I admit right off the bat that I took all the code from the Wicket plugin and replaced all references to Wicket with references to Tapestry. I still need to remove some of the config options here that really have nothing to do with Tapestry, but this is a very nice start (I was initially having some trouble getting the framework support in - I spent a good number of hours until I found out exactly how to register the framework in the IDE).





The last one is a list of a couple of new file types added to a project. Most likely, I will have to restrict them to Tapestry projects only, but it's a nice start again. THere is more work to be done to maybe create a graphical customizer for a Tapestry page, but still.. I'm pumped.. :-)


Popular Posts

Related Posts with Thumbnails