JavaOne: Practical Application of Aspects

Posted by ryan
at 2:59 PM on Wednesday, June 29, 2005



So after 4 long months of preparation for my JavaOne BOF I finally delivered it last night. While I can’t say I was too thrilled to get the 10:30pm time slot (I mean who wants to talk Java at 11:00 at night – not even geeks do), I’d say it went very well. The audience at least seemed engaged and interested in the topic judging by the quantity and quality of the questions. As I would tend to agree with my colleagues about the lack quality of presentations at JavaOne, I did my best not to be one of those.

I’m sure in one of the speaker waivers I signed I basically signed over my first born to Sun and they now own everything I’ve ever done related to aspects – but I’ll post the presentation up here for those that are interested. The target audience for the talk is what I would call a high-beginner level of knowledge about aspects. If that’s you it may be worth the download.

Practical Application of Aspects (PowerPoint)
Practical Application of Aspects (OpenOffice Impress)
Practical Application of Aspects (PDF)

Also, here’s the accompanying source files zip that accompany the presentation:

Practical Application of Aspects source files (zip)

Now that I have my life back I hope to be able to incrementally post a lot of the stuff I learned as part of the preparation for this talk, but no promises.

Define the Spring Framework w/o using "IOC" or "Dependency Injection" 4

Posted by ryan
at 12:45 PM on Thursday, February 03, 2005



I am often asked (i.e. once every other year) by my coworkers, “What is Spring”? I usually launch into a long-winded diatribe of what it is followed by how it’s used and what it allows you to do. Most people get it, but I have decided it’s time to solidify that base definition of Spring so that it can be taken, alone, as a concise yet accurate definition of Spring. The people who ask me this are often bright Java guys, just unaware of the base concepts of Spring, IOC etc… so the definition can’t contain any of those buzzwords typically associated with Spring (kind of like explaining what “the” means without using the word “the”). My first attempt looked something like this:

Spring is a framework for transparently forming relationships between objects.

Ok, that statement is accurate but hardly embodies the full power of the framework. The word “transparent” is key and should be kept. We should also convey it’s lightweight nature and maybe the fact that it allows for the interception of it’s wired components using aspects? (but let’s not use the word “aspect”):

Spring is a lightweight framework that allows for the transparent management, wiring and interception of application components.

Ok, that’s a pretty tight definition of the base Spring functionality. Remember, I’m not trying to tell somebody everything Spring can do in one sentence, I’m just trying to convey the major functionality and potential of the framework. I’d like to add something in there about Spring’s ability to both replace or work with J2EE technology as Spring’s documentation goes to great length to stress both:

Spring is a lightweight framework, working in concert with or replacing J2EE, that allows for the transparent management, wiring and interception of application components.

But it also works in concert with many other standard Java frameworks and specs such as Hibernate, JDBC etc…, not just “J2EE”:

Spring is a lightweight framework that allows for the complete abstraction and encapsulation of implementation-specific technologies, like EJB, JDBC, Hibernate and others, by providing the ability to transparently manage, wire and intercept application components.

I feel like that’s a pretty good stab at it. My only fear is that I’m so engrossed in the making of the definition that it makes perfect sense to me while making absolutely no sense to any other reasonable person. That’s where you come in.. thoughts?

Solving Swing's MVC Deficiencies 2

Posted by ryan
at 11:27 AM on Monday, March 22, 2004



The MVC design pattern is widely recognized as the preferred patter for developing UI-type applications, whether they be web applications or

more traditional client applications. While there are an abundance of widely accepted and quite mature MVC web frameworks, there are very

few for Swing applications. I believe this is because Swing does a good job of solving the “M” and the “V” portions of “MVC”, while leaving the “C” portion open.

Swing provides native support for using models, having a rich set of model interfaces and abstract classes for most of their UI components; I.e.

TableModel, TreeModel etc… Views are defined by the rich ui components that are driven by these models. It is when tying together the

interactions between the models and views (the controller portion) that Swing’s paradigm falls apart. Swing’s event/listener model is what can be

considered the controller part of the MVC, but is much too diffucult to maintain is it manifests itself as a graph of events and actions to listeners.

Thus Swing’s native controller is an unmaintainable myriad of event to listener to bound object relationships:

So while it’s clear that there is control logic, it’s all seperated between various listeners that are responsible for which bound objects to manipulate

upon which events. In addition, when forming these listener to event relationships you have to have a way to retrieve the reference to the actual

object you need to add the listener to. The same goes for getting the references to the bound objects that the listeners will need to manipulate.

What results is that you have to expose every object that wants to be a part of this system of events and listeners, independent of whether or not

it’s good design to expose these objects.

The first step to solving this problem is to consolidate the control logic into a more respectable, singular controller entity:

Instead of maintaining seperate listeners for every event, the controller has exposed methods to capture all system events and perform the

necessary response actions to the bound objects. While this consolidates the control logic, and forms a controller entity, it still does not clean up the

relationships between objects or the need to expose every object that needs to be part of this eco-system. I.e. the controller still must know of every

event and every bound object. What we need is a way for each event to log the event to a registry, and for each bound object to specify which

events they want to be notified of. Going even one step further, we need a more generic way for the bound objects to specify which events they

want to be notified of and not to refer directly to the event. This sounds a lot like the bus paradigm to me.

When an event occurs the object firing the event places an event message on the event bus. Any object that wishes to respond to an event can register itself with the event bus to be notified on the applicable events:

In this model, none of the events need to know anything about the bound objects and none of the bound objects need to know about the events.

And instead of having one big conglomeration of event/object bindings in the form of a controller, we can allow the bus to marshal event messages

to any object that cares about them. This offers the perfect seperation of logic without sacrificing flexibility.

In code I imagine this event model will manifest itself like so;

<i>Event firing object</i>
public void onEvent1() {
    EventBus.placeEvent(new Event("event1", this.eventContext));
}

<i>Event receiving object</i>
public void handleEvent(String eventId, EventContext context) {
    if(eventId == "event1") {
        aTextField.value = context.getProperty("userId");
    }
}

Thinking even further of the type of configuration and enhancements that could be applied here:

  • Events can be further organized by a heirarchical set of topics. So an event could be send on the “ui.mouse.movement” topic with an id of

    “panelHover”. Any bound object that has registered itself to listen to the “ui.mouse” topic would get notification of this event. This would make

    things like logging and other such wide-area functionality very basic to implement. The logging object would just register itself for the root or all

    (”*”) topic to receive notification of every event.
  • Using such frameworks as spring, or even utilizing aspect-oriented-programming, we can fully wire events to event bus to listening objects

    using an external XML configuration file. For instance, we can say which events are sent to which topics, and can then specify which objects

    listen to events of which topics. We can even specify which methods to execute when a particular event is received.
    <events>
        <event objectClass="com.ryandaigle.ui.MyButton" 
    eventClass="java.awt.ActionEvent" topic="ui.button" />
    </events>
    <receivers>
        <receiver-ref id="logger">
            <subscribeTopic id="ui.*" />
        </receiver-ref>
    </receivers>
    
    Now granted there is a lot here that I haven’t solved yet, but you get the idea.

I haven’t had a chance to look at how to maximize XWork in Swing, although

I’ve heard some rumblings about it recently. I’ve also been intrigued with Spring’s spring-rcf but have yet to see any code or documention for it.

My hope is that one of these two, or the combination thereof will implement a decoupled event bus-like model. It just seems to be the prefect model

for Swing/Java UI applications.

Frustrating Tomcat 5.5.x Issue Solved (conflicting jars...)

Posted by ryan
at 3:05 PM on Thursday, January 27, 2005



I’ve recently decided to move most of my web apps from a Tomcat 4.x platform to Tomcat 5.5.x (which also means moving to jdk 1.5). All went fine with Java-Frameworks.com (since decommissioned), but I ran into an issue when upgrading another app of mine. When I would access any page or action I would get the following stack trace:

SEVERE: Servlet.service() for servlet jsp threw exception
org.apache.jasper.JasperException: Unable to read TLD "META-INF/c-1_0.tld" from JAR file "file:/opt/java/jakarta-tomcat-5.5.4/webapps/bblmgr/WEB-INF/lib/standard-tags.jar": org.apache.jasper.JasperException: Failed to load or instantiate TagLibraryValidator class: org.apache.taglibs.standard.tlv.JstlCoreTLV
        at org.apache.jasper.compiler.DefaultErrorHandler.jspError(DefaultErrorHandler.java:50)
        at org.apache.jasper.compiler.ErrorDispatcher.dispatch(ErrorDispatcher.java:407)
        at org.apache.jasper.compiler.ErrorDispatcher.jspError(ErrorDispatcher.java:179)
        at org.apache.jasper.compiler.TagLibraryInfoImpl.<init>(TagLibraryInfoImpl.java:181)
        at org.apache.jasper.compiler.Parser.parseTaglibDirective(Parser.java:418)
        at org.apache.jasper.compiler.Parser.parseDirective(Parser.java:483)
        at org.apache.jasper.compiler.Parser.parseElements(Parser.java:1539)
        at org.apache.jasper.compiler.Parser.parse(Parser.java:126)
        at org.apache.jasper.compiler.ParserController.doParse(ParserController.java:211)
        at org.apache.jasper.compiler.ParserController.parse(ParserController.java:100)
        at org.apache.jasper.compiler.Compiler.generateJava(Compiler.java:146)
        at org.apache.jasper.compiler.Compiler.compile(Compiler.java:286)
        at org.apache.jasper.compiler.Compiler.compile(Compiler.java:267)
        at org.apache.jasper.compiler.Compiler.compile(Compiler.java:255)
        at org.apache.jasper.JspCompilationContext.compile(JspCompilationContext.java:556)
        at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:296)
        at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:295)
        at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:245)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:802)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:237)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:157)
        at com.opensymphony.module.sitemesh.filter.PageFilter.parsePage(PageFilter.java:129)
        at com.opensymphony.module.sitemesh.filter.PageFilter.doFilter(PageFilter.java:61)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:186)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:157)
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:214)
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:178)
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:126)
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:105)
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:107)
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:148)
        at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:825)
        at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.processConnection(Http11Protocol.java:731)
        at org.apache.tomcat.util.net.PoolTcpEndpoint.processSocket(PoolTcpEndpoint.java:526)
        at org.apache.tomcat.util.net.LeaderFollowerWorkerThread.runIt(LeaderFollowerWorkerThread.java:80)
        at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:684)
        at java.lang.Thread.run(Thread.java:595)

Ok, seems like I had run into this before… oh yeah, I needed to upgrade the apache commons standard tag library to the JSTL 1.1 version located (here). Ok, downloaded that and put it in the app’s lib dir. Let’s give it another go. Nope, getting this now:

org.apache.jasper.JasperException: Unable to read TLD "META-INF/c-1_0.tld" from JAR file "file:/opt/java/jakarta-tomcat-5.5.4/webapps/bblmgr/WEB-INF/lib/standard.jar": org.apache.jasper.JasperException: Failed to load or instantiate TagLibraryValidator class: org.apache.taglibs.standard.tlv.JstlCoreTLV
  at org.apache.jasper.compiler.DefaultErrorHandler.jspError(DefaultErrorHandler.java:50)
  at org.apache.jasper.compiler.ErrorDispatcher.dispatch(ErrorDispatcher.java:407)
  at org.apache.jasper.compiler.ErrorDispatcher.jspError(ErrorDispatcher.java:179)
  at org.apache.jasper.compiler.TagLibraryInfoImpl.<init>(TagLibraryInfoImpl.java:181)
  at org.apache.jasper.compiler.Parser.parseTaglibDirective(Parser.java:418)
  at org.apache.jasper.compiler.Parser.parseDirective(Parser.java:483)
  at org.apache.jasper.compiler.Parser.parseElements(Parser.java:1539)
  at org.apache.jasper.compiler.Parser.parse(Parser.java:126)
  at org.apache.jasper.compiler.ParserController.doParse(ParserController.java:211)
  at org.apache.jasper.compiler.ParserController.parse(ParserController.java:100)
  at org.apache.jasper.compiler.Compiler.generateJava(Compiler.java:146)
  at org.apache.jasper.compiler.Compiler.compile(Compiler.java:286)
  at org.apache.jasper.compiler.Compiler.compile(Compiler.java:267)
  at org.apache.jasper.compiler.Compiler.compile(Compiler.java:255)
  at org.apache.jasper.JspCompilationContext.compile(JspCompilationContext.java:556)
  at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:296)
  at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:295)
  at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:245)
  at javax.servlet.http.HttpServlet.service(HttpServlet.java:802)
  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:237)
  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:157)
  at com.opensymphony.module.sitemesh.filter.PageFilter.parsePage(PageFilter.java:129)
  at com.opensymphony.module.sitemesh.filter.PageFilter.doFilter(PageFilter.java:61)
  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:186)
  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:157)
  at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:214)
  at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:178)
  at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:126)
  at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:105)
  at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:107)
  at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:148)
  at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:825)
  at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.processConnection(Http11Protocol.java:731)
  at org.apache.tomcat.util.net.PoolTcpEndpoint.processSocket(PoolTcpEndpoint.java:526)
  at org.apache.tomcat.util.net.LeaderFollowerWorkerThread.runIt(LeaderFollowerWorkerThread.java:80)
  at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:684)
  at java.lang.Thread.run(Thread.java:595)

with a root cause of …

SEVERE: Servlet.service() for servlet jsp threw exception
java.lang.ClassCastException: org.apache.taglibs.standard.tlv.JstlCoreTLV
        at org.apache.jasper.compiler.TagLibraryInfoImpl.createValidator(TagLibraryInfoImpl.java:647)
        at org.apache.jasper.compiler.TagLibraryInfoImpl.parseTLD(TagLibraryInfoImpl.java:246)
        at org.apache.jasper.compiler.TagLibraryInfoImpl.<init>(TagLibraryInfoImpl.java:162)
        at org.apache.jasper.compiler.Parser.parseTaglibDirective(Parser.java:418)
        at org.apache.jasper.compiler.Parser.parseDirective(Parser.java:483)
        at org.apache.jasper.compiler.Parser.parseElements(Parser.java:1539)
        at org.apache.jasper.compiler.Parser.parse(Parser.java:126)
        at org.apache.jasper.compiler.ParserController.doParse(ParserController.java:211)
        at org.apache.jasper.compiler.ParserController.parse(ParserController.java:100)
        at org.apache.jasper.compiler.Compiler.generateJava(Compiler.java:146)
        at org.apache.jasper.compiler.Compiler.compile(Compiler.java:286)
        at org.apache.jasper.compiler.Compiler.compile(Compiler.java:267)
        at org.apache.jasper.compiler.Compiler.compile(Compiler.java:255)
        at org.apache.jasper.JspCompilationContext.compile(JspCompilationContext.java:556)
        at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:296)
        at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:295)
        at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:245)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:802)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:237)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:157)
        at com.opensymphony.module.sitemesh.filter.PageFilter.parsePage(PageFilter.java:129)
        at com.opensymphony.module.sitemesh.filter.PageFilter.doFilter(PageFilter.java:61)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:186)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:157)
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:214)
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:178)
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:126)
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:105)
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:107)
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:148)
        at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:825)
        at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.processConnection(Http11Protocol.java:731)
        at org.apache.tomcat.util.net.PoolTcpEndpoint.processSocket(PoolTcpEndpoint.java:526)
        at org.apache.tomcat.util.net.LeaderFollowerWorkerThread.runIt(LeaderFollowerWorkerThread.java:80)
        at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:684)
        at java.lang.Thread.run(Thread.java:595)\

After at least 2 and a half hours of trying the nightly builds of Tomcat and the standard tag libraries (when does that ever work – should have known better), I took a closer look at the last exception thrown above – ClassCastException. Don’t know why I had been mostly ignoring the significance of that exception, but it became clear to me that I probably had conflicting jsp/jstl classes on my classpath. Tomcat probably provided one set and my app another. Sure enough, I had included a “jsp-api.jar” in my application’s lib directory, and Tomcat had its own version in $CATALINA_HOME/common/lib. I removed the jar from my application and everything loaded just fine. I could have also just copied the version from Tomcat to my app, but since I didn’t need it there was no sense in keeping it around.

And so ends this particular hurdle, can’t wait to see what’s next.

In my googling for a solution to this issue there was very little out there – so I thought I’d better post it in case anybody else runs into this issue. Ascintillating it’s not, but hopefully it will be helpful.

This little tidbit may help find jars with conflicting class files – it’s how to use the Linux “find” and “xargs” command to do just that. If you’re on windows then… Cygwin?

List of Rejected JavaOne Topics...

Posted by ryan
at 4:51 PM on Tuesday, March 08, 2005



Like the front line of a civil war troop formation, the first wave of JavaOne presentation submissions have been mowed down. To track what Sun apparently doesn’t think is worthy of our time, here’s a list of topics known to have been rejected. This is less an excercise in public humiliation and more an excercise in making me feel like I have company in my futile Don Quixote-like quest.

Have one to add? Let me know about it. We can wallow in our sorrow and rejection together.

I guess I have to bite my tongue now :)

Adding Chaining Support to Spring Web MVC

Posted by ryan
at 11:52 AM on Tuesday, July 20, 2004



Having the ability to chain together independent and seperate modules of functionality as part of one line of execution is something I think is mandatory in an MVC framework, yet few support this powerful functionality (and even fewer support what I think is the proper definition of chaining). I started using Spring and the Spring Web MVC at work recently, and while I think Spring is great in how it allows, provides and forces proper design habits, its MVC framework isn’t quite as mature. First among my wishlist of unsupported features is chaining.

So why is chaining essential to any proper MVC framework? It is a failure of any framework to assume that one “action”, i.e. logging a user in or saving a piece of data, has only one linear line of execution. Each logical action is really composed of a series of decisions and calls, and each endpoint of an action can vary based on its context of caller. With Spring you can pull out each piece of logic into it’s own object and inject them into the one controller that handles that particular action. This is good in that it properly seperates each bit of logic, but it encompasses all the branching logic between the various pieces into one controller, which isn’t reusable at all. Chaining lets us keep the modularity of the above solution while letting each invocation dictate the branching logic.

First, let me explain what I think the ideal implementation of chaining is.

  • Each link of the chain must be independent from the others and completely pluggable into a chain at any point.
  • Each link of the chain doesn’t return the next link, but rather a result identifier that indicates (in business logic vocabulary) the result of it’s particular chunk of execution.
  • Each link of the chain can have its results interpreted differently depending on the context of its execution (i.e. depending on which chain it’s included in)
  • Each link of the chain has its own set of validation rules and dependencies.
  • Each chain should have its own session that allows each link to place domain objects and other indicators that may be used by future links.

So how do we make Spring support chaining? Since Spring takes control of execution from each controller using the ModelAndView object, we have to embed the chaining within the controllers themselves. While having a controller be a facade to chaining has its own set of disadvantages (discussed later), it at least gives us most of what we’re looking for. The basic idea is that a controller that has complex or branched logic calls a chain in its doSubmit or applicable execution method, gets the result of the chain (in Spring’s case a ModelAndView) and hands it back to Spring. The controller is still responsible for the handling binding and validation, but submit execution is the reponsibility of its chain.

Since the concept of a chain is one not specific to Spring, most of the chaining classes aren’t dependent on Spring. All results and endpoints are Objects and are only cast to ModelAndViews within Spring controllers.

If we look at what we need a chain to do, it’s really quite simple. Here is the Chain interface:

public interface Chain {
    public Object executeChain(ChainableSession session)
      throws Exception;
}

All we ask of a chain is to execute and return a result. The ChainableSession is a wrapper for the request and response and also holds variables for access only within the context of the chain’s execution. A chain is really just an entry and exit point for the series of links, or Chainables, that make up the chain. Each link performs an action and returns a result of that action which can be used to determine the next link to execute. Let’s look at the Chainable interface:

public interface Chainable {

    public ChainableResult execute(ChainableSession session)
      throws Exception;

    public Chainable getNext(ChainableSession session,
            ChainableResult thisResult);
}

A Chainable is responsible for executing an individual or logical action and returning a result which states whether or not to continue with the chain. If the chain should continue execution, the Chainable is asked for its next link. You’ll note that the execute method only takes a ChainableSession. At one point I had it also taking the previous Chainable that was executed, but that would violate the independence of each link. Each chainable should be pluggable into any chain without having a dependency on a previous chainable. Now the chainable session can contain items from previous executions, but no explicit dependence on a previous chainable should exist. It is the responsibility of the chain’s caller to instantiate a session for the chain. This should be used to put things like the command object in the case of a simple form controller, or other runtime objects provided by the various Spring controllers that are needed by the chainables.

The getNext method determines what Chainable should be executed next. As a Chainable should be thread safe, the only items used to determine the next link should be the session and the result of this execution. The result contains a result id object that can be used to encapsulate any compound identifier needed when determining the next chainable. Let’s look at the ChainableResult interface:

public interface ChainableResult {

    public Object getResult();

    public Object getResultId();

    public boolean continueChain();
}

The difference between the result and the result id is simple. The result id identifies the outcome of the chainable’s execution and should be used in determining the next link of the chain. The result object is the result of the execution that’s returned when the chain completes execution. In the context of Spring, this will often be the ModelAndView. If a chain does not return a result, then it will be assumed that the response has been handled internally.

One thing we haven’t looked at is the ChainableSession. As I mentioned earlier, this is merely a wrapper for the request and response and a way to store items within the context of a chain’s execution.

public interface ChainableSession {

    public static final String ATTR_COMMAND = "COMMAND";

    public HttpServletRequest getRequest();

    public HttpServletResponse getResponse();

    public void setSessionAttribute(Object attributeKey,
              Object attribute);

    public Object getSessionAttribute(Object attributeKey);
}

The only thing of any interest is the ATTR_COMMAND static variable which is used to identify the Spring command object within the session. I don’t really like this variable here because 1) it’s spring specific and 2) it’s not a very flexible way to define such keys. If you have any ideas, let me know, I just hadn’t had the time to look at this particular issue yet.

Ok, so we have the pieces to make a chain, how do they fit into the controller paradigm? I’ve include a few simple controller implementations for convenience, but they’re really quite simple. Here’s the ChainableSimpleFormController implementation:

public class ChainableSimpleFormController extends SimpleFormController {

    private Chain chain;

    protected ModelAndView onSubmit(HttpServletRequest request,
              HttpServletResponse response,
              Object command,
              BindException errors)
              throws Exception {

        ChainableSession session =
          new ChainableSessionImpl(request, response);        
        session.setSessionAttribute(ChainableSession.ATTR_COMMAND,
          command);        
        return (ModelAndView) chain.executeChain(session);
    }

    public void setChain(Chain chain) {
        this.chain = chain;
    }
}

So how would this look in the spring-servlet.xml bean configuration file? Well let’s set up a scenario. In my case, we have an application that performs a series of branching decisions based on a user’s role and their access to any number of sites.

  1. If the user doesn’t have access to any sites, then display an error.
  2. If the user has access to one site then evaluate their permissions
    1. If the user has the super role, then display the site selection interface
    2. If the user has the site-only role, then display site information interface
  3. If the user has access to more than one site then display the site selection interface
We can see that there are three branch points, site access, number of sites, and role. If we make a chainable for each, we can string them together as independent, reusable modules. And in several scenarios within this application I’m able to reuse these chainables as part of a different chain. Let’s look at how the first of the chainables are configured.

<bean id="siteAccessChainable" 
  class="com.demo.web.chainables.SiteAccessChainable">
  <property name="noSitesResultId">
    <value>noSites</value>
  </property>
  <property name="hasSitesResultId">
    <value>hasSites</value>
  </property>
  <property name="resultMappings">
    <map>
      <entry key="noSites">
        <ref bean="noSitesViewEndpoint" />
      </entry>
      <entry key="hasSites">
        <ref bean="userSitesChainable" />
      </entry>
    </map>
  </property>
</bean>

<bean id="noSitesViewEndpoint" 
  class="springx.web.webmvc.chainables.ViewEndpointChainable">
  <property name="view">
    <value>error.jsp</value>
  </property>
</bean>

<bean id="userSitesChainable" 
  class="com.demo.web.chainables.UserSitesChainable">
  <property name="oneSiteResultId">
    <value>oneSite</value>
  </property>
  <property name="manySitesResultId">
    <value>manySites</value>
  </property>
  <property name="resultMappings">
    <map>
      <entry key="oneSite">
        <ref bean="..." />
      </entry>
      <entry key="manySites">
        <ref bean="..." />
      </entry>
    </map>
  </property>
</bean>

These chainables are using an abstract chainable provided for convenience (AbstractResultIdBasedChainable) that lets us map a result id (in this case a string) to the next chainable to execute for that result. Since the results are seperated from the chainable bean, we can create a new bean if another chain has different branching logic. The noSitesViewEndpoint is how we can specify that the end of the chain has been reached and the given view should be displayed. We could just pass in the view to the chainable as a property, but that would limit the flexibility of the chainable since it assumes that that specific result will always want to go to a view.

Now all we have to do is define the chain, which is merely iterates over the sequence of chainables starting with the root chainable, and give that chain to the proper controller.

<bean id="siteAccessChain" 
  class="springx.web.webmvc.chain.impl.ChainImpl">
  <property name="root">
    <ref bean="siteAccessChainable" />
  </property>
</bean>

<bean id="startController" 
  class="springx.web.webmvc.controllers.ChainableController">
  <property name="chain">
    <ref bean="siteAccessChain" />
  </property>
</bean>

Hopefully that brings our little example to closure. I’ve tried to cram a lot of info about chaining into this post, and I hope it was with some clarity. The point of all this is to provide a way to seperate and modularize cleary independent branch points within the context of one action’s execution. There are several issues with the solution I’ve presented that I hope to address in the future. Here are some of them:

  • The ChainableSession is specifically tied to the HttpServletRequest and HttpServletResponse. Ideally a chain would be environment independent and could be used in dekstop swing apps etc… But seeing as how this is in the context of a Spring web-app, this is somewhat acceptable now.
  • There needs to be a cleaner, more extensible way to defined chainable session attribute keys.
  • It would be nice if the ChainableResult beans could be defined in the spring config files, right now I have them instantiated within each chainable
  • Each chainable should have it’s own binding and validation, instead of still having that done at the controller level. This way each chainable is a completely portable and self-contained unit.
Any suggestions on the above are welcomed.

The Goods
The springx.web.webmvc classes can be downloaded here. There’s not much documentation provided beyond what I’ve explained here, so feel free to pull it out and start playing.

How To Integrate Spring with WebWork 2

Posted by ryan
at 12:48 PM on Monday, March 08, 2004



This article has since been moved to the WebWork 2 wiki.

I recently started to work with WebWork 2, Spring and Hibernate 2 in an effort to utilize some of the more popular open source frameworks and libraries out there. While the Hibernate 2 documentation was quite complete and integration efforts went smoothly, as did getting WebWork 2 set-up, getting Spring integrated with Webwork 2 (or vice-versa actually) turned out to require some tweaking.

I started out using the original WebWork documentation to get Spring to initialize Webwork actions, but it appears that a lot has changed since the days of WebWork 1.x. This will be my attempt to clarify some of those changes and to list the steps necessary to get the two to play nicely. Please comment with clarifications or corrections!

WebWork 1.x (these are assumptions based on the 1.x documentation mentioned above)
It seems that the way you got Spring to initialize WebWork 1.x action classes was to add this line into your webwork.properties file:

webwork.action.factory=webwork.action.factory.SpringActionFactory

so that WebWork would know to use Spring’s view of the world to create actions. The WebWork action classes would then need to be declared in the Spring applicationContext.xml file so that Spring would know directly of the action objects. Upon invocation of an action, WebWork would know to first use the SpringActionFactory to try and create an instance of the requested action which would ask Spring to create the object using its configuration. If there was no Spring definition of that action object, then WebWork would use it’s normal instantiation methods to create that action. Well, things have changed slightly since WebWork 1.x.

WebWork 2 In WebWork 2 (the functionality actually exists in XWork), you specify relationships from action classes to other objects in XWork’s xwork.xml file instead of Spring’s applicationContext.xml file. So if you have an action class that utilizes a DAO, instead of having a bean definition like so in applicationContext.xml:

<bean id="myAction" class="com.ryandaigle.web.actions.MyAction" 
singleton="false">
  <property name="DAO">
    <ref bean="myDAO"/>
  </property>
</bean>
<bean id="myDAO" class="com.ryandaigle.persistence.MyDAO" 
singleton="true" />

you move the action definition to xwork.xml and keep the DAO definition in applicationContext.xml so that xwork.xml looks like:

<action name="myAction" 
class="com.ryandaigle.web.actions.MyAction">
  <external-ref name="DAO">myDAO</external-ref>
  <result name="success" type="dispatcher">
    <param name="location">/success.jsp</param>
  </result>
</action>

and applicationContext.xml looks like:

<bean id="myDAO" class="com.ryandaigle.persistence.MyDAO" 
singleton="true" />

Notice how there is the external-ref element in the action definition that points to an object that Spring is managing. There are several things that need to be in place for the external-ref to work, but I just wanted to give an overview of what has changed before going into the specific steps.

Steps for Configuring Spring/WebWork (XWork) Integration:

  1. Get the files you need to externally resolve Spring beans. I’ve bundled them all here. They were originally spread between two JIRA issues filed against XWork 1.0 (see references below). This zip includes the source, the class files (so you can just include it in your classpath) and my example configuration files. Either extract the source files into your application, or put the file onto your classpath. (You may want to take the applicationContext.xml and xwork.xml files out, I don’t know if they’ll override your files… They’re just there as an example configuration).
  2. Now, let’s get your XWork configuration file (xwork.xml) to resolve external references. XWork resolves external references (using the external-ref element) by utilizing an external reference resolver per package. You specify your external reference resolver as an attribute of the package element:
    <package name="default" extends="webwork-default" 
    externalReferenceResolver=
    "com.atlassian.xwork.ext.SpringServletContextReferenceResolver">
    
    This SpringServletContextReferenceResolver class reference is a class not part of the XWork distribution written as an extensions for XWork/Spring that I got from this JIRA issue filed against XWork addressing this Spring integration effort. (I have bundled it with the rest of the necessary files later on down for your convenience). This class will intercept all external-refs and resolve the references using Spring’s context. There is also a SpringApplicationContextReferenceResolver included in the zip file that will allow you to resolve Spring references for applications not executing within the web context. But as this is a WebWork/Spring article, the servlet resolver is what we need to use.
  3. Now we need to add the XWork reference resolver as part of the interceptor stack you’re using. This will allow any references to be resolved (using the reference resolver you specified in the externalReferenceResolver attribute). This is how I’ve added that interceptor:
    <interceptors>
      <interceptor name="reference-resolver" class=
    "com.opensymphony.xwork.interceptor.ExternalReferencesInterceptor"/>
      <interceptor-stack name="myDefaultWebStack">
        <interceptor-ref name="defaultStack"/>
        <interceptor-ref name="reference-resolver"/>
      </interceptor-stack>
    </interceptors>
    <default-interceptor-ref name="myDefaultWebStack"/>
    
  4. As I briefly outlined before, you can now reference Spring beans that your action classes need in xwork.xml:
    <action name="myAction" 
    class="com.ryandaigle.web.actions.MyAction">
      <external-ref name="DAO">myDAO</external-ref>
      <result name="success" type="dispatcher">
        <param name="location">/success.jsp</param>
      </result>
    </action>
    
    And that’s all we have to do to xwork.xml to let XWork know how to resolve references to Spring’s managed beans.
  5. Now let’s setup our web environment to properly notify Spring and our external reference resolver of the web context. We do this by adding two context listeners to your application’s web.xml file:
    <listener>
    <listener-class>
    org.springframework.web.context.ContextLoaderListener
    </listener-class>
    </listener>
    <listener>
    <listener-class>
    com.atlassian.xwork.ext.ResolverSetupServletContextListener
    </listener-class>
    </listener>
    
    The first listener is Spring’s that you would need independent of whether or not you were integrating with WebWork 2. The second listener is our external resolver’s that will use the servlet context to retrieve Spring’s application context. This is the link between WebWork and Spring.
  6. At this point, we’ve set up Spring and our XWork reference resolver to work within a web context, and we’ve told XWork how to resolve external references to Spring. We’re done! Fire it up and let me know if there are some steps I’ve missed or assumptions I’ve made that I shouldn’t have.

References
- Here is my bundled source, class and example configuration files (that contains all the needed referenced files below); webwork2-spring.jar
- My searching started with the original WebWork 1.x + Spring documentation and comments on the Wiki; http://wiki.opensymphony.com/comments/Spring+Framework+Integration
- The Wiki pointed me to the two JIRA issues that contained the source files for the reference resolvers:

Credits
Judging by the comments etc… of the JIRA issues filed against XWork, it appears that Ross Mason (of Atlassian?) is the man to thank for the external reference resolver code. And of course we have to thank the people of Spring and WebWork 2 for making this all possible.

Please let me know if I’ve missed anything.

My JavaOne Submission ... Accepted!

Posted by ryan
at 8:41 AM on Wednesday, March 16, 2005



I guess after the somewhat sarcastic and critical tone of my previous post, I have no room to gripe anymore… my final submission to JavaOne has been accepted. It is entitled “Practical Application of Aspects in Everyday Development” – I hope it’s something that peaks your interest…

Just to wet your appetite, here’s the summary from the submitted abstract:

Aspect Oriented Programming (AOP) is a recent shift in software development that allows for transparent injection of functionality into standard object oriented designs. While obviously a very powerful concept, it seems to still be limited to very specific types of frameworks and not yet harnessed as an integral part of the developer’s toolkit. Frameworks such as the Spring Framework and PicoContainer utilize aspects to provide powerful transactional and runtime binding functionality, but are aspects limited to these types of container frameworks? This discussion will focus on the practical applications of aspects in everyday programming scenarios and the types of problems they can solve. From the transparent injection of logging to the validation of method parameters, aspects can be used as a standard part of everyday development.

Right now the talk is slated to be a Birds-of-a-Feather session which means it will be a pretty informal 50-minute evening talk with about 150 attendee slots. Time to start prepin’....

I originally thought I was being pretty damn over achieving by submitting 3 proposals to JavaOne, of which only one got accepted. But then you’ve got Debu Panda over there who got 3 submissions accepted – who knows how many he submitted? Well done, man.

The Need for Another Type of J2EE Object Scope 0

Posted by ryan
at 11:21 AM on Thursday, March 18, 2004



So it seems like directly manipulating the session is the defacto way to store cross-request objects in WW2 (and every other paradigm?) [see my previous post]. (Thanks for the advice, Jason. It’s active community involvement like this that makes projects such as yours and many other so successful). This got me thinking that the default scopes provided by the J2EE spec are pretty limiting, and that a good framework should provide a way to define intermediate scopes. Specific to WebWork 2, it seems like what needs to be defined is a lifespan of the various properties of the action. In my case I wanted the user property to span several actions. How about having property scopes defined in the xwork.xml like so:

<action ...>
  <property name="user" scope="session" />
  ...

This allows the scope of each property to be defined outside the actual action without the need for directly manipulating session maps etc…. However, it is not as flexible as to allow the lifespan or scope to be set to a finite number or types of actions. What we need is a kind of a scope in between a request and a session. How about being able to define an action sequence as a scope in xwork.xml?

<scopes>
  <scope type="actionSequence" name="userSequence">
    <action-ref name="getUserAction" />
    <action-ref name="saveUserAction" />
  </scope>
</scopes>

Then scoping your action properties like so:

<action name="getUserAction" ...>
  <property name="user" scope-ref="userSequence" />
  ...
</action>
<action name="saveUserAction" ...>
  <property name="user" scope-ref="userSequence" />
  ...
</action>

When the two requests occur in sequence or are chained, the user property of each action will be assured to be the same object. This would allow the flexibility of defining object lifespans beyond the limited request/session/application scopes that are now provided.

You could even go one step further and allow regular expressions when defining the action-ref attribute of each scope, so that all actions of a certain family can be grouped:

<scopes>
  <scope type="actionSequence" name="userSequence">
    <action-ref name="*UserAction" />
  </scope>
</scopes>

Just seems like a way to tightly define specific property lifespans within the context of the application flow… Comments are welcome.

Java-Frameworks.com is no more

Posted by ryan
at 9:40 AM on Tuesday, September 20, 2005



My little frameworks experiment is coming to an end… Java-Frameworks.com started out as my little personal repository of java utilities, frameworks and libraries that was open to anybody (think a lightweight version of sourceforge with project dependency linking). Rather than keep it around knowing I’m not going to add any functionality or fix any bugs I’ve decided to take it off the air. I have backups of all the projects, so let me know if you need something off of there and I’ll see what I can do.

Here is a listing of all of my little projects that were hosted there (most are several years old and have better alternatives, but for posterity sake….):

  • JDBC Execution Framework v1.1.4: “This is a flexible framework that will remedy the repetition of interacting with a JDBC compliant database. Note: The original form of the framework is outlined in this JavaWorld article. It has since been modified for more flexible use.” [depends on Common Utilities v1.2]
  • Spring Web MVC Chain Extension v1.0.1: see here for summary.
  • Directory Watcher v1.1: “This is a set of utility classes that will monitor a specified directory for any changes to that directory (i.e. additions, deletions or modifications). The monitor will listen to the directory, pinging it for changes on a developer specified time interval. The monitor can accept generic resource listeners, which will be notified when an event occurs on the directory.” [depends on Common Utilities v1.2]
  • Web App Flow Framework v1.1.1: “This is a framework designed to take the repetition out of servlet based application programming. This framework forms an application into a series of request handlers. The flow of each request can then be configured in an XML file that specified which handlers will be called on which requests. The idea is to have several handlers that perform logical independent tasks. By stringing a series of independent handlers together, different chains of reusable functionality can be achieved.” [depends on Common Utilities v1.2 and dom4J]
  • Web App Security Framework v1.0.2: “This framework is designed to provide a way to specify reource level security for a web application. Resources may include jsp pages as well as individual classes. The security of each resource is specified external to that resource, thus seperating the security from the business logic.” [depends on Common Utilities v1.2 and dom4J]
  • Cache Framework v1.0: “This caching framework allows you to build a simple, type-independant caching mechanism with developer specified key types.” [depends on Common Utilities v1.2 and Log4J]
  • Pool Framework v1.0: “This is a framework that will allow for type independent pools to be built very quickly. The common functionality of pooling mechansims has been factored out into a set of clean interfaces and abstract classes. All a developer of a pool needs to code is the factory methods for creating a new poolable item.” [depends on Common Utilities v1.2 and Log4J]
  • Common Utilities v1.2: “Simple utility classes such as NestedException and others…”

It’s funny to look back on work I’ve done in the past and see how different things are now a days. Who writes their own web MVC framework now? JDBC … what’s that?

Pretty URLs (Rails style) with WebWork

Posted by ryan
at 10:39 AM on Friday, January 13, 2006



I recently had to develop a way to provide for non-parameterized URLs in a WebWork (2.1.x) application. Non-parameterized URLs are those that don’t have the endless list of ?key1=value1&key2=value2 parameters attached to the URL and instead have the nice tidy Rails style URL like ../key1/value1/key2/value2.

Besides being much prettier, this style of URL also helps with search engines as some don’t like to index pages with too many parameters specified (or with an “&id” parameter). When the parameters appear as part of the URL, everybody is happy.

WebWork v2.1.x doesn’t exactly have a nice plugin point to introduce this behavior, so the actual dispatcher servlet needs to be modified to parse URLs of that format. Just so happens there is a very undocumented version of the dispatcher servlet called com.opensymphony.webwork.dispatcher.CoolUriServletDispatcher that attempts to provide just such behavior (thanks, Jim). However, it puked up some String.substring() index out of bounds exceptions when I gave it a spin. I have a feeling its parsing of the URL was very dependent on the request mapping configuration in the web.xml (which is a hairy task). So, what else was I to do but create my own?

My version is pretty similar to the CoolUriServletDispatcher that’s included with WebWork except that it has some enhancements:

  1. doesn’t throw a String.subtring index out of bounds exception on my deployment ;)
  2. can handle conventional actionName.action (or any other extension) url formats
  3. assumes a format of actionName/value to set the id property on the action and NOT to set the id property on the actionName property of the action
  4. can simultaneously handle both pretty url parameters (/key1/value1…) and conventional parameters (/key1/value1?key2=value2)
Here are some quick usage guidelines:
  • Conventional requests will be handled as always:
    http://HOST/CONTEXT/ACTION_NAME.action?id=1&key1=value1
    will be handled by the ACTION_NAME action with the given parameters
  • Pretty urls in this format (when using both conventional and pretty url formats):
    http://HOST/CONTEXT/link/ACTION_NAME/id/1/key1/value1
    will be handled by the ACTION_NAME action with parameters (id=1, key1=value1)
  • Pretty urls in this format (when using both conventional and pretty url formats):
    http://HOST/CONTEXT/link/ACTION_NAME/id/1?key1=value1
    will be handled by the ACTION_NAME action with parameters (id=1, key1=value1)
  • Pretty urls in this format (when using both conventional and pretty url formats):
    http://HOST/CONTEXT/link/ACTION_NAME/1?key1=value1
    will be handled by the ACTION_NAME action with parameters (id=1, key1=value1)
  • When only the pretty url format is used and all requests are mapped to this dispatcher servlet, the /link portion can be removed and you will see the same functionality:
    http://HOST/CONTEXT/ACTION_NAME/id/1/key1/value1
    will be handled by the ACTION_NAME action with parameters (id=1, key1=value1)
    Same goes for: http://HOST/CONTEXT/ACTION_NAME/1/key1/value1

I’ve attempted to make the javadocs quite complete, so I’ll point you there for further documentation: UriMappingServletDispatcher javadocs.

And here is the actual servlet file (actual source is attached at the end of this entry as well):

UriMappingServletDispatcher.java (for Java 5)
UriMappingServletDispatcher.java (for Java 1.4 and below)

It should be noted that the recently released WebWork v2.2 does have an ActionMapper plugin point and a RestfulActionMapper implementation that does this very thing, so go use that if you can.



Actual source:

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.security.AccessController;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import sun.security.action.GetPropertyAction;

import com.opensymphony.webwork.dispatcher.ServletDispatcher;
public class UriMappingServletDispatcher extends ServletDispatcher {

    private static final long serialVersionUID = 1L;

    private static final String DEFAULT_ENCODING = (String) AccessController
            .doPrivileged(new GetPropertyAction("file.encoding"));

    public static final String URI_IGNORE_CONFIG_KEY = "ignoreURIPortion";

    private String ignoreURIPortion = "";

    /*
     * (non-Javadoc)
     * 
     * @see javax.servlet.Servlet#init(javax.servlet.ServletConfig)
     */
    public void init(ServletConfig servletConfig) throws ServletException {
        super.init(servletConfig);

        // Get if we need to ignore any portion of the URL
        String ignore = servletConfig.getInitParameter(URI_IGNORE_CONFIG_KEY);
        if (ignore != null) {
            ignoreURIPortion = ignore;
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see javax.servlet.http.HttpServlet#service(javax.servlet.http.HttpServletRequest,
     *      javax.servlet.http.HttpServletResponse)
     */
    public void service(HttpServletRequest request, HttpServletResponse response)
            throws ServletException {

        // Determine action name
        String actionName = getActionName(getAdjustedString(request
                .getServletPath()));
        if (actionName != null && !"".equals(actionName)) {
            serviceVanillaRequest(request, response, actionName);
        } else {
            actionName = getUriMappedActionName(request);
            serviceUriMappedRequest(request, response, actionName);
        }
    }

    /**
     * This request has been identified as not being a vanilla request, so
     * handle it as though it's a URI mapped request.
     * 
     * @param request
     * @param response
     * @param actionName
     */
    protected void serviceUriMappedRequest(HttpServletRequest request,
            HttpServletResponse response, String actionName) {

        // Place to store our parsed parameters
        Map parameters = new HashMap();

        // Get the part of the URL from the actionName onwards
        String requestURI = getAdjustedString(request.getRequestURI());
        String paramPortion = requestURI.substring(requestURI
                .indexOf(actionName), requestURI.length());
        StringTokenizer st = new StringTokenizer(paramPortion, "/");

        // Collect the parameters
        List paramsList = new ArrayList(st.countTokens());
        while (st.hasMoreTokens()) {
            try {
                paramsList.add(URLDecoder.decode(st.nextToken(),
                        DEFAULT_ENCODING));
            } catch (UnsupportedEncodingException e) {
                paramsList.add(st.nextToken());
            }
        }

        // Which tokens the params start on. Default is the the second,
        // since the first token is the action
        int tokenStart = 1;

        // If there are an even number of params then we can assume that
        // the first token is the name of the action and the second
        // is the id property to set on that action.
        if (paramsList.size() % 2 == 0) {
            parameters.put("id", paramsList.get(1));
            tokenStart = 2;
        }

        // Parse the rest of the parameters as key/value/key/value...
        for (int i = tokenStart; i < paramsList.size(); i = i + 2) {
            parameters.put(paramsList.get(i), paramsList.get(i + 1));
        }

        // Add in any 'normal' request parameters that are present (which
        // will override the url mapped ones)
        parameters.putAll(request.getParameterMap());

        // Pass of our parameters and action on to the default processing
        // This part is wholly copied from
        // com.opensymphony.webwork.dispatcher.CoolUriServletDispatcher
        try {
            request = wrapRequest(request);
            serviceAction(request, response, ””, actionName,
                    getRequestMap(request), parameters, getSessionMap(request),
                    getApplicationMap());
        } catch (IOException e) {
            String message = “Could not wrap servlet request with MultipartRequestWrapper!”;
            sendError(request, response,
                    HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
                    new ServletException(message, e));
        }

    }

    /*
     * This request has been identified as being a vanilla request:
     * actionName.action?key=value&key=value…., handle it appropriately
     * 
     * @param request
     * @param response
     * @param actionName
     */
    protected void serviceVanillaRequest(HttpServletRequest request,
            HttpServletResponse response, String actionName) {
        try {
            serviceAction(wrapRequest(request), response,
                    getNameSpace(request), actionName, getRequestMap(request),
                    getParameterMap(request), getSessionMap(request),
                    getApplicationMap());
        } catch (IOException e) {
            String message = “Could not wrap servlet request with MultipartRequestWrapper!”;
            sendError(request, response,
                    HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
                    new ServletException(message, e));
        }
    }

    /*
     * The action could not be determined when the vanilla action.xxx format was
     * used – revert to other more manual means to determine the action name.
     * 
     * @param request
     * @return
     /
    protected String getUriMappedActionName(HttpServletRequest request) {

        // Safest way seems to be to take the request URI, and strip off the
        // context path from the beginning, then strip off everything after the
        // first slash
        String uri = request.getRequestURI();
        String contextPath = request.getContextPath();
        String servletPath = request.getServletPath();

        // Strip off the context and servlet paths to get at our action string
        String baseUri = uri.substring(contextPath.length(), uri.length());
        baseUri = baseUri.substring(servletPath.length(), baseUri.length());

        // Strip off trailing args past the action name (and not
        // including leftover leading ”/”)
        int trailingSlash = baseUri.indexOf(”/”, 1);
        baseUri = baseUri.substring(1, (trailingSlash > 0 ? trailingSlash
                : baseUri.length()));
        return baseUri;
    }

    /*
     * Get the portion of the request URI that should be analyzed for action
     * names, parameters etc… This is basically the URI minus the text
     * specified in the “ignoreURIPortion” servlet init param. (only takes out
     * the first occurance of the string – override for other functionality)
     * 
     * @param request
     * @return
     */
    protected String getAdjustedString(String adjustable) {
        return adjustable.replace(ignoreURIPortion, ””);
    }
}

Useful command to find conflicting Java classes

Posted by ryan
at 9:19 PM on Thursday, December 08, 2005



I had the need awhile ago to find if any jar files in my app included the same class files. On *nix you can do it using this command (which will recursively search all jars in the current directory and compare them to jars in the otherDir directory:

find ./ -name "*.jar" -type f -print | xargs -i -t jar -tf {} |
   grep .class | xargs -i -t grep {} ../<i>otherDir</i>/*.jar |
   grep matches > matches.txt

I’m sure there’s a slicker way of doing it, but it worked for me…

Why Have an Abstract Interface? 3

Posted by ryan
at 2:06 PM on Monday, February 14, 2005



I have run across the following in both some JBoss source that I’ve seen as well as the “new Interface” wizard in Eclipse… What is the purpose of having an interface and its methods defined as being abstract? To me, this is completely redundant:

abstract interface MyIfc {
   public abstract whatsThePoint();
}

If it’s an interface, of course you have to implement its definition – which is what being abstract means. What is the point of basically specifying the same thing twice? I know I’m missing something here?