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.