Wednesday, September 06, 2006

Tapestry directory layout with Maven2

I like Tapestry framework and Maven. But it's hard to use tapestry in maven web project without right directory layout.
And i decided to simplfy my life :)
I create such directory layout in my web maven project:





  • components - there're tapestry component templates(*.html) and definitions (*.jwc)
  • java -standart directory with java classes
  • pages - there're tapestry page templates(*.html) and definitions (*.page)
  • resources - standart directory
  • templates - there're velocity templates for email sending
  • webapp - standart directory


And ant plugin customization to copy all files to right place on project compilation.
You should add this code to pom.xml in plugins node.

<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<phase>compile</phase>
<configuration>
<tasks>
<copy todir="target/your-project-web/WEB-INF" flatten="true">
<fileset dir="src/main/pages" includes="**/*.page"/>
</copy>
<copy todir="target/your-project-web" flatten="true">
<fileset dir="src/main/pages" includes="**/*.html"/>
</copy>
<copy todir="target/your-project-web/WEB-INF" flatten="true">
<fileset dir="src/main/components" includes="**/*.jwc"/>
</copy>
<copy todir="target/your-project-web/WEB-INF" flatten="true">
<fileset dir="src/main/components" includes="**/*.html"/>
</copy>
<copy todir="target/your-project-web/templates">
<fileset dir="src/main/templates" includes="**/*.vm"/>
</copy>
<copy todir="target/your-project-web/WEB-INF" flatten="true">
<fileset dir="src/main/components" includes="**/*.script"/>
</copy>
<copy todir="target/your-project-web/WEB-INF" flatten="true">
<fileset dir="src/main/pages" includes="**/*.script"/>
</copy>
</tasks>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>


That's all - you can start tomcat or package war file with working tapestry project.

Sunday, September 03, 2006

AJAX with Tapestry using JSON-RPC

Once i was making user's agenda. For easy using i decided to make it using Ajax technology.

There's XTile component in Tapestry but you should write your own exception handler and thinking about in/out parameters and transforming it to java and javascript objects.

I found very easy way to create dynamic web application with JSON. And there's very good free library - JSON-RPC


To enable it in your tapestry project you should add jsonrpc-1.0.jar to you classpath and jsonrpc.js to your pages.

In web.xml add json servlet to enable remote calls





<servlet>

<servlet-name>com.metaparadigm.jsonrpc.JSONRPCServlet</servlet-name>

<servlet-class>com.metaparadigm.jsonrpc.JSONRPCServlet</servlet-class>

<init-param><br/>

<param-name>keepalive</param-name>

<param-value>0</param-value>

  </init-param>

<init-param><br/>

<param-name>auto-session-bridge</param-name>

<param-value>0</param-value>

  </init-param>

</servlet>

<servlet-mapping>

  

<servlet-name>com.metaparadigm.jsonrpc.JSONRPCServlet</servlet-name>

<url-pattern>/JSON-RPC</url-pattern>

</servlet-mapping>






Enabling json-rpc on client side:



jsonrpc = new JSONRpcClient("/JSON-RPC");




But in my case tomcat wrote jsessionid in url and if i created json without jsessionid, then on server side i lost current session in service object. I solved this problem so:



jsonrpc = new JSONRpcClient("/JSON-RPC<span jwcid='@Insert' value="ognl:sessId'/>");


In tapestry page i added this method:



public String getSessId() {

  return ";jsessionid=" + getRequestCycle().getRequestContext().getSession().getId();

}

Then create your main tapestry servlet:


public class StockwitApplicationServlet extends org.apache.tapestry.ApplicationServlet {

  public void init(final ServletConfig servletConfig) throws ServletException {

    JSONRPCBridge.registerLocalArgResolver(Visit.class, javax.servlet.http.HttpServletRequest.class,

new VisitResolver());

    JSONRPCBridge.getGlobalBridge().registerObject("eventService", new EventService());

  super.init(servletConfig);

}

...

}


 


You can see 2 methods:



  • registerLocalArgResolver - when you call your server side function you can pass different params from javascript side, but what if you want to pass some server side params for example user session, request or Visit object in Tapestry. For first ones there're existed resolvers in JSON-RPC library but for all other things you should write own resolver. I wrote Visit resolver for Tapestry framework:


    public class VisitResolver implements LocalArgResolver {

      public Object resolveArg(final Object context) throws LocalArgResolveException {

        if (!(context instanceof HttpServletRequest))

          throw new LocalArgResolveException("invalid context");


        final HttpServletRequest request = (HttpServletRequest) context;

         final Visit visit = (Visit) request.getSession().getAttribute("state:app:visit");

        if(null == visit || visit.getUserId() < 0) {

          throw new IllegalStateException("Your session is ended. Please login again.");

        }

        return visit;

        }

      }




  • registerObject - i registered my event service for remote calls. Now JavaScript side can call all public methods of this object.


    Server side Java object:
    public class EventService {

    public WeekEventVO getWeekEvent(final Visit visit, final Date currentDate) {

    final WeekEventVO weekEvent = new WeekEventVO();

    weekEvent.setName("some name");

    final List<IEvent> events = getEventHome().getWeekEvents(new Date(), visit.getUserId());


    for(IEvent event: events) {

    final EventVO eventVO = new EventVO();

    eventVO.setName(event.getName);

    dayEvent.getEvents().add(eventVO);

    }

    return weekEvent;

    }







    Javascript callback function (It's better to use async ajax):
    function drawWeekEvent(weekEvent, exception) {

    if (exception) {

    alert(exception.message);

    } else {

    var weekEventDiv = document.getElementById("weekEvent");

    weekEventDiv.innerHTML = weekEvent.name;

    }

    }


    And the last step is linking server side and client side:

    jsonrpc.eventService.getWeekEvent(drawWeekEvent, new Date());

    Where
    :

    • jsonrpc - main json object
    • eventService - name f service which you registered on server side
    • getWeekEvent - java object method name
    • drawWeekEvent - callback javascript function
    • new Date() - params, can be more than one param.


    But you see that our srever method has 2 params - Visit object and Date. There's no miracle, it's our VisitResovler sets visit param.
    JSON-RPC can convert simple java object to javascript object and complex like list, map, array.

    And if you want to get first event name from WeekEventVo object

    on client side, you should make such thing:

    weekEvent.events.list[0].name



    For detail documentation visit JSON-RPC site and i use very useful free firefox plugin FireBug to see which javascript objects are generated by JSON-RPC and for javascript debugging.

Thursday, August 31, 2006

Add jars to manifest file using Maven2

It's not easy to find how we can customize maven plugins.
There's poor documentation for plugins on maven site.
You should spend much time in maillist or looking plugin source codes to understand how you can customize plugin behavior.

Some time ago i wanted to make running my JARs more easy. I wanted to put all depending jars to manifest file. So i put in pom.xml such customization:




<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>fully.qualified.MainClass</mainClass>
<addClasspath>true</addClasspath>
</manifest>
</archive>
</configuration>
</plugin>



Now when maven packages my project it creates in manifest file classpath references:

Class-Path: antlr-2.7.6.jar commons-logging-1.0.4.jar ....

And I can easy start my jar without long classpath string just type: java -jar myproject.jar

Introduction

Hi everybody,
I'm starting this blog to share my experience in Java and relative technologies.
I'm java server side developer and I'll write in my blog about things I'm interested in :
  • ORM (Hibernate, TopLink)
  • Web frameworks (Tapestry, RIFE, JSF, Struts)
  • IoC (Spring, HiveMind)
  • AJAX (GWT, Yahoo, JSON RPC)
  • AOP
  • Building tools (Maven2, Ant)
  • IDE (IDEA, Eclipse)
  • and whatever i use and want to use
But if i find interesting thing in "desktop" word, i'll post such things too.

There're many tools, frameworks in java ocean and it's hard to choose right one. I think here we can find the right tool for every situation.