Newsletter sign-up
View all newsletters

Enterprise Java Newsletter
Stay up to date on the latest tutorials and Java community news posted on JavaWorld

Sponsored Links

Optimize with a SATA RAID Storage Solution
Range of capacities as low as $1250 per TB. Ideal if you currently rely on servers/disks/JBODs

The PathProxy pattern: Persisting complex associations

Illustrated With JPA, Spring, and JSF

  • Print
  • Feedback

Page 3 of 7

Service and DAO layers

The application's service and DAO layers are also mostly vanilla flavored, except for the PathProxy stuff. Notice that I've gathered the common operations that can be used on any object into the CommonService interface. That way every persistent object doesn't require its own version of every operation, like the findById() method.

The PathProxyDAO class contains the heart of the logic that manages the PathProxy instances. This class provides us the CRUD capabilities for objects that rely on the PathProxy. Using it, we can add an object to a path, get objects of a type from a path, and remove objects from a path.

The Tree and EntityPath classes

The simple application has only a handful of backing beans. For getting into the PathProxy, the AjaxTreeBean is the most important. The AjaxTreeBean supplies data to the tree on the main page of the application.

As you know, there is a real issue with HTTP, which is that everything has to go over the wire as strings. Don't get me wrong, I love HTTP for what it's given us (simplicity, universal adoption, and a standard protocol). It's just ... well, everything is strings. That includes the paths we are representing in our system.

The AjaxTree used in the sample application was built using concepts explained in a previous JavaWorld article (see "The AjaxComponent strategy for JSF"). It represents every node with a nodeString. It is up to the application builder to decide how the nodeString is marshalled and unmarshalled.

When the AjaxTree is rendering, the first thing it needs to do is output the root nodes of the tree. You can see this in Listing 2.

Listing 2. AjaxTreeBean.getRootNodes()

public List<AjaxTreeNode> getRootNodes(){
        rootNodes = new ArrayList<AjaxTreeNode>();
        rootNodes.add(new AjaxTreeNode(Constant.PEOPLE, false, "People", Constant.PEOPLE));
        Long projectCount = commonService.getCount(Project.class);
        rootNodes.add(new AjaxTreeNode(Constant.PROJECTS, projectCount <= 0, "Projects", Constant.PROJECTS));
        return rootNodes;
    }


Listing 2 shows how the AjaxTreeBean provides the data necessary to render the root nodes of the tree. The AjaxTreeNode constructor's first argument is the NodeString. In the case of the root nodes, it's very simple. Those constants are strings. When someone clicks on the first root node, the AjaxTree will send back the string "people". It then falls to the method getChildNodes() to take that string and return a new list of nodes, representing the children of the people node.

Listing 3. AjaxTreeBean.getChildNodes() - part 1

public List getChildNodes(String nodeString){
        if (log.isInfoEnabled()) { log.info("BEGIN getChildNodes(): " + nodeString); }

        EntityPath path = this.getNewPath().setPathAsString(nodeString); // Get an EntityPath object representing the path

        ArrayList<AjaxTreeNode> children = new ArrayList<AjaxTreeNode>();
        if (path.equals(Constant.PEOPLE)){
            Long devCount = commonService.getCount(Developer.class);
            children.add(new AjaxTreeNode(Developer.class.getName(), devCount <= 0, "Developers"));

            Long managerCount = commonService.getCount(Manager.class);
            children.add(new AjaxTreeNode(Manager.class.getName(), managerCount <= 0, "Managers", "normal", "managers"));
        } else if (path.equals(Developer.class.getName())
                || path.equals(Manager.class.getName()) || path.equals(Project.class.getName())){
            try {
                children.addAll(this.getMoNodeList(commonService.getAll(Class.forName(path.toString()))));
            } catch (Exception e){
                throw new RuntimeException("Unknown type (classname expected): " + path);
            }
        // } else if...

        // Continued in Listing 4 ...


Listing 3 shows the first part of getChildNodes. The first thing we've done is to wrap the nodeString in an EntityPath object. You'll learn more about the EntityPath class in a bit. We've also tested whether the path is Constant.PEOPLE ("people"). If so, we create a couple more nodes, each with their own nodeStrings. The process can then repeat on the newly added nodes.

  • Print
  • Feedback

Resources
  • Download the sample application for this article, built with Spring, JPA/Hibernate, and JSF. The application build tool was Maven 2 and it was tested on Tomcat 6.
  • PathProxy isn't Matt Tyson's first published design pattern. Learn about his design strategies for Ajax-style development in JavaServer Faces: the AjaxCommand strategy and the AjaxComponent strategy, both published by JavaWorld.
  • The Spring Framework Documentation Section 3.3.4.1 explains Spring's lookup method injection.
  • See the JPOX homepage for a good discussion of JPA inheritance.
  • "Understanding the Java Persistence API" (Aditi Das, JavaWorld, January 2008) is a two-part introduction to Java-platform persistence with JPA. Part 2 walks through an example implementation of JPA annotations.
  • "J2EE design decisions" (Chris Richardson, JavaWorld, January 2006) explores five design patterns for implementing enterprise applications using lightweight frameworks such as Spring and Hibernate. An excerp from POJOs in Action; Manning Publications, January 2006.
  • "Get started with Hibernate" (Christian Bauer and Gavin King, JavaWorld, October 2004) is a short introduction to Hibernate written by its creator, Gavin King. Excerpted from Hibernate in Action; Manning 2004.)
  • Visit the JavaWorld Java Standard Edition research center for more articles about core Java programming tools, design patterns, and concepts.
  • Also see Network World's IT Buyer's Guides: Side-by-side comparison of hundreds of products in over 70 categories.