Loading...
i have been practicing test first development (from TDD) approach for last 1.5 years. i wrote a lot of junit test cases and wrote a lot of jmock based mock objects. it was amazing work with it these tools. specially jmock was fantastics and my most favorite mocking tool.
anyway, while i seriously started ruby on rails it is about 2/3 months ago, when i formed my own rails team and started working on first commercial rails project.
at the beginning i was working on IntelliJ IDEA 6M2 on windows environment, where i found running runit test cases are taking longer than we suppose to expect. it was really annoying.
good luck i got my mac book pro where i set up all rails stuff with IntelliJ IDEA 6M2. now i could see a lot more significant difference. now i am really feeling my test environment for rails project over this environment is running more than i expected. it really leads me to belief test driven approach over rails environment is really fast.
it must be some platform related significant changes, which only the expert on that platform can assure me.
by the way, i am really loving intelliJ IDEA and rails over my mac environment.
RESTful url may contain the content type with in the url string. For example: http://host/action/xml/bookmark. Here “xml” is content type, this content type can be changed to “text, json” or etc…
So following urls are valid too. http://host/action/text/bookmark, http://host/action/json/bookmark etc…
these days I am playing with “Stripes” web framework a lot. Those who didn’t get in touch with “Stripes” have a look on the following URL - http://stripes.mc4j.org, hope you will enjoy it.
stripes has fantastic flexibility, it enables a lot of customization. Now my tutorial will demonstrate how you can enable this url pattern, where your single “ActionBean” will be invoked on the following url patterns:
http://host/action/xml/bookmark, http://host/action/text/bookmark, http://host/action/json/bookmark etc…
My target audience:
Who has already been introduced with Stripes or those who are interested on stripes framework.
Routing plan:
Request Dispatch
[visitor] — > http://host/action/xml/bookmark — > [web server] — > [Stripe servlet] — > [Custom Action resolver] — > [remove user defined content type “xml” and retrieve action bean]
Response Dispatch
[clean url (after removing content type)] — > http://host/action/bookmark — > [BookmarkActionBean] — > [Resolution] — > < hello world/ >
Pre requisite:
Stripes servlet is configured and web context is up and running.
ActionBean code:
* create an ActionBean, for example “BookmarkActionBean”
< CODE >
@UrlBinding(”/action/bookmark”)
public class BookmarkAction implements ActionBean {
private final Log LOG = LogFactory.getLog(getClass());
private ActionBeanContext mActionBeanContext;
private String mContentType = “text/xml”;
public void setContext(ActionBeanContext actionBeanContext) {
mActionBeanContext = actionBeanContext;
// retrieve user requested content type constant for example “text,json, xml”
// convert consts to mime type “text, text/xml, application/JSON”
mContentType = URLHelper.getMimeType(URLHelper.getContentType(getContext().getRequest().getPathInfo()));
}
public ActionBeanContext getContext() {
return mActionBeanContext;
}
@DefaultHandler
public Resolution save() {
if (LOG.isDebugEnabled())
LOG.debug( “storing bookmark object on the data store, ” +
“response content type is requested - ” + mContentType );
return new StreamingResolution( mContentType, new StringReader(”< test/ >“) );
}
}
< /CODE >
Description:
Here i have set our action on “/action/bookmark” url, but our user requested url pattern is “/action/< contentTypeConstants >/actionBean”
Look on the “setContext” method, I have added an extra line
mContentType = URLHelper.getMimeType(URLHelper.getContentType(getContext().getRequest().getPathInfo()));
now have a look on the URLHelper class.
public static String getContentType( String pRequestedUrl ) {
String contentType = CACHED_URL_CONTENT_TYPE.get(pRequestedUrl);
if (contentType == null) {
contentType = DEFAULT_CONTENT_TYPE;
Perl5Util util = new Perl5Util();
if (util.match( REGEX_ACTION_CONTENT_TYPE, pRequestedUrl ))
contentType = util.group(1)+”";
CACHED_URL_CONTENT_TYPE.put( pRequestedUrl, contentType );
}
return contentType;
}
This method is responsible to retrieve user requested content type constants.
for example “text, xml, json”
public static String getMimeType( String pContentType ) {
// convert content type to MIME Type
if (pContentType.equalsIgnoreCase(CONTENT_TYPE_CONST_XML))
pContentType = CONTENT_TYPE_XML;
else if (pContentType.equalsIgnoreCase(CONTENT_TYPE_CONST_JSON))
pContentType = CONTENT_TYPE_JSON;
return pContentType;
}
This method is also converting constant to MIME content type.
For example “xml –> text/xml”
Now return to my base action bean. I have added the following method, which is defined as default handler.
@DefaultHandler
public Resolution save() {….
return new StreamingResolution( mContentType, new StringReader(”< test/ >“) );
}
Here “mContentType” is repopulate when “setContext” is invoked.
ActionResolver code:
This is my action resolver.
public class NBookmarkSystemActionResolver extends NameBasedActionResolver {
// ………
@Override
public ActionBean getActionBean(ActionBeanContext pActionBeanContext, String pRequestedUrl) throws StripesServletException {
String cleanUrl = URLHelper.getCleanUrl(pRequestedUrl);
if (LOG.isDebugEnabled())
LOG.debug( “user requested url - ” + pRequestedUrl + ” clean url - ” + cleanUrl);
return super.getActionBean(actionBeanContext, cleanUrl);
}
}
Now let’s have a look on “getCleanUrl” method.
public static String getCleanUrl( String pRequestedUrl ) {
return pRequestedUrl.replaceAll(”/”+getContentType(pRequestedUrl),”");
}
Custom ActionResolver configuration:
< filter >
< display-name >Stripes Filter< /display-name >
< filter-name >StripesFilter< /filter-name >
< filter-class >net.sourceforge.stripes.controller.StripesFilter< /filter-class >
< init-param >>
< param-name >ActionResolver.UrlFilters>< /param-name >>
< param-value >/WEB-INF/classes/>< /param-value >>
< /init-param >>
< init-param >>
< param-name >ActionResolver.PackageFilters< /param-name >
< param-value >com.we4tech.nBookmarkSystem.service.webService/*< /param-value >
< /init-param >
< init-param >
< param-name >ActionResolver.Class< /param-name >
< param-value >com.we4tech.nBookmarkSystem.configuration.NBookmarkSystemActionResolver< /param-value >
< /init-param >
< /filter >
That’s all for today,
Hope you will enjoy stripes. Best of luck…
hi,
at least i could manage some time to write about Stripes (http://stripes.mc4j.org/)
stripes is a web framework, it has very few dependencies, configuration over convention is highly adopted on Stripes.
you don’t need to bother about any separate XML file or properties file, it is as simple as web.xml servlet configuration. just put your all configuration over
more over it has default convention centric url discovery… for example “HelloAction”.. this action can be accessed over “http://
very flexible system. it has very simple work flow management, (who already familiar with JSF navigation or Spring web flow will be interested on its work flow)
by default it has multi action on each class, and you can override the url or any settings over @annotation. which is the most powerful feature over stripes.
web form validation is one of the nice and simple approaches over stripes. i am really loving it..
you can apply validation rule over @annotation. here is few example.. hope it will give you clean understanding.
@ValidateNestedProperties({
@ValidateNestedProperties({
@Validate( field = “accountName”, required = true, on = {”register”}),
@Validate( field = “password”, required = true, minlength = 6, on = {”register”})})
private User user;
@Validate( expression = “user.password == this”, on = “register”, required = true)
private String confirmPassword;
it has support over spring container, so spring developer won’t get you out…
best wishes…
http://hasan.we4tech.com







| www.flickr.com |
Leave a reply