Showing posts with label AOP. Show all posts
Showing posts with label AOP. Show all posts

Friday, May 28, 2010

Get a Spring Aspect Working

After some time away from AOP, I've found myself forgetting the bare essentials of getting off the ground - i.e., what's the least I have to do just to prove that my aspect is getting invoked?

Assuming a Spring 3.0 environment, here is the summary:
  1. Create the aspect
  2. Create a Spring context file that declares AOP
  3. Use Spring to instantiate both the aspect and the application object
  4. Run your test case to prove it's working
Here's a bare-bones aspect:

package com.mybiz;
import org.aspectj.lang.annotation.Aspect;

@Aspect
@Component
public class MyAspect
{
    // Flag indicating that a given pointcut was in fact invoked.
    public boolean madeIntercept = false;

    @Pointcut("execution(* com.mybiz.MyApp.myMethod(..))")
    public void myMethodPointcut() {}

    @After("myMethodPointcut()")
    public void doSomething() { madeIntercept = true; }
}

Here's a simple Spring file, named spring-test-aspect.xml:

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
       http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd">

    <context:annotation-config/>
    <context:component-scan base-package="com.mybiz"/>

    <aop:aspectj-autoproxy/>

</beans>

The aspect will automatically get Spring-managed since it uses the @Component annotation, and component scanning declared above includes its package. Use the same approach with your application object:

package com.mybiz;
@Component
public class MyApp
{
    public void myMethod() {}
}

Filling in the method is irrelevant; all we're trying to do is prove that if that method is invoked, that the aspect will  intercept the control flow afterwards. Here's a test case that does this for us:

package com.mybiz;

@ContextConfiguration(locations ={"file:spring-test-aspect.xml"})
public class MyAspectTest extends AbstractTestNGSpringContextTests
{
    @Resource
    private MyAspect myAspect;

    @Resource
    private MyApp myApp;

    @PostConstruct
    public void init() { assert myAspect != null; assert myApp != null; }

    @Test
    public void confirmInterception() 
    { 
        assert !myAspect.intercepted();
        myApp.myMethod(); 
        assert myAspect.intercepted();
    }
}


There's the proof-of-concept; from here, you'd add real functionality to your application class and decorate that functionality with the aspect. I should offer a fair warning: the above snippets have not been actually compiled and run, rather simply copy-pasted with various names changed to be more general purpose (as such, it might not be totally correct). So, if you bump into any problems - you have my apologies, but I'm sure the problems will be trivial.

Monday, March 15, 2010

Case Study: Add Functionality Without Changes to Code

What I'll describe here is an exercise I've completed that adds functionality to an existing codebase without changing that codebase. The product is not dynamically "pluggable", service-oriented, etc., so I don't have those levers to address the problem; instead, I've used Aspect Oriented Programming (AOP), JSF phase listeners, and the Observer design pattern to add to the codebase in a modular way. This gives me an easy way to remove that code if that's called for - and, for this exercise, that's the primary goal.


Our team's product cycle is transitioning with one release in test cycle, moving soon to a Beta audience; and with some new functionality targeted for the next release. These releases are being managed in separate SCM trees; however, due to various infrastructure limitations, we're being asked to wait on checking in changes to the test-cycle branch. But I don't want this to stop me from moving forward on that release.

There are various well-known problems, of course, if one makes "too many" changes to a  codebase before checking things in:
  1. There could be a conflict-resolution exercise between my changes and my teammates' changes to the same files.
  2. If a bug is found in Beta, that code will need a bugfix and a patch - but if I've intermingled new stuff in the code needing bugfixes, I have a potentially error-prone, tedious and time-consuming version control exercise.
There are SCM strategies to address #2; but for the sake of argument, let's just say that my constraint is to develop the new functionality with minimal - if not zero - impact to existing code, to avoid both potential problems from above.

For that matter, I wanted to challenge myself to see just how much I could do with this type of constraint - so I gave myself some "rules":
  1. keep the code changes as modular as possible so they can easily be added, for that matter easily removed if called for;
  2. ideally, no changes at all are made to existing code;
  3. if for some reason, I must change existing code, it must be done in such a way that new classes, declarations, etc. can be introduced, but existing code must not make reference to the new artifacts
So, e.g., I can use aspects, includable XML files, listeners of various flavors, and the like. Looking more closely at my "rules", it appears that #2 and #3 actually are the "how-to" supporting the "what" of #1 - i.e., the true goal here is to make it easy to add or remove the functionality if called for.

Here's the new functionality to be added:
  1. At various points during the customer's use of the product, a certain process should be launched to accomplish a particular goal. I'm intentionally being vague since the details don't really matter here.
  2. For each version of the product, that process should be executed just once without any confirmation from the user that it should proceed; but once it's been executed that first time (for a particular product release), the user should be issued some kind of popup confirmation dialog (this is a webapp UI) that offers a choice: allow the process to proceed with due caution, or just bail out.
  3. Every time a new product release is installed, the warning mechanism resets, i.e. the very next time the user launches the process, no such confirmation dialog appears.
The relevant pieces of the technology stack that I'll be "modifying" includes:
  1. A JSF-based web tier, using in particular the IceFaces component set;
  2. Spring 3.0
Breaking things down, it seems I'll need to do things like this:
  1. Persist some information around the product version, to be generated at build time and deployed with product installation;
  2. intercept the rendering of the UI button that launches the process so that the confirmation dialog can be associated with it, such that when the button is clicked, the confirmation will appear (giving the user a choice of proceeding or not) - but the confirmation appears only if the process has already executed for this product release;
  3. persist information after each process execution indicating this execution has occurred for a given product installations; and
  4. interpret the lack of that persisted information to indicate the process has not executed for this installation. This will be the initial condition, and the condition after each new product release is installed.

What I did to address #1 is trivial, and frankly out of scope for the purposes of this post. Likewise, #4 is reasonably straightforward; no additional details are needed around this.

To address #2 - intercept the rendering of the user action - my initial instinct tells me this sounds like an aspect...well, to be honest, I was looking for some excuses to use aspects - not only because I think this is a good approach to adding functionality in a modular way, but because I want to get better at AOP. A solution for #3 might also use an aspect, so that after the process has been run, the process-execution-history is updated.

As it turned out, the most interesting problem was intercepting the rendering of the UI button to attach a confirmation dialog dynamically. Note that sometimes the confirmation should be there - if the process has already been run - and sometimes, the process should just get launched without any warning to the user.

Let's first establish the confirmation dialog to be used. I'm using IceFaces, which provides a panelConfirmation tag that I use like this:

    <!--
    Warn user if process has already executed for this release
    -->
    <ice:panelConfirmation 
       id="warnProcessExecuted" 
       message="#{msgs['confirm.rerun']}"
       acceptLabel="Yes" cancelLabel="No"/>

The straightforward way to use this is to simply add it as an attribute to the existing IceFaces button that launches the process:

<ice:commandButton id="launchProcess"
     value="Launch Process"
     immediate="true"
     confirmationPanel="warnProcessExecuted"
     actionListener="#{eventsManager.startProcess}"/>

But this violates my self-imposed constraint described by rule #2 above: "ideally, no changes at all are made to existing code".  So my initial thought is to do this:
  1. intercept the handling of the action after user clicks on the button;
  2. find the JSF component associated with the button; and
  3. dynamically add the confirmationPanel attribute to that button component.
Doing things this way also would factor out the conditional part: if the process has not executed yet, there's no need to add the confirmation. But it turns out that trying to add the attribute during the action handling is too late - what I want is to intercept the rendering of the button. This sounds like I could use a JSF phase listener that listens for the beginning of the RENDER_RESPONSE phase to do this. This worked out just fine, but the thing about it that bothered me was that this happens several times for each action, and the method that I use to attach the attribute gets called each time. In this case, no harm is done; but I'd like to find a more general solution so my code execution is more deterministic and less at the mercy of the JSF lifecycle - bottom line, so that the method of interest is called only once at the beginning of the RENDER_RESPONSE phase. Here's how I did it:

First I create a reusable hierarchy of JSF phase listeners. The superclass provides the PhaseListener implementation, and additionally provides a registration mechanism - with which it remembers any interested listeners for a given phase. Each registered listener implements a PhaseObserver interface, and is notified at the beginning and end of each JSF phase:

public class PhaseMonitor implements PhaseListener {

    private static Map<JsfPhaseId, Set<PhaseObserver>> observers =
        new HashMap<JsfPhaseId, Set<PhaseObserver>>();

    // notify all registered observers for this phase that the phase has begun
    public void beforePhase(PhaseEvent event) {

        JsfPhaseId phaseId = JsfPhaseId.getJsfPhaseId(event.getPhaseId());
        Set<PhaseObserver> these = observers.get(phaseId);
        if (these != null) {
            for (PhaseObserver observer : these) {
                observer.notifyBeforePhase(phaseId);
            }
        }
    }

    // notify all registered observers for this phase that the phase has ended
    public void afterPhase(PhaseEvent event) {

        JsfPhaseId phaseId = JsfPhaseId.getJsfPhaseId(event.getPhaseId());
        Set<PhaseObserver> these = observers.get(phaseId);
        if (these != null) {
            for (PhaseObserver observer : these) {
                observer.notifyAfterPhase(phaseId);
            }
        }
    }

    // observer pattern: interested observers implement the PhaseObserver interface and register their interest
    public static void register(JsfPhaseId phase, PhaseObserver observer) {

        Set<PhaseObserver> these = observers.get(phase);
        if (these == null) {
            these = new HashSet<PhaseObserver>();
        }
        these.add(observer);
        observers.put(phase, these);
    }

    protected PhaseId getMyPhaseId() { // subclasses will override this for each JSF phase
        return null;
    }

    public PhaseId getPhaseId() {
        return getMyPhaseId();
    }
}


The JsfPhaseId is a first-class enum, provided not only so the observers can reference a simple enum constant (which the JSF PhaseID does not provide - it is not an enum (!!)), but so that client code need not be tightly coupled to JSF. Granted, clients will use the JsfPhaseId, which uses JSF, so the deployment will be coupled to JSF - but at least I've encapsulated my usage of JSF by providing this facade:

public enum JsfPhaseId
{
    APPLY_REQUEST_VALUES, INVOKE_APPLICATION, PROCESS_VALIDATIONS,
    RENDER_RESPONSE, UPDATE_MODEL_VALUES, RESTORE_VIEW, UNKNOWN;

    public static JsfPhaseId getJsfPhaseId(PhaseId phaseId) {

        if (phaseId.equals(PhaseId.APPLY_REQUEST_VALUES)) {
            return JsfPhaseId.APPLY_REQUEST_VALUES;
        } else if (phaseId.equals(PhaseId.INVOKE_APPLICATION))  {
            return JsfPhaseId.INVOKE_APPLICATION;
        } else if (phaseId.equals(PhaseId.PROCESS_VALIDATIONS)) {
            return JsfPhaseId.PROCESS_VALIDATIONS;
        } else if (phaseId.equals(PhaseId.RENDER_RESPONSE)) {
            return JsfPhaseId.RENDER_RESPONSE;
        } else if (phaseId.equals(PhaseId.UPDATE_MODEL_VALUES)) {
            return JsfPhaseId.UPDATE_MODEL_VALUES;
        } else if (phaseId.equals(PhaseId.RESTORE_VIEW)) {
            return JsfPhaseId.RESTORE_VIEW;
        }
        return JsfPhaseId.UNKNOWN;
    }
}

Each phase-specific subclass of PhaseMonitor does this:

public class RenderResponsePhaseMonitor extends PhaseMonitor {

    private PhaseId phaseId = PhaseId.RENDER_RESPONSE;
    protected PhaseId getMyPhaseId() {
        return phaseId;
    }
}

This is repeated for the other JSF phases. Now I need to add these phase listeners to the code, but in a way that minimizes impact that existing code. So, I do not want to modify my existing JSF configuration file by declaring these listeners; instead, I add a new config file using the web-tier deployment descriptor (web.xml):

<context-param>
        <param-name>javax.faces.CONFIG_FILES</param-name>
        <param-value>/WEB-INF/faces-config-application.xml, /WEB-INF/faces-config-listeners.xml</param-value>
</context-param>

That config file looks like this:

<faces-config xmlns="http://java.sun.com/JSF/Configuration">
    <!-- listen for phase events to facilitate phase listening, notification -->
    <lifecycle>
        <phase-listener>com.mybiz.web.jsf.lifecycle.ApplyRequestValuesPhaseMonitor</phase-listener>
        <phase-listener>com.mybiz.web.jsf.lifecycle.InvokeApplicationPhaseMonitor</phase-listener>
        <phase-listener>com.mybiz.web.jsf.lifecycle.ProcessValidationsPhaseMonitor</phase-listener>
        <phase-listener>com.mybiz.web.jsf.lifecycle.RenderResponsePhaseMonitor</phase-listener>
        <phase-listener>com.mybiz.web.jsf.lifecycle.RestoreViewPhaseMonitor</phase-listener>
        <phase-listener>com.mybiz.web.jsf.lifecycle.UpdateModelValuesPhaseMonitor</phase-listener>
    </lifecycle>
</faces-config>

The interested observers implement this interface:

public interface PhaseObserver {

    public void notifyBeforePhase(JsfPhaseId phaseId);
    public void notifyAfterPhase(JsfPhaseId phaseId);
}

With these levers in place, I can now implement an observer that will be notified once and only once at the beginning of the RENDER_RESPONSE phase, at which time it will determine if a confirmation for the user is needed; if so, it will find the JSF component of interest and attach the confirmation panel, and, if the user elects to proceed, updating some persistent history "somewhere" with information about this execution; else it sets the attribute value for the confirmation panel to an empty string so that no such dialog pops up. Since I don't want to minimize my changes to existing code, I add this functionality with an aspect:

@Aspect
public class ExecutionAspects implements PhaseObserver {

    public ExecutionAspects() {
        PhaseMonitor.register(JsfPhaseId.RENDER_RESPONSE, this);
    }

    private ExecutionHelper executionHelper;  // injected via Spring
    public void setExecutionHelper(ExecutionHelper theHelper) {
        executionHelper = theHelper;
    }

    /**
     * Establish a pointcut that describes a method which we know will be called when the button is rendered
     */
    @Pointcut("execution(* com.mybiz.view.ViewHelper.isLaunchProcessButtonShowing(..))")
    public void isLaunchProcessButtonShowing() {
    }

    // here's how we enforce the "once and only once" constraint:
    private boolean needConfirmationForThisRequest = true;
    public void notifyBeforePhase(JsfPhaseId phaseid) {
        needConfirmationForThisRequest = true;
    }
    public void notifyAfterPhase(JsfPhaseId phaseid)
    {
        needConfirmationForThisRequest = false;
    }

    /**
     * Intercept rendering of button to detect whether or not the process has already been run for this release
     */
    @Around("isLaunchProcessButtonShowing()")
    private boolean interceptRender(ProceedingJoinPoint pjp) throws Throwable {
        if (needConfirmationForThisRequest)
        {
            // get UI component, add confirmation panel if needed
            HtmlCommandButton button =
                    (HtmlCommandButton) FacesUtils.findComponent(FacesUtils.getFacesContext().getViewRoot(),
                            "launchProcess");  // search from root of JSF component tree for the launch button ID
            if (executionHelper.getProcessHasExecutedForThisProduct()) {
                // attach the confirmation
                button.setPanelConfirmation("warnProcessExecuted");
            } else {
                // set the confirmation attribute to an empty string so no warning will appear
                button.setPanelConfirmation("");
            }
            needConfirmationForThisRequest = false;
        }
        // return value as normal
        return (Boolean)pjp.proceed();
    }

    /**
     * Establish a pointcut that intercepts the user action of launching the process
     */
    @Pointcut("execution(* com.mybiz.view.EventsHelper.startProcess(..))")
    public void startProcess()
    {
    }

    /**
     * Intercept launching of process to facilitate updating the execution history after it's done
     */
    @Around("startProcess()")
    private void interceptProcess(ProceedingJoinPoint pjp) throws Throwable
    {
        pjp.proceed();
        // update history so user can be warned that it's already been run (next time it's requested)
        executionHelper.updateConfMergeHistory();
    }
}

Now the aspect needs to be added to runtime execution; I already have a Spring context file for the existing product functionality, but again I don't want to change that file. Instead, I modify the web-tier deployment descriptor to add a new one:

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/beans-all.xml, /WEB-INF/beans-execution.xml</param-value>
</context-param>

That Spring context file manages the ExecutionAspects class, supplying the ExecutionHelper dependency:

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="
       http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
       ">

    <!--
    Configuration file used to maintain execution information - i.e. as a control for when the process
    is run with or without warning, we need to maintain information about what release is this
    product, and compare that to what release was the last execution run against.
    -->
    <bean id="executionHelper" scope="session" class="com.mybiz.aspects.ExecutionHelper">
    </bean>

    <aop:aspectj-autoproxy proxy-target-class="false"/>

    <bean id="execution-aspect" class="com.mybiz.aspects.ExecutionAspects">
        <property name="executionHelper" ref="executionHelper"/>
    </bean>

</beans>

The ExecutionHelper is of minimal interest here; it simply does CRUD on "some persistence mechanism" to manage information about what is the current product release and what particular release has the process last been executed against. It provides a convenience method (getProcessHasExecutedForThisProduct(), as seen above) encapsulating all of that information with a boolean indicating exactly what it's name suggests.


So let's revisit my initial goals and see how well I've done:
  1. keep the code changes as modular as possible so they can easily be removed if called for;
  2. ideally, no changes at all are made to existing code;
  3. if for some reason, I must change existing code, it must be done in such a way that new classes, declarations, etc. can be introduced, but existing code must not make reference to the new artifacts (this facilitates rule #1)
#1: are my changes modular? In the sense that they can be removed very easily if needed, yes - here's what I'd need to do to remove this functionality: change this -->

<param-value>/WEB-INF/beans-all.xml, /WEB-INF/beans-execution.xml</param-value>

to this -->

<param-value>/WEB-INF/beans-all.xml</param-value>nclude src="/WEB-INF/includes/panel-confirmation.jspx"/>

Without the single additional declaration of Spring context that attaches the new aspect to the runtime, the aspect will not get instantiated, let alone executed. All of the existing code - well, most of it anyway - remains untouched. The new code can be left as an addition to the codebase, ready for activation whenever product management calls for that.

You'll notice I said most of the existing code is unchanged. Beyond the addition of the 2nd Spring context, as noted here, and the additional JSF Config file that declares the hierarchy of phase listeners, I did need to make one change to the JSF file that declares the command button; I needed to include the new JSF file that declares the confirmation within the same form. Apparently this is a constraint of the component set, and it is not surprising. So I ended up doing this:


<ice:commandButton id="launchProcess"
    value="Launch Process"
     immediate="true"
    actionListener="#{eventsManager.startProcess}"/>
             
 <!-- confirmation panel must be in same form as the button that references it. The
  "launchProcess" button, above, is managed dynamically to point to this confirmation
  in an aspect. For better modularity, include the panelConfirmation snippet:
  -->
  <ui:include src="/WEB-INF/includes/panel-confirmation.jspx"/>

So I didn't quite succeed with rule #2 -- I did have to make some changes to existing code. But for all intents and purposes, it's not an issue -- since the change to the code is a declaration that is not referenced by existing code. I'd argue likewise for the addition of the JSF Config file with the hierarchy of phase listeners and built-in observer mechanism - this is, in my opinion, a worthwhile addition to any JSF application, one that I'll likely continue doing from this point forward. I just happened to leverage it with an aspect that registers as an interested observer of the RENDER_RESPONSE phase. That is the essence of modularity.

Again, not quite successful with rule #3 - since the changes to the web.xml do make reference to the new JSF Config and Spring context files. But again, in spirit that goal was only in place to facilitate success on rule #1 - and bottom line, I can add or remove this new functionality without breaking a sweat.

Thursday, September 10, 2009

Spring 3.0 AOP: Cheatsheet

Continuing with insights and tips around Spring 3.0, here is a collection of code samples I've established "so far" with my (rather brief) prototyping using that framework. As with all of my cheatsheets, I'm not presenting these things as any kind of definitive reference; they are only from my own experience, done only in a "sandbox" so far -- we've not yet put these things into production. Your contributions and corrections to this cheatsheet, and any of my other ones, are welcome.


Dependencies

The following libraries are needed:

org.springframework.asm-3.0.0.M3.jar
org.springframework.beans-3.0.0.M3.jar
org.springframework.context-3.0.0.M3.jar
org.springframework.core-3.0.0.M3.jar
org.springframework.expression-3.0.0.M3.jar
org.springframework.aop-3.0.0.M3.jar
antlr-3.0.1.jar commons-logging.jar
com.springsource.org.aopalliance-1.0.0.jar
com.springsource.org.aspectj.runtime-1.6.5.RELEASE.jar
com.springsource.org.aspectj.weaver-1.6.5.RELEASE.jar

Concepts

Some key terminology and concepts, pulled from the Spring 3.0 Reference doc - I'll just copy key pieces verbatim first and then paraphrase at the end:
  • Aspect: a modularization of a concern that cuts across multiple classes. Transaction management is a good example of a crosscutting concern in J2EE applications. In Spring AOP, aspects are implemented using regular classes (the schema-based approach) or regular classes annotated with the @Aspect annotation (the @AspectJstyle).
  • Join point: a point during the execution of a program, such as the execution of a method or the handling of an exception. In Spring AOP, a join point always represents a method execution.
  • Advice: action taken by an aspect at a particular join point. Different types of advice include "around," "before" and "after" advice. Many AOP frameworks, including Spring, model an advice as an interceptor, maintaining a chain of interceptors around the join point.
  • Pointcut: a predicate that matches join points. Advice is associated with a pointcut expression and runs at any join point matched by the pointcut (for example, the execution of a method with a certain name). The concept of join points as matched by pointcut expressions is central to AOP, and Spring uses the AspectJ pointcut expression language by default.
  • Introduction: declaring additional methods or fields on behalf of a type. Spring AOP allows you to introduce new interfaces (and a corresponding implementation) to any advised object. For example, you could use an introduction to make a bean implement an IsModified interface, to simplify caching. (An introduction is known as an inter-type declaration in the AspectJ community.)
  • Target object: object being advised by one or more aspects. Also referred to as the advised object. Since Spring AOP is implemented using runtime proxies, this object will always be a proxied object.
  • AOP proxy: an object created by the AOP framework in order to implement the aspect contracts (advise method executions and so on). In the Spring Framework, an AOP proxy will be a JDK dynamic proxy or a CGLIB proxy.

So an aspect is a class that contains methods referred to as "advice". The advice is executed as specified by the annotation (before, after, etc.) and the "pointcut", or predicate (what classes/methods match the expression). The point in the application where the advice is applied is a "join point". The runtime object containing these join points (i.e., being advised by one or more aspects) is the "target" or "advised object". Spring uses proxying to accomplish the advising (see section 8.6.1 - really, read it, it's short and helpful), and will use JDK dynamic proxies if all advised objects implement at least one interface. Finally, "introductions" are a mechanism where advised objects can be transparently made to implement new interfaces (to retrofit things like caching, comparability, serialization, immutability, etc.), with the advice providing an implementation of the interface, and being handed a reference to the advised object that it can use to invoke the new interface methods.


Problem Space

Recommendations in the following discussions are in bold-face.

The proof-of-concept application is a trivial tongue-in-cheek model of a "family service", where my son Connor and my Siberian Husky Nika would each like to get my attention. It happens. Spring IoC is used to declaratively determine who wins; since that's a static configuration, it's for now the same answer every time.

So the basic idea is a shown in the UML: we have a FamilyService with a FamilyMember property, and two FamilyMembers, each with a name property.

Note that all classes implement an interface. This is in general a good idea for testability, etc. but in particular with Spring AOP, I'd favor this approach because it facilitates use of JDK dynamic proxies instead of CGLIB proxies. Use of CGLIB should consider these things: (1) more library dependencies, (2) final methods cannot participate in AOP, and (3) constructors are called twice due to CGLIB implementation details.

Short of other insights, I would for now recommend implementing at least one interface for any classes that participate in Spring AOP.

A detailed explanation of the above issue around CGLIB vs JDK dynamic proxying, as well as very clear presentation in general around Spring 3.0, can be found in the Spring Reference doc.



Enabling AOP

The injection of the family member getting my attention is done like this:

<bean id="family-service" class="spring.FamilyService">
 <property name="member">
     <ref local="nikadog"></ref>
 </property>
</bean>

This is typical Spring injection; nothing special here. The more interesting stuff is to now add some AOP. Do this by adding an "aop" namespace to the beans declaration tag and enabling what I would recommend as the preferred flavor of Spring AOP (AspectJ-style annotations plus Spring auto-proxying):
 
 <beans xmlns="http://www.springframework.org/schema/beans"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns:aop="http://www.springframework.org/schema/aop"
   xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
 ....
   <aop:aspectj-autoproxy/>
 </beans>

The Spring reference doc again provides a clear, useful discussion around the various "flavors" you can use with Spring AOP. Given the tradeoffs described there, I recommend the AspectJ-style annotations with Spring auto-proxying for the following reasons:
  1. Their advice to "use the simplest thing that works" is IMO sound guidance
  2. So, for now, assume that AspectJ-annotations will suffice until you find otherwise
  3. If you need to gain more power, you can migrate easily from the AspectJ-annotations to full-blown AspectJ itself

The limitations to be aware of include these:

  1. AOP can only be applied to Spring-managed beans (therefore, Spring-declare any classes that will leverage AOP)
  2. AOP mechanisms can be applied only to public method-level executions (excluding constructors)
  3. Methods in AOP-enabled classes that have aspects declared will not see those aspects applied if invoked by other
    methods in that same class (i.e., do not use self-invocation within AOP-enabled classes)

Limitations #2 and #3 are a result of Spring's proxy approach to AOP. See section 8.6.1 in the reference doc for a detailed discussion. Note that a workaround for #3 is discussed in that section, but it involves a tight coupling to Spring and makes the application class acutely aware that it is being AOP-managed, neither of which is a recommended practice.


Simple AOP

To create an aspect with some advice that executes before all public methods in the spring package (see reference doc, section 8.2.3.4 for examples around expression syntax):

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
@Aspect
public class MyAspect {
 /**
  * Log a message before entry to specified methods
  */
  @Before("execution(* spring..*(..))")
  private void logOnEntry(JoinPoint jp) {
     // JoinPoint argument is optional, but recommended as quite useful
     System.out.println("Before " + getSimpleName(jp));
  }
 /**
  * Returns the simple name of the class being advised, as per the given
  * join point.
  */
  private String getSimpleName(JoinPoint jp) {
     return jp.getTarget().getClass().getSimpleName();
  }
 }

The aspect must be managed by Spring to be put into play - add this entry to the configuration file:

<bean id="myAspect" class="spring.MyAspect"> </bean>

As you can see, you can also access the target object via the JoinPoint argument. As such, you can cast it to your application type and execute its public methods.

You can also execute advice after a method or around a method. The @After is analogous to the above example. The "execution" part of the expression is the "pointcut designator" or PCD; there are several others, but "execution" is probably what will be used the most. Since it's indicating a method-level execution, you can alter the method-portion of the expression to e.g. address only setters:

@Before("execution(* spring..set*(..))")

To address executions at a type level (i.e. all public methods in a given type), use the "within" PCD:

@After("within(*.*Service)")

You can also use the Spring bean ID declaration as an alias for a given type; so, given this bean declaration:

<bean id="family-service" class="spring.FamilyService"></bean>

...you can specify this join point using the "bean" PCD:

@After("bean(family-service)")


Reusable Pointcuts

Reusable pointcuts can be established:

/**
 * Establish a pointcut on execution of any and all public methods
 */
@Pointcut("execution(* *.*(..))")
public void anyMethod() {}

Pointcuts can be combined to form conditional expressions, using AND, OR and NOT operators (&&, ||, and !):

@Pointcut("within(com.xyz.service..*)")
private void inServiceModule() {}
@Pointcut("anyMethod() && inServiceModule()")
private void serviceOperation() {}

To intercept the throwing of an exception resulting in a method exit, using the "anyMethod" pointcut established above:

/**
 * Intercept execution when any method exits by throwing any exception
 */
 @AfterThrowing(pointcut = "anyMethod()", throwing = "ex")
 private void trackExceptions(JoinPoint jp, Exception ex) {
     System.out.println("Exception thrown from "           + getSimpleName(jp) + ": " + ex);
 }

To intercept the value returned from a specified pointcut:

 /**
  * Establish a pointcut on execution of specified method
  */
  @Pointcut("execution(* spring.Nika.getName())")
  public void getNikadogName() {}
 /**
  * Intercept the return from specified pointcut
  */
  @AfterReturning(pointcut = "getNikadogName()", returning = "name")
  private void getNikaName(String name) {
      System.out.println("after returning from nikadog, pointcut name: "
           + name + "...");
  }


Beyond the Simple

The @Around PCD is bit more sophisticated:

 /**
  * Establish a pointcut on execution of specified method
  */
  @Pointcut("execution(* FamilyService.getMember(..))")
  public void getMember() {}
 /**
  * Wrap specified method to get profiling information. Can also use this pattern
  * for tracing, caching, etc.
  */
  @Around("getMember()")
  private FamilyMember doProfiling(ProceedingJoinPoint pjp)  throws Throwable {
    long start = System.currentTimeMillis();
    FamilyMember member = (FamilyMember) pjp.proceed();
    System.out.println("Elapsed time to get member: " +        (System.currentTimeMillis() - start));
     return member;
 }

In the above snippet, the ProceedingJoinPoint facilitates setting things up before the advised object method is executed (i.e. start the stopwatch, check the cache for a hit, etc.), then supports (optionally!) executing the method, and finally returning the appropriate value - so you can see that this decorates the object execution with your own proxying code. Note that you can easily check a cache for a "hit", then simply return the cached value if it's there without executing the method, otherwise executing the method and stuffing it in the cache for subsequent requests. Using the "args" PCD, you can (e.g.) examine incoming argument values to qualify what specific object in the cache is being requested.

Note that this approach to caching relies on the aspect to manage the cache. An alternate approach will be presented in the "Introductions" section below.

Suppose our service class was throwing an exception, and we want to apply a retry strategy since the problem involves waiting for some remote resource to become available (e.g. the database is spinning up):

@Around("getMember()")
 private FamilyMember retry(ProceedingJoinPoint pjp) throws Throwable {
     int numAttempts = 0;
     int maxRetries = 5;
     Throwable t = null;
     do {
        numAttempts++;
        try {
            return (FamilyMember)pjp.proceed();
        } catch (DatabaseNotReadyException ex) {
            System.out.println("=========== Caught exception from "
                 + getSimpleName(pjp)
                + "; retry attempt #" + numAttempts + "==============");
            t = ex;
        }
     } while (numAttempts <= maxRetries);
              throw t;
   }

Introductions

A technique described above for caching relies on the aspect itself to manage the cache. An alternate approach is to implement an interface that prescribes caching functionality:

public interface Cacheable {
     public boolean isCached();
     public void save(Object obj);
     public Object fetch();
}
But we may be motivated to regard this cacheability as a cross-cutting concern, one that should be maintained and managed (enable/disable, track hits, monitor throughput gains, flush the cache, etc.) separately from the pure business logic (vs simply having FamilyService implement the interface explicitly, i.e. such that one's business classes are not responsible for determining their own "cacheability" - that's an orthogonal concern). If so, we can use AOP "introductions" to retrofit the caching.

An implementation supporting the FamilyService (and, for that matter, other services in general) might begin life like this:

public class CacheableImpl implements Cacheable {
      private boolean cached = false;
      private Object cachedObject = null;
      public boolean isCached() {
        return cached;
     }
      public void save(Object obj) {
        cachedObject = obj;
        cached = true;
     }
      public Object fetch() {
        return cachedObject;
     }
}
An "introduction" is a way of retrofitting an implementation of an interface onto the target object. Since it's AOP, the target object does not and need not know it's being decorated like this. The somewhat cryptic syntax to make it happen is encapsulated in the aspect:
@DeclareParents(value = "spring.FamilyService", defaultImpl = CacheableImpl.class)
 public static Cacheable mixin;
 .......
 @Around("getMember() && this(service)")
 public FamilyMember checkCache(ProceedingJoinPoint jp, Cacheable service) throws Throwable {
     if (service.isCached())  {
        System.out.println(" ---> Returning cached member");
        return (FamilyMember) service.fetch();
     }
     System.out.println(" ---> Member NOT cached; call service and save result...");
     FamilyMember member = (FamilyMember) jp.proceed();
     service.save(member);
     return member;
 }
Now, instead of relying on the aspect to manage caching - arguably a questionable responsibility - the details of caching are factored out to give us better cohesion. This is just one possible use of the AOP introduction.
Resources Spring 3.0.M3 Reference Documentation, by Rod Johnson et. al., 2009 Spring Framework

Friday, July 17, 2009

Using Spring-iBatis to access LDAP - Part 2

Introduction

In the first half of this series, I described our experience with the latest Spring-LDAP module, concluding that an alternative mechanism would be needed due to deployment issues. I promised an alternative iBatis-over-LDAP solution, and in this article I provide demonstration code samples.
With this approach in place, we can view an LDAP repository as an ordinary SQL-based database, albeit with its own variant of SQL. Other advantages include the standard iBatis benefits, in particular the ability to declaratively specify SQL queries and as such manage them from a single point of change.

What follows is a description of how I put a quick-and-dirty prototype together, in particular using Spring 3.0.

Dependencies

The key to this solution is a JDBC driver that wraps LDAP repositories, created by Octet String (and now owned by Oracle). Once we have a JDBC driver, in theory we should be able to layer iBatis over it.

Download version 2.1 of that driver:
https://sourceforge.net/projects/myvd/files/

Put these jars from that download into your runtime classpath:

jdbcLdap.jar
ldap.jar

You'll need the standard set of jars for Spring 3.0 - for the minimal Spring 3.0 prototyping I've done so far, here is the set that has worked for me:

commons-lang.jar
commons-logging.jar
antlr-3.0.1.jar
org.springframework.asm-3.0.0.M3.jar
org.springframework.beans-3.0.0.M3.jar
org.springframework.context-3.0.0.M3.jar
org.springframework.core-3.0.0.M3.jar
org.springframework.expression-3.0.0.M3.jar

Add in iBatis:

iBatis-2.3.4.jar

Add what's needed to support Spring 3.0 over iBatis:

commons-dbcp.jar 
com.springsource.org.apache.commons.pool-1.4.0.jar
org.springframework.jdbc-3.0.0.M3.jar
org.springframework.orm-3.0.0.M3.jar
org.springframework.transaction-3.0.0.M3.jar

The last jar listed above is the Spring 3.0 version of transactions. The 2.5.6 version is required for Spring-LDAP, and since the classes in both jars are largely (if not completely) the same, this raises a warning flag about classloading conflicts. I didn't get far enough into a test execution to hit any problems; instead I found that deploying Spring-LDAP with Spring 3.0 AOP causes a runtime error out of the gate (during Spring initialization), and at that point I bailed out on use of Spring LDAP (please refer to my first article for the details).

Finally, though it's not necessary for this example, I include the Spring-AOP libraries, if for nothing else to demonstrate that we won't see the same runtime error as happened using Spring-LDAP with Spring 3.0. You can safely exclude these for your own prototyping of this solution (but if so, just be sure to remove the AOP references in the Spring configuration file described below):

com.springsource.org.aopalliance-1.0.0.jar
com.springsource.org.aspectj.runtime-1.6.5.RELEASE.jar
com.springsource.org.aspectj.weaver-1.6.5.RELEASE.jar
org.springframework.aop-3.0.0.M3.jar


Code Artifacts


Now you're ready to do some coding. First, construct the domain object:

package com.mybiz.model;

public class User {

    private String uid;

    public User() {}
   
    public String getUid() { return uid; }
    public void setUid(String uid) { this.uid = uid; }

    @Override
    public String toString() { return this.uid; }
}

Construct the DAO for the domain object. I recommend using an interface and its implementation - because (1) using interfaces is in general a good idea for testability, polymorphism, and etc., and (2) in particular with AOP-proxied classes in Spring, I'd favor this approach because it facilitates use of JDK dynamic proxies instead of CGLIB proxies. Use of CGLIB involves these things: (1) more library dependencies, (2)  final methods cannot participate in AOP, and (3) constructors are called twice due to CGLIB implementation details. Again, use of an interface is an optional step; if you exclude it, you'll need the CGLIB jars (which I haven't used - and plan to avoid using - so I can't point you to the exact set needed).

In either event, here's the DAO interface and implementation:

package com.mybiz.model;

import java.util.List;

public interface UserDao {
    public List getAllUsers();
}

package com.mybiz.model;

import com.ibatis.sqlmap.client.SqlMapClient;

import java.sql.SQLException;
import java.util.List;

public class MyUserDao implements UserDao { 

    // injected via Spring
    private SqlMapClient sqlMapClient;
    public void setSqlMapClient(SqlMapClient sqlMapClient) { this.sqlMapClient = sqlMapClient; }
    private SqlMapClient getSqlMapClient() { return this.sqlMapClient; }

    public List<user> getAllUsers()
    {
        String query = "selectAll";
        try {
            return (List<user>)getSqlMapClient().queryForList(query);
        } catch (SQLException e) {
            System.err.println("Query '" + query + "' failed: " + e);
            throw new IllegalStateException(e);
        }
    }
}

The database properties are described in a standalone file, to facilitate easy modifications to suit different environments (test, development, production). The key here is to specify the ignore_transactions parameter in the URL; adding the search_scope as a default scope is an optional convenience so that this won't be needed in every one of your SQL queries. Let's name the file database.properties in the com/mybiz/model directory; you'll of course need to adjust the parameters here to match your environment:

database.driver=com.octetstring.jdbcLdap.sql.JdbcLdapDriver
database.url=jdbc:ldap://127.0.0.1:389/dc=mybiz,dc=com?search_scope:=subTreeScope&ignore_transactions:=true
database.user=cn=Manager,dc=mybiz,dc=com
database.password=verycleverpassword

Following through with my convention from the first half of this series, I've bold-faced the relevant configuration pieces so you can compare how things are specified. Above, we see that the database connection parameters (LDAP URL, base node specification, principal and password) have moved from the Spring configuration (when using Spring-LDAP, as per my previous article) and into this file.

Next, layer iBatis over the database connection. We need first the SQL Map Configuration file; it doesn't need to do anything but point to your collection of SQL Maps. Let's call it SqlMapConfig.xml in the com/mybiz/model directory:

<!DOCTYPE sqlMapConfig
        PUBLIC "-//ibatis.apache.org//DTD SQL Map Config 2.0//EN"
        "http://ibatis.apache.org/dtd/sql-map-config-2.dtd">

<sqlMapConfig>
    <sqlMap resource="com/mybiz/model/SqlMap.xml"/>
</sqlMapConfig>

Here is the specified SQL Map. As per the above specification, it should be named SqlMap.xml in the com/mybiz/model directory:

<!DOCTYPE sqlMap
    PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN"
    "http://ibatis.apache.org/dtd/sql-map-2.dtd">

<sqlMap namespace="user">
  <typeAlias alias="user" type="com.mybiz.model.User"/>
  <select id="selectAll" resultClass="user">
    SELECT uid  FROM dc=mybiz,dc=com  where objectclass='person'
  </select>
</sqlMap>

Here, we have bold-faced the LDAP attribute to be fetched, the node from which the search begins, and the search qualifier. While these query parameters plus the database connection parameters were all in one place using Spring-LDAP, here they've been split up into separate files. It's your judgment as to whether this is a good thing or not; personally, I consider these things as separate concerns, so I prefer it. However, you might prefer single point of change for all things database-related and/or all things configuration-related. More importantly, we can now use iBatis' parameterized substitution to declare a query, keeping it readably intact while varying its parameter values dynamically. With Spring-LDAP, we can likewise achieve dynamic query construction, but the model is more procedural.

In the above SQL Map, you'll notice the interesting use of an LDAP base specification instead of a table name (and again, you'll need to adjust this query to match up with your LDAP repository structure). The docs for the JDBC-LDAP bridge do mention that one can map things to an aliased table name, but for our purposes here, transparency and simplicity are more important.

The next step is to configure iBatis with Spring. I included transactional and AOP support, though these are optional for this exercise. Some explanations:
  • Though LDAP itself is not transactional (hence the ignore_transactions parameter above), you might be in an environment where you'll also be accessing normal relational databases, for which you'll want Spring's transactional support. Since we're now solely Spring 3.0, there is in either event no fear of classloading conflicts. However, to make this a bare-bones proof-of-concept, you can exclude the tx namespace declaration in the beans tag, the transaction manager bean and the tx:annotation-driven tag.
  • This Spring config file also configures in AOP solely to demonstrate that there is no longer any deployment conflict as was seen with combining Spring-LDAP and Spring-3.0-AOP; it's not essential for the iBatis-over-LDAP solution per se. As I mentioned above, if you specify AOP in this Spring configuration, you'll need the Spring-AOP runtime jars. Again, to make this a bare-bones proof-of-concept, you can exclude the aop namespace declaration in the beans tag and the aop:aspectj-autoproxy tag.
  • For that matter, Spring itself is not essential to layering iBatis over LDAP - I was able to remove Spring from the stack entirely and get the same successful result. However, Spring provides various benefits to an iBatis application, so I include it here for completeness (and, frankly, because I rely on Spring to help me). If you exclude it, you'll need to configure iBatis manually; I do not include those details here.
Let's name the file beans.xml, in the com/mybiz/model directory:

<beans xmlns="http://www.springframework.org/schema/beans"   
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
       http://www.springframework.org/schema/tx
       http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">

    <!-- OPTIONAL: AOP -->
    <aop:aspectj-autoproxy/>

    <!-- support for referencing properties from the database.propeties file  in the data source bean, below -->
    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="location" value="classpath:com/mybiz/model/database.properties"/>
    </bean>

    <!-- OPTIONAL: transaction manager - needed more for regular databases, not for LDAP -->
    <bean id="txnMgr" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dbcpDataSource"/>
    </bean>
    <!-- OPTIONAL -->
    <tx:annotation-driven transaction-manager="txnMgr"/>

    <!-- Apache DBCP data source, configured with properties from database.properties file -->
    <bean id="dbcpDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <property name="driverClassName" value="${database.driver}"/>
        <property name="url" value="${database.url}"/>
        <property name="username" value="${database.user}"/>
        <property name="password" value="${database.password}"/>
    </bean>

    <!-- iBatis SQL Map client, configured with the config-file location and the data source   -->
    <bean id="sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
        <property name="configLocation" value="classpath:com/mybiz/model/SqlMapConfig.xml"/>
        <property name="dataSource" ref="dbcpDataSource"/>
    </bean>

    <!-- inject the iBatis SQL Map client into the application DAO -->
    <bean id="userDao" class="com.mybiz.model.MyUserDao">
        <property name="sqlMapClient" ref="sqlMapClient"/>
    </bean>
    
</beans>

You'll notice there are no bold-faced sections in the Spring configuration file (i.e., no application-specific configurations are specified). The database connection and database query configuration information are now in separate files dedicated to these responsibilities alone, vs being embedded in what's potentially a rather large Spring configuration. Again, your take on this may vary from mine: I consider this a good thing, but you might prefer all configuration information to be in a single file.

Finally, we provide a test driver program:

package com.mybiz.demo;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.mybiz.model.User;
import com.mybiz.model.UserDao;
import java.util.List;

public class IBatisOverLdapDemo {

    public static void main(String[] args) {

        ApplicationContext context = new ClassPathXmlApplicationContext(
                "com/mybiz/model/beans.xml");
        UserDao dao = (UserDao) context.getBean("userDao");

        List<user> users = dao.getAllUsers();
        for (User user : users) {
            System.out.println(user);
        }
    }
}

Executing this program, with database connection information, queries, and etc. tailored to your LDAP environment, should yield a list of attribute values as expected.

Conclusion

Using iBatis-over-LDAP instead of JNDI-LDAP, you can:
  • configure, connect to and query both RDBMS and LDAP databases in the same manner
  • be unencumbered by JNDI-LDAP programming models
  • gain all other benefits that iBatis has to offer, since the LDAP-ness has been (mostly) abstracted away. For example, fine-tuning queries for performance can be done without changing Java code.
Using iBatis-over-LDAP instead of Spring-LDAP, you gain all of the above advantages, plus these:
  • all SQL is established declaratively (vs being constructed programmatically), facilitating maintenance and debugging
  • as a result, the DAO needs fewer properties - i.e., with Spring LDAP, the DAO needs things like the LDAP base, LDAP attribute(s) to be returned and a search-filter qualifier to configure the search method. However, using iBatis, all of these things are simply part of the SQL statement specified in the SQL Map file.
Spring-LDAP has a lot to offer, including numerous features that this solution lacks, and for many applications will be very suitable. In my opinion, its strongest value-add is the compensating transactional control in an LDAP environment. If our application was more demanding than it is, I'd be motivated to dig further into the Spring-LDAP feature set and would likely be all the more impressed - in my opinion, what the Spring team has been doing is the best thing to ever happen to J2EE, and their LDAP work is likely no exception. But for our application needs - very simple CRUD + Spring 3.0 AOP - the Spring LDAP module is not the right choice. The iBatis-over-LDAP solution is clean and simple, meeting our requirements with a minimum of fuss.

Resources

Using Spring-iBatis to access LDAP - Part 1
, by Gary Horton, July 2009
MyVD Virtual Directory: JDBC-LDAP Bridge
Spring LDAP 1.3.x Reference Documentation, by Mattias Arthursson, Ulrik Sandberg, Eric Dalquist, 2009 Spring Framework
Spring Framework 3.0.M3 Reference Documentation, by Rod Johnson, et. al, 2009 Spring Framework

Thursday, July 16, 2009

Using Spring-iBatis to access LDAP - Part 1

Introduction

As the Spring team points out, the standard JNDI-LDAP programming model is cumbersome, at best - and there's no question that the Spring-LDAP module simplifies that problem considerably, though not as completely as some would prefer. In a 2008 article, Colin Lu describes a homegrown facade using an iBatis-style framework to address his concerns with Spring-LDAP. Our own experience with Spring-LDAP has been a mixed bag, and in this 2-part series, I'll discuss another approach that leverages iBatis-over-LDAP directly. This first article starts with the JNDI-LDAP approach, looks at the improvements available with Spring-LDAP, and describes our attempt to leverage Spring-LDAP in a Spring 3.0 environment. Since that attempt was not successful, my followup article will present an alternate solution that layers Spring-iBatis over LDAP.

JNDI-LDAP Example

Ill start with the plain-vanilla JNDI-LDAP model, and evolve it in two steps - first to Spring-LDAP, and secondly using Spring-iBatis. As presented by Sunil D. Patil in his 2007 article, an example class might look something like this (key pieces are bold-faced so you can keep track of them as we evolve the program):

public class PlainLDAPDemo {
    private static final String LDAP_BASE = "dc=mybiz,dc=com";
    private static final String LDAP_USERNAME = "uid";
    private static final String LDAP_PROVIDER_URL = "ldap://127.0.0.1:389";
    private static final String LDAP_SECURITY_AUTHENTICATION = "simple";
    private static final String LDAP_SECURITY_PRINCIPAL = "cn=Manager,dc=mybiz,dc=com";
    private static final String LDAP_SECURITY_CREDENTIALS = "verycleverpassword";

    public static void main(String[] args) {

        Hashtable env = new Hashtable();
        env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
        env.put(Context.PROVIDER_URL, LDAP_PROVIDER_URL);
        env.put(Context.SECURITY_AUTHENTICATION, LDAP_SECURITY_AUTHENTICATION);
        env.put(Context.SECURITY_PRINCIPAL, LDAP_SECURITY_PRINCIPAL);
        env.put(Context.SECURITY_CREDENTIALS, LDAP_SECURITY_CREDENTIALS);

        DirContext ctx = null;
        NamingEnumeration results = null;
        try {
            ctx = new InitialDirContext(env);
            SearchControls searchControls = new SearchControls();
            searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);
            results = ctx.search(LDAP_BASE, "(objectclass=person)",
                    new String[]{LDAP_USERNAME}, searchControls);

            List<string> users = new ArrayList<string>();
            while (results.hasMore()) {
                SearchResult searchResult = (SearchResult) results.next();
                Attributes attributes = searchResult.getAttributes();
                Attribute attr = attributes.get(LDAP_USERNAME);
                String cn = (String) attr.get();
                users.add(cn);
            }
            Collections.sort(users);
            for (String user : users) {
                System.out.println(" UID = " + user);
            }

        } catch (NamingException e) {
            throw new RuntimeException(e);
        } finally {
            if (results != null) {
                try { results.close(); } catch (Exception ignored) {}
            }
            if (ctx != null) {
                try { ctx.close(); } catch (Exception ignored) {}
            }
        }
    }
}

As you can see, the bold-faced portions comprise the application-specific configuration, and are a small part of the overall program - most of the rest is boilerplate that can and should be factored out. That's what the Spring team has done for us.

Spring-LDAP Example

Mr. Patil does an excellent job of moving you from this verbose beginning to a lean Spring-LDAP treatment of the same program, so I won't repeat those details here. The transformation I came up with includes a test driver program, a DAO and a Spring configuration file. Here is my test driver:

public class SpringLDAPDemo {

    public static void main(String[] args) {

        Resource resource = new ClassPathResource("beans.xml");
        BeanFactory factory = new XmlBeanFactory(resource);
        UserDao ldapContact = (UserDao) factory.getBean("ldapContact");
        List<String> users = ldapContact.getAllUsers();

        Collections.sort(users);
        for (String user : users) {
            System.out.println(" UID  = " + user);
        }
    }
}

This is noticeably simpler client access. Here is the DAO:

public class UserDao { 

    private LdapTemplate ldapTemplate;
    private String ldapBase;
    private String ldapUsername; 
    private String searchQualifier; 

    public void setLdapTemplate(LdapTemplate ldapTemplate) { this.ldapTemplate = ldapTemplate; }

    public String getLdapBase() { return ldapBase; }

    public void setLdapBase(String ldapBase) { this.ldapBase = ldapBase; }

    public String getLdapUsername() { return ldapUsername; }

    public void setLdapUsername(String ldapUsername) { this.ldapUsername = ldapUsername; }

    public String getSearchQualifier() { return searchQualifier; }

    public void setSearchQualifier(String searchQualifier) { this.searchQualifier = searchQualifier; }

    public List getAllUsers() {

        return this.ldapTemplate.search(getLdapBase(), getSearchQualifier(),
                new AttributesMapper() {
                    public Object mapFromAttributes(Attributes attrs)
                            throws NamingException {
                        return attrs.get(getLdapUsername()).get();
                    }
                });
    }
}

Again, much cleaner than the original - perhaps even reusable. All of the application-specific configuration and most of the cruft has been factored out, thanks to Spring. Here's the Spring configuration that encapsulates application-specific details:

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
       http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

    <bean id="contextSource"
          class="org.springframework.ldap.core.support.LdapContextSource">
        <property name="url" value="ldap://127.0.0.1:389"/>
        <property name="userDn" value="cn=Manager,dc=mybiz,dc=com"/>
        <property name="password" value="verycleverpassword"/>
        <property name="pooled" value="true"/>
    </bean>
    <bean id="ldapTemplate" class="org.springframework.ldap.core.LdapTemplate">
        <constructor-arg ref="contextSource"/>
    </bean>
    <bean id="ldapContact" class="UserDao">
        <property name="ldapTemplate" ref="ldapTemplate"/>
        <property name="ldapBase" value="dc=mybiz,dc=com"/>
        <property name="ldapUsername" value="uid"/>
        <property name="searchQualifier" value="(objectclass=person)"/>
    </bean>
</beans>

Note that I'm working with the latest Spring-LDAP release, 1.3.0, and as such my packages and property names are slightly different from the 2.0.1-based example in Mr. Patil's article - in particular, please note the bold-italic sections above.

The Problem

Now, I'm also working with Spring 3.0 to gain the latest-and-greatest dependency injection, AOP and iBatis integration. Since the Spring LDAP Reference document claims that "...Spring LDAP 1.3 is supported on Spring 2.0 and later", I initially assumed I'd be OK. However, when my program is deployed as a standalone, it actually fails with this:

java.lang.ClassNotFoundException: org.springframework.dao.EmptyResultDataAccessException

I used an Ivy configuration to fetch dependencies for org.springframework.ldap, and in checking back with the artifacts from that retrieval, I found the missing class is available only in the 2.5.6 distribution (in particular, I needed org.springframework.transaction-2.5.6-SEC01.jar), so I would need to do some mixing-and-matching of 3.0 and 2.5.6 jars in my deployment to get this to work.

Yes, I had misgivings about this; the last thing I want is to experiment with combinations of libraries that might cause classloading or other runtime mismatches later on - a costly misadventure in a production environment. So my next step was to test drive the Spring-LDAP standalone with the 3.0 core and the 2.5.6 transaction libraries; this worked out just fine - the missing class is of course available and my simple test program succeeded without a problem. Next, I combined this program with another test driver that applies Spring AOP - but now this message appears:

Cannot convert value of type [$Proxy15 implementing org.springframework.ldap.core.LdapOperations,org.springframework.beans.factory.InitializingBean,org.springframework.aop.SpringProxy,org.springframework.aop.framework.Advised] to required type [org.springframework.ldap.core.LdapTemplate] for property 'ldapTemplate': no matching editors or conversion strategy

Removing Spring-LDAP from the mix of course remedies my AOP program - this is no surprise since the LdapTemplate is implicated in the error message above. Checking a little deeper, I find that the 2.5.6 transaction jar has many (if not all) of the same classes as the 3.0 transaction jar that I need to support my AOP configurations. So there's a growing doubt that I will succeed in a full-blown deployment, given the obvious concern around classloading problems, let alone how quickly I encountered the error as seen above.

Analysis of the Problem

Now, I could certainly take steps at this point to Google the error message (which, in fairness, I did - but I found no solution), experiment further, query the forums, and etcetera - but the cost/benefit of further effort here is a question mark. My mission is not to leverage Spring-LDAP; my mission is to establish a clean alternative to some existing JNDI-LDAP code. If Spring-LDAP worked without a hitch in my 3.0 deployment, I would choose that direction and move on. In fairness, and impressively enough, "it just works" has been the case for everything else I've tried so far with Spring 3.0 - injection, iBatis integration, AOP and in particular AOP-based transaction management. But here are some points about our application requirements, rationalizing why I'm reluctant to put much more effort into Spring-LDAP:
  1. Our LDAP-based use cases are dirt simple; this part of the application is not enterprise-scale. We need simple CRUD operations, nothing more. The path of least resistance here is to just wrap that CRUD in our own DAO facade and be done with it.
  2. The application itself, however, is enterprise-scale, and we're prototyping modern technologies like Spring to facilitate a rewrite of the web tier. The legacy web tier is a mix-and-match of more than a few technologies - Struts 1.x, Dojo, (massive amounts of) JavaScript, iFrames, JSTL, JSP, etc. - and is a poster child for a "how many different ways can we do the same thing?" approach. We are motivated this time to keep the technology selection down to a bare minimum, establish a minimal set of reusable patterns, choose frameworks that "just work" and think twice before going with things that have problems out of the gate. The resistance we're meeting here with Spring-LDAP in a 3.0-AOP context gives us cause for pause.
  3. While we could get around the deployment problems with Spring 3.0 AOP and 2.5.6 LDAP modules by isolating the LDAP component as a web service (e.g.), this begins to feel like overkill. This would add an extra network hop to retrieve information, and gives us one more point of failure (the new service) - this is probably not worth it, given #1 above, and especially since we'd be doing this only to enable use of Spring-LDAP. That's the tail wagging the dog.
Consider an Alternative Solution?

As such, I am now motivated to explore a second alternative to JNDI-LDAP, that of wrapping Spring-iBatis around a JDBC-LDAP bridge driver. But first, here are some points further validating my conclusion on #3 above, i.e. reluctance to use Spring LDAP in a separate service for our application:
  1. Clearly Spring-LDAP is a vast improvement over the JNDI-LDAP programming model. But, while the code is cleaner and simpler, it'sjust not that much code to worry about for our application (see #1 above).
  2. Spring-LDAP provides the ability to execute some business logic either before or after a search (but, we can also do this using regular Spring AOP, if I understand this feature correctly).
  3. We can optionally implement a method in the Spring-LDAP inner class that converts LDAP object into custom Java objects (but, we can also do this using an iBatis approach).
  4. Spring-LDAP provides the ability to create dynamic filters (but, this obscures the query being constructed since it's done in Java code. An iBatis approach simply externalizes the SQL in one place, supporting dynamic queries using parameterized templating).
  5. Likewise, basic CRUD idioms in Spring-LDAP are available; but these are also constructed procedurally in java code. Again, an iBatis approach is our preference.
  6. Spring-LDAP provides simplified "dynamic authentication" (i.e. an arbitrary user logging in to the LDAP system, as opposed to an implicitly declared principal as done in the example). However, this is not one of our requirements - the use of a single declaratively specified principal (via Spring configuration) is all we need.
  7. Spring-LDAP provides "compensating transaction support" - which is a solid improvement over the transaction-impaired LDAP environment - but we do not need this. From the Spring-LDAP docs: "The client side transaction support will add some overhead in addition to the work required by the original operations. While this overhead should not be something to worry about in most cases, if your application will not perform several LDAP operations within the same transaction (e.g. a modifyAttributes followed by a rebind), or if transaction synchronization with a JDBC data source is not required (see below) there will be nothing to gain by using the LDAP transaction support."
The list of Spring-LDAP features goes on, but for our application needs, none are compelling enough to warrant deploying it as a separate service (which for now is the only solution we have to get around the deployment issue with 3.0 AOP). In my next post, I'll present our solution that layers Spring-iBatis over the JDBC-LDAP bridge.

Resources

Spring Framework 1.3.x Reference Documentation, by Mattias Arthursson, Ulrik Sandberg, Eric Dalquist, 2009 Spring Framework
Simplify directory access with Spring LDAP, by Sunil D. Patil, 2007 JavaWorld
Extending Spring LDAP with an iBATIS-style XML Data Mapper, by Colin (Chun) Lu, 2008 JavaWorld
SpringSource Enterprise Bundle Repository
MyVD Virtual Directory: JDBC-LDAP Bridge
Simple Authentication Using Spring LDAP, by Mattias Arthursson, 2009 Spring Framework

Friday, June 26, 2009

AOP - Why should you care?

Here's a snippet that, as much as I hate to admit it, resembles some code that I've been known to write:

public class BusyBodyService
{
    public Object fetch() throws Exception
    {
        // trace entry
        log("Entered BusyBody");

        // start profiler
        startStopWatch();

        // check cache
        if (isCached())
        {
            return fetchFromCache();
        }

        // fetch from database - loop until connection made or bail out
        int numAttempts = 0;
        int maxRetries = 5;
        Exception t = null;
        Object retval = null;

        do
        {
            numAttempts++;

            // set isolation level
            setRepeatableRead();

            // start transaction
            startTransaction();

            try
            {
                // -------------- pure business logic starts here -------------- 
                retval = getFromDatabase();
                // -------------- pure business logic ends here -------------- 

                // commit transaction
                commit();

                // deal with various exceptions
            } catch (DatabaseDownException ex)
            {
                log("Database is down");
                // email administrator
                emailDBA("Database is down; you're working all weekend");
            } catch (NetworkDownException ex)
            {
                log("Network is down");
                // email administrator
                emailNetworkAdmin("Network is down; you're fired");
            } catch (Exception ex)
            {
                // rollback transaction
                rollback();
                System.out.println("Caught exception; retry attempt #" +
                    numAttempts);
                t = ex;
            } finally
            {
                // close database connection
                closeConnection();
            }
        } while (numAttempts <= maxRetries);

        if (retval == null)
        {
            throw t;
        }

        // save in cache
        cache(retval);

        // stop profiler
        stopStopWatch();

        // trace exit
        log("Exit BusyBody");

        return retval;
    }
}
Although I knew better, I didn't have the tools to factor out all the orthogonal concerns:
  1. tracing
  2. profiling
  3. caching
  4. retry strategy
  5. transaction isolation levels
  6. transactional wrapping
  7. dealing with specialized exceptions
  8. cleaning up connections and other resources
All of these things can be regarded as "aspects" - cross-cutting concerns that ideally are managed somewhere besides your business logic, even more ideally in a reusable manner such that e.g.  NetworkDownExceptions are always handled the same way, and the response can be managed with single point of change; or transaction isolation levels can be managed from a central place; and etcetera. Factoring out these aspects buys you a maintainable codebase and central management of orthogonal concerns - and this will save long-term costs. Your manager should care deeply about this - since it has been said that maintenance is 80% of the overall software lifecycle cost. And since it will facilitate getting the busy code snippet above to look more like this:
public class CleanAndElegantService
{
    public Object fetch() throws Exception
    {
        return getFromDatabase();
    }
}

...I'm thinking you might care about this also (I'm assuming there's no need to elaborate on this - the difference should speak for itself). In subsequent posts I'll explore Spring 3.x AOP to see if we can't factor out all the aspects and move from busy-body to clean-and-elegant.

Thursday, June 25, 2009

Getting Started with Spring 3.0 AOP

Choosing the latest-and-greatest of various technologies may serve you well, and it may also give you some headaches. For projects with longer timelines, it's useful to deploy your first GA with up-to-date infrastructure; but in spinning things up, you're subject to early-adopter pain. Here's my recent experience with Spring 3.0.0, in particular the AOP component of that framework, shortly after that version's first release. I'll assume you've already downloaded the 3.0.0 distribution and are motivated to test-drive Spring IoC and AOP functionality.

My prototyping began of course with basic Spring Core. Since, at the time of this writing, the Spring 3.x stuff is not in Spring's repository, I couldn't simply declare the org.springframework.core jar in an Ivy file and let Ivy do the dependency resolving for me; this is the first point of pain we're bumping into (and I'm sure there'll be more). Here's how I addressed this.

A very simple program that leverages Spring IoC required these jars (which I discovered attempting to run the program and simply observing what classes needed loading, and making some decent guesses as to what Spring distro jars would provide them) :

org.springframework.asm-3.0.0.M3
org.springframework.beans-3.0.0.M3
org.springframework.context-3.0.0.M3
org.springframework.core-3.0.0.M3
org.springframework.expression-3.0.0.M3

Testing my IoC program revealed additional non-Spring class-defs-not found, and long story short I added these:

antlr-3.0.1
commons-logging

With these in place, my IoC prototype ran just fine. Other dependencies may be called for if a more sophisticated program is used; but my intent here is not to itemize the exhaustive possibilities, rather it is to document how I went about figuring things out for your (and my) future reference.

From here, I wanted to do some proof-of-concept with the AOP stuff. From my read of the Spring developer guide, I concluded I want to use Spring AOP (vs. AspectJ), and I want to use the @AspectJ annotation-style approach. I won't go into my rationale here; that's a different topic. As our project unfolds, I'll provide more insights in future posts.

To use the AspectJ annotation-style, I began by placing the following into my Spring XML configuration file:

In the beans tag, add this attibute to declare the aop namespace:

xmlns:aop="http://www.springframework.org/schema/aop"

...and at the end of the beans tag body, add this declaration:

<aop:aspectj-autoproxy/>

Now, I run my program again; note that I've added no advise or pointcuts yet - I only want to get off the ground in establishing my dependencies, of which I'm sure some are now missing. Sure enough:
ClassNotFoundException: org.aopalliance.intercept.MethodInterceptor
Now, this one is obviously not a Spring Framework class; it's a third-party. I could probably use any repository to retrieve it, but I choose to use Spring's repository just to stay consistent. That repo is located at http://www.springsource.com/repository/app/. Interestingly enough, note that the trailing slash is a required part of this URL - my guess is that this is a RESTfully-constructed website in which the trailing slash indicates a collection, and without which the URL is not a valid identifier. But REST is, again, a different topic.

Searching for the missing class in Spring's repo, it offers me an Ivy entry, which I add to my ivy.xml and run the ivy:retrieve ant target. Here I'm assuming you have familiarity with Ant and Ivy, and know how to configure a simple Ivy environment; to digress on these topics here would make this post much too long, but I want to circle back eventually with a post on Ivy.

Running the Ivy retrieve task fetches the AOP Alliance library for me, and upon adding that to my project build, there is one more missing reference to an AspectJ class; I fetch this one using the same technique as above, choosing the 1.6.5. RELEASE version of AspectJ-Weaver. I rebuild with this in place, and re-run my program - this time, without any problems.

At this point, my goal is accomplished; I only wanted to get "off the ground" with Spring AOP. Now it's time to dig a little deeper and see what the AOP stuff has to offer.