Thursday, June 6, 2013

Java Code Refactoring





I recently browsed again the excellent book Code Complete from Steve McConnell while in the middle of several Java code reviews. Although the book is nor specifically dedicated to Java code, I still found it quite useful and inspiring.

The chapter on refactoring in particular offers a very practical perspective that all programmer should have in mind when it comes to infuse a dose of evolution in the life cycle of their software.

What I found particularly valuable are the checklists that the author has put together: reasons to refactor, specific re-factorings (data level, statement level, routine-level, class-implementation, class-interface, system-level), refactoring safely, strategies, summary.

In this post, I would like to illustrate some of these refactoring techniques with java code snippets.

Since I do not have time to comment every item in these checklists, I decided to pick-up those that are not trivial or obvious and might bring the best return on your refactoring investment. These items are high-lighted in green and developed in sections at the end of this article.

If you think that missing items are worth explaining, please add a comment to this post and I will be glad to add a specific paragraph for those as well.







Checklist: Reasons to Refactor

  • Code is duplicate
  • A routine is too long
  • A loop is too long or too deeply nested
  • A class/interface/method has poor cohesion
  • A class interface does not provide a consistent level of abstraction
  • A parameter list has too many parameters
  • Changes within a class tend to be compartmentalized
  • Changes require parallel modifications to multiple classes
  • Inheritance hierarchies have to be modified in parallel
  • Related data items that are used together are not organized into classes
  • A routine uses more features of another class than of its own class
  • A primitive data type is overloaded
  • A class doesn't do very much
  • A chain of routines passes tramp data
  • A middle man object isn't doing anything
  • One class is overly intimate with another
  • A routine has a poor name
  • Data members are public
  • A subclass uses only a small percentage of its parents' routines
  • Comments are used to explain difficult code
  • Global variables are used
  • A routine uses setup code before a routine call or takedown code after a routine call
  • A program contains code that seems like it might be needed someday

 Checklist: Summary of Refactorings


Data Level Refactoring
  • Replace a magic number with a named constant
  • Rename a variable with a clearer or more informative name
  • Move an expression inline
  • Replace an expression with a routine
  • Introduce an intermediate variable
  • Convert a multi-use variable to a multiple single-use variables
  • Use a local variable for local purposes rather than a parameter
  • Convert a data primitive to a class
  • Convert a set of type codes to a class
  • Convert a set of type codes to a class with subclasses
  • Change an array to an object
  • Encapsulate a collection
  • Replace a traditional record with a data class
Statement Level Refactorings
  • Decompose a boolean expression
  • Move a complex boolean expression into a well-named boolean function
  • Consolidate fragments that are duplicated within different parts of a conditional
  • Use break or return instead of a loop control variable
  • Return as soon as you know the answer instead of assigning a return value within nested if-then-else statements
  • Replace conditionals with polymorphism (especially repeated case statements)
  • Create and use null objects instead of testing for null values
Routine Level Refactorings
  • Extract a routine
  • Move a routine's code inline
  • Convert a long routine to a class
  • Substitute a simple algorithm for a complex algorithm
  • Add a parameter
  • Remove a parameter
  • Separate query operations from modification operations
  • Combine similar routines by parameterizing them
  • Separate routines whose behavior depends on parameters passed in
  • Pass a whole object rather than specific fields
  • Pass specific fields rather than a whole object
  • Encapsulate downcasting ⇐ 

Class Implementation Refactorings
  • Change value objects to reference objects
  • Change reference objects to value objects
  • Replace virtual routines with data initialization
  • Change member routine or data placement
  • Extract specialized code into a subclass
  • Combine similar code into a superclass
Class Interface Refactorings
  • Move a routine to another class
  • Convert one class to two
  • Eliminate a class
  • Hide a delegate
  • Replace inheritance with delegation
  • Replace delegation with inheritance
  • Remove a middle man
  • Introduce a foreign routine
  • Introduce a class extension
  • Encapsulate an exposed member variable
  • Remove Set() routines for fields that cannot be changed
  • Hide routines that are not intended to be used outside the class
  • Encapsulate unused routines
  • Collapse a superclass and subclass if their implementations are very similar
System Level Refactorings
  • Duplicate data you can't control
  • Change unidirectional class association to bidirectional class association
  • Change bidirectional class association to unidirectional class association
  • Provide a factory routine rather than a simple constructor
  • Replace error codes with exceptions or vice versa

Selected items refactoring samples in java

  • A class/interface/method has poor cohesion
    • A class, interface or method should be only responsible for a precise and meaningful set of functionality and behavior. For example,the interface KitchenAppliance below lacks cohesion. A generic kitchen appliance should not allow to wash both clothes and dishes.
    •  
      public interface KitchenAppliance {
       public float waterConsumption = 0;
       public float energyConsumption = 0;
       void washClothes();
       void washDishes();
      }
      

              ⇒

      public interface WashingKitchenAppliance {
       public float waterConsumption = 0;
       public float energyConsumption = 0;
       void wash();
      } 
       
       
  • A class interface does not provide a consistent level of abstraction
    •  In Java, a consistent level of abstraction is usually obtained when the objects that represent abstract actors perform work, report on, change their state and communicate with other java objects in a a compatible and comparable way.
      The use of inheritance, encapsulation and polymorphism is usually the key to a consistent level of abstraction and is at the core of good design patterns. In the example below, an intermediary level of abstraction, e.g. DairyAnimal (cows, goats) and MeatAnimal (pigs, steers), could be created to avoid  specifying the type of food for each animal and focus on more specific features for the sub-classes.
    •  
      public class Animal extends LivingThing
      {
       private Location loc;
       private double energyReserves;
      
       public boolean isHungry() {
        return energyReserves < 2.5;
       }
       public void eat(Food food) {
        energyReserves += food.getCalories();
       }
       public void moveTo(Location location) {
        this.loc = location;
       }
      }
      
      thePig = new Animal();
      theCow = new Animal();
      if (thePig.isHungry()) {
          thePig.eat(tableScraps);
      }
      if (theCow.isHungry()) {
          theCow.eat(grass);
      }
      theCow.moveTo(theBarn);
       

       
      public class DairyAnimal extends Animal {
       private Double milkProduction;
      
       public Double getMilkProduction() {
        return milkProduction;
       }
              ...
      }
      
  • A parameter list has too many parameters
    • Methods with too many parameters is an indication that the code has either been badly designed initially (lack of abstraction) or has evolved over the months or years without proper refactoring. One elegant solution for creational methods/constructor requiring a large number of parameters is to use a builder pattern well define in Joshua Bloch's Effective Java and offers a way to use optional parameters:
    •  
      public NutritionFacts(int servingSize, int servings, int sodium, int iron, int fat, int carbs) {
           this.servingSize = servingSize;
           this.sodium = sodium;
           this.servingSize = servingSize;
           this.iron = iron;
           this.fat = fat;
           this.carbs = carbs;
      }
      
      NutritionFacts soda = new NutritionFacts(240, 8, 35, 13, 0, 27);
      

      public class NutritionFacts {
       private int servingSize = 0;
       private int servings  = 0;
       private int sodium  = 0;
       private int iron  = 0;
       private int fat  = 0;
       private int carbs  = 0;
      
       public static class Builder {
        private int servingSize;
        private int servings;
        private int sodium;
        private int iron;
        private int fat;
        private int carbs;
      
        public Builder(int servingSize, int servings) {
         this.servingSize = servingSize;
         this.servings = servings;
        }
        
        public Builder sodium(int val) {
         this.sodium = val;
         return this;
        }
        
        public Builder iron(int val) {
         this.iron = val;
         return this;
        }
      
        public Builder fat(int val) {
         this.fat = val;
         return this;
        }
      
        public Builder carbs(int val) {
         this.carbs = val;
         return this;
        }
        
        public NutritionFacts build() {
         return new NutritionFacts(this);
        }
       }
       
       private NutritionFacts(Builder builder) {
        servingSize = builder.servingSize;
        servings = builder.servings;
        sodium = builder.sodium;
        iron = builder.iron;
        fat = builder.fat;
        carbs = builder.carbs;
       }
      }
      
      NutritionFacts soda = new NutritionFacts(240, 8).build();
      or
      NutritionFacts soda = new NutritionFacts(240, 8).sodium(35).iron(13).fat(0).carbs(27).build();
      or
      NutritionFacts soda = new NutritionFacts(240, 8).sodium(35).iron(13).carbs(27).build();
      
      
  • Changes require parallel modifications to multiple classes
    • If you regularly have to modify the same set of classes then try to refactor these classes with the correct level of abstraction and factorization so changes only affect one class.
  • Related data items that are used together are not organized into classes
    • Recurrent set of operations can be combined in its own class:
    • theCow = new DairyAnimal();
      theCow.brush();
      theCow.feed();
      theCow.milk();
      theCow.feed();
      

      public class DairyAnimalOperation {
       public void tend(DairyAnimal dairyAnimal) {
        dairyAnimal.brush();
        dairyAnimal.feed();
        dairyAnimal.milk();
        dairyAnimal.feed();
      };
      
      Even better, refactoring can include the use of a flexible strategy pattern, if the recurrent process needs to be dynamically.
  • A chain of routines passes tramp data
    • "Tramp data" refers to passing data to one method so it can be passed to another one (Page-Jones 1988). This can be solved by introducing a better level of abstraction in the interfaces in question
  • Replace a magic number with a named constant
    • The word magic refers to the use of numeric or string literal. Use constants or Enums instead.
    • public double areaOfCircle (double radius)  {  
          return Math.pow(radius * 3.14159, 2);  
      }  
      

      private static final double PI = 3.14159;
      
      public double areaOfCircle (double radius)  {  
          return Math.pow(radius * PI, 2);  
      } 
      
  • Convert a multi-use variable to a multiple single-use variables
    • Common offenders are variable names like i,j, temp. These need to be replaced by specific names (e.g. row, column).
    • for (int i=0;i&tl;N;i++) {
          for (int j=0;j&tl;M;j++) {
             matrix[i][j] = 0; 
          }
      }
      

      for (int row=0;row&tl;numRows;row++) {
          for (int colum=0;colum&tl;numColumns;colum++) {
              matrix[row][colum] = 0; 
          }
      }
      
  • Encapsulate a collection
    • Instead of returning the collection itself, encapsulate a read-only collection instance with specific methods to add or remove elements in the original collection. You can leverage unmodifiable view methods that are part of the collection class for this:
    • public static <T> Collection<T> unmodifiableCollection(Collection<? extends T> c)
      public static <T> Set<T> unmodifiableSet(Set<? extends T> s)
      public static <T> SortedSet<T> unmodifiableSortedSet(SortedSet<T> s)
      public static <T> List<T> unmodifiableList(List<? extends T> list)
      public static <K,V> Map<K,V> unmodifiableMap(Map<? extends K,? extends V> m)
      public static <K,V> SortedMap<K,V> unmodifiableSortedMap(SortedMap<K,? extends V> m)
      
  • Replace conditionals with polymorphism
    • With polymorphism, subclasses of a class possesses their own specific behaviors and share also some of the functionality of their parent class. Refactor conditionals, especially complex case statements with polymorphism design:
    • Bike myBike = new Bike();
      String bikeType = "default";
      witch(myBike.getTireWidth()) {
       case 23 : 
        if (myBike.getSuspension().compareToIgnoreCase("Simple") == 0) {
         bikeType = "Road bike";
        }
       break;
       default : 
        if (myBike.getSuspension().compareToIgnoreCase("Dual") == 0) {
         bikeType = "Mountain bike";
        }
       break;
      }

             ⇒

      public class MountainBike extends Bicycle {
          private String suspension;
      
          public MountainBike(
                     int startCadence,
                     int startSpeed,
                     int startGear,
                     String suspensionType){
              super(startCadence,
                    startSpeed,
                    startGear);
              this.setSuspension(suspensionType);
          }
      
          public String getSuspension(){
            return this.suspension;
          }
      
          public void setSuspension(String suspensionType) {
              this.suspension = suspensionType;
          }
      } 
      
      public class RoadBike extends Bicycle{
          private int tireWidth;
      
          public RoadBike(int startCadence,
                          int startSpeed,
                          int startGear,
                          int newTireWidth){
              super(startCadence,
                    startSpeed,
                    startGear);
              this.setTireWidth(newTireWidth);
          }
      
          public int getTireWidth(){
            return this.tireWidth;
          }
      
          public void setTireWidth(int newTireWidth){
              this.tireWidth = newTireWidth;
          }
      }
      
  • Separate routines whose behavior depends on parameters passed in
    •  If you have a method which executes different statements based on a particular parameter value, figure out if you can break the method into separate ones without passing the parameter in question.
  • Encapsulate downcasting
    • Objects returned by a method should use the most specific type possible. 
    • public class A {
       public String doSomething() {
        return "Do something.";
       }
      }
      
      public class B extends A {
       public String doSomethingMoreSpecific() {
        return "Do something more specific.";
       }
      }
      
      public class DownCast {
      
       private List<A> list;
       
       public List<A> getList() {
        return list;
       }
      
       public List<B> getMostSpecificList() {
        return (List<B>) (List<?>) list;
       }
        
       public void setList(List<A> list) {
        this.list = list;
       }
      
       public DownCast() {
        list = new ArrayList<A>();
        for (int i=0;i<10;i++) {
         list.add(new B());
        }
       }
      
      }
      
      public static void main(String[] args) {
        
       DownCast obj = new DownCast();
       List<A> listOfA = obj.getList();
       System.out.println(listOfA.get(0).doSomething());
         
       List<B> listOfB = obj.getMostSpecificList();
       System.out.println(listOfB.get(0).doSomethingMoreSpecific());
          
      }
      
  •  Extract specialized code into a subclass
    • Refactor specialized code into specific own subclasses if the code in question is only used in a subset of initial classes.
  •  Hide a delegate
    •  If Class A calls B then C while A was supposed to only call B and B calls C, then dissociates C from A and have B calls C only.
  •  Remove a middle man
    • On the other hand, if you think that A should call C directly as long as the role of B is still clearly defines, does not have overlap with C and can be used independently of C.
  •  Encapsulate unused methods
    • Create new interfaces for the most common used set of methods
    • public class Bird {
       
       private String species;
       private String eggColor;
       private String food;
       private int flySpeed;
       private int flyHeight;
       private String dragType;
       private String wingType;
       
       public String getSpecies() {
        return species;
       }
       public void setSpecies(String species) {
        this.species = species;
       }
       public String getEggColor() {
        return eggColor;
       }
       public void setEggColor(String eggColor) {
        this.eggColor = eggColor;
       }
       public String getFood() {
        return food;
       }
       public void setFood(String food) {
        this.food = food;
       }
       public int getFlySpeed() {
        return flySpeed;
       }
       public void setFlySpeed(int flySpeed) {
        this.flySpeed = flySpeed;
       }
              ...
      }

             ⇒

       
      public interface BirdFlight {
       public int getFlySpeed();
       public void setFlySpeed(int flySpeed);
       public int getFlyHeight();
       public void setFlyHeight(int flyHeight);
       public String getDragType();
       public void setDragType(String dragType);
       public String getWingType() ;
       public void setWingType(String wingType);
      }
      
      public class Bird implements BirdFlight {
       
       private String species;
       private String eggColor;
       private String food;
       
       public String getSpecies() {
        return species;
       }
       public void setSpecies(String species) {
        this.species = species;
       }
       public String getEggColor() {
        return eggColor;
       }
       public void setEggColor(String eggColor) {
        this.eggColor = eggColor;
       }
       public String getFood() {
        return food;
       }
       public void setFood(String food) {
        this.food = food;
       }
       
       @Override
       public int getFlySpeed() {
        ...
       }
       @Override
       public void setFlySpeed(int flySpeed) {
        ...
       }
       @Override
       public int getFlyHeight() {
        ...
       }
       @Override
       public void setFlyHeight(int flyHeight) {
        ...
       }
       ...
        
      }
      
  •  Duplicate data you can't control
    • As long as layering principles are not violated, wrap or access data maintain by the system via a consistent way/interface/API. A typical examples is data shares in GUI control in the front-end layer. Try to find a way to copy/mirror the data in question and treat it as reference source of data.

Friday, May 17, 2013

Advanced UML Sequence Diagrams


A Sequence Diagram is a type of UML Interaction Diagram that is used to model objects that need to pass messages to accomplish a task.

The messages are usually defined in the order of the execution.

Objects interactions can include:
  • creation and termination
  • requests
  • invoke object operations
  • notifications
In the very simple sequence diagram below, a user sends a query to a health IT application that retrieve a clinical document to an XDS Repository. The clinical data is returned back to the user (an actor in this type of diagram).

Object colors can indicates a different scope between objects (e.g gray here indicate a component that is part of a different sub-system, or out-of-scope for the current document or release etc).
























Lifelines are vertical dashed lines with the object positioned at the top.  

Messages are horizontal lines with arrows pointing in the direction in which the message is sent with annotation (method, parameters, arguments, return value, type of control flow etc ...)










































UML 2.0 has two forms of messages:
  • operation call : the invocation of an operation of a receiving object (either synchronous or asynchronous)
  • signal : a message object sen out by one object and handle by another one (always asynchronous)




Synchronous messages usually have solid arrows (by the way, in the tool I use, return synchronous messages for not have a solid arrow). Asynchronous message use dashed arrows.


















An interaction operand is a container that groups the interaction fragments and uses an optional guard expression or interaction constraint. When the guard condition is not present, the interaction is always executed.

Interaction operators include:
  • Alternative (alt) 
  • Option (opt) : 
  • Break (break) :
  • Parallel (par)
  • Loop (loop)  
  • Critical (critical) or (region)
  • Negative (neg)
  • Assertion (assert)
  • Strict Sequence (strict)
  • Weak Sequence (seq)
  • Ignore (ignore)
  • Consider (consider)
Lets consider a simple alternative (alt) operand.

Imagine that in the initial sequence diagram, that we want to request a document, we request a clinical document from an external source (CCD producer system).

In this case, the first thing is to add a combined fragment on top of the existing diagram, and choose the alt type:
































Then conditions are added (if and else equivalent):






























Then you can add the new alternative message (to the external CCD producer system) and re-organize the layout of the diagram : placing the combined fragment below the incoming message and moving the else clause separation (dotted line) below the first alternative (accessing the XDS repository). In my tool, you can use ALT-Left-Mouse click for this:









There are numerous UML modeling tools available (commercial or free). For his post, I used Enterprise Architect.

Thursday, March 28, 2013

Richfaces Ajax CDI Push and JBoss



You may not know it, but when you go to a restaurant, you most likely to be served via a method called service à la russe (service in the Russian Style). This is in contradiction to the much older traditional service à la française (service in the French Style).

In the original French Style, all the food was brought from the kitchen into the dining room of the aristocrats or high clergy and served all at once. Then the cooks who lost their jobs during the French revolution, end-up opening places call restaurants to make a living when common people could come to eat and relax (from the verb se restaurer in French), meaning "to restore itself".

French serving style remains in some high class restaurants where small tables or guéridons are moved close to the guest's table where the food preparation is completed and served.



The buffet is a variation of the French Style where the guests help themselves from the table (in French it is traditionally a piece of furniture that looks like a table with drawers called in fact buffet).











On the other hand, the Russian Style that comes from Russia was introduced in the French restaurants during the 19th century where courses are brought to the table sequentially by the waiter. This is now the style in which most modern western restaurants serve food (with some significant modifications).

The place setting (called a cover) for each guest includes a service plate, all the necessary cutlery except those required for dessert, and stemmed glasses for water, wines and champagne

Guests immediately remove their napkins and place them in their laps.

The rule is as such: a filled plate is always replaced with an empty one, and no place goes without a plate until just before the dessert course.

Directly before dessert everything is removed from the place settings but the wine and water glasses. Crumbs are cleared and dessert is served.

As you can see, both styles have very precise rules and mechanisms that must be followed to ensure the best service.




Richfaces itself offers several Ajax server-side push mechanisms to bring data from the server to the client.

Interesting to point-out by the way, that a waiter in french is called "un serveur" (someone who serves) and that the same word is used to design a server in computer science.

These three Ajax Push methods are:
  • TopicsContext - accesses a RichFaces message queue directly
  • Push CDI - uses the CDI Event mechanism to fire messages
  • Push JMS - the RichFaces Push consumes messages from an enterprise messaging system and exposes them to the client (tightly coupled with the JMS runtime) 
In a previous article I was explaining how RichFaces Extended Data Tables can be enhanced.

In this article, I will describe how Richfaces Ajax Push CDI can be implemented and deployed specifically on a JBoss container (I am using JBoss application server 7.0)



The Richfaces showcase describes well as usual the java and JSF code needed to implements the CDI Ajax Push.  One thing though, the Push JMS mechanism in not explicated in the show case, but described in the chapter 3 of the documentation.

First what does CDI means?

If you look at your project  facets (I am using Eclipse IDE), you will see that CDI stands for Context and Dependency Injection.

Container/Context Dependency Injection in Java EE 6 decouples the processing threads of  event producers and event consumers by using the Observer pattern in the form of event broadcasting.

An event in CDI is just a regular POJO that can be fired by any class through the use of the Event implementation injected automatically by the container via the @Inject annotation.







 

import java.io.Serializable;

import javax.enterprise.context.RequestScoped;
import javax.enterprise.event.Event;

import javax.inject.Inject;
import javax.inject.Named;

import org.richfaces.cdi.push.Push;

@Named
@RequestScoped
public class PushCdiBean implements Serializable {

 private static final long serialVersionUID = 6414191802542861042L;
 public static final String PUSH_CDI_TOPIC = "pushCdi";
 private String message = "";

 @Inject
 @Push(topic = PUSH_CDI_TOPIC)
 Event<string>pushEvent;
 
 
 public void sendMessage() throws Exception {
  if (pushEvent == null) {
  } else {
   pushEvent.fire(message);
  }
  message = "";
 }

 public String getMessage() {
  return message;
 }

 public void setMessage(String message) {
  this.message = message;
 }
}

If you download the source code of the Richfaces showcase (I am using richfaces-4.3.1.Final), you will see that the readme file located under .\richfaces-4.3.1.Final\examples\richfaces-showcase describes useful steps necessary to deploy the sample application on various containers, including JBoss.



First, you need your Maven pom file to have both the Java API CDI and the atmosphere dependencies:
<dependency>
 <groupId>javax.enterprise</groupId>
 <artifactId>cdi-api</artifactId>
 <version>1.1-20130222</version> 
</dependency>
<dependency>
 <groupId>org.atmosphere</groupId>
        <artifactId>atmosphere-runtime</artifactId>
        <version>1.0.10</version>
</dependency>

To be able to inject your CDI bean, your WEB-INF folder needs to contain a bean.xml file:

<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:weld="http://jboss.org/schema/weld/beans" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://docs.jboss.org/cdi/beans_1_0.xsd http://jboss.org/schema/weld/beans http://jboss.org/schema/weld/beans_1_1.xsd"> </beans>

On your deployment platform, you need JBoss standalone configuration located in .\standalone\configuration\standalone-full.xml to have a JMS topic that match your Push CDI topic:


<jms-destinations>
 <jms-queue name="testQueue">       
  <entry name="queue/test"/>  
  <entry name="java:jboss/exported/jms/queue/test"/>
        </jms-queue>  
 <jms-topic name="pushCdi">
         <entry name="topic/pushCdi"/>  
 </jms-topic>     
</jms-destinations>


You also need to start the JBoss server in full configuration:























Another necessary step is  to create the JMS user account/password:

























From there, you should be able to test your Ajax CDI push application. In my case, the consumer is a popup window that I launch by clicking a button (see code below):

Producer code:

<ui:define name="body">
 <h:form id ="from">
  <a4j:commandButton value="Message Consumer"
   oncomplete="#{rich:component('cdi_message_consumer_popup')}.show();" />
  <h:panelGrid columns="4">
   <h:outputLabel value="Message:" />
   <h:inputText id="messageInput" value="#{pushCdiBean.message}"/>
   <a4j:commandButton value="Send" 
    action="#{pushCdiBean.sendMessage}"
    execute="@form" 
    render="messageInput" 
    oncomplete="#{rich:element('messageInput')}.value=''"/>
  </h:panelGrid>
 </h:form>
 <ui:include src="rf_ajax_push_consumer_popup.xhtml" />
</ui:define>

Consumer code:

<rich:popupPanel 
 id="cdi_message_consumer_popup" 
 modal="false"
 resizeable="false" top="100" 
 left="300" 
 autosized="true"
 domElementAttachment="parent">
 <f:facet name="header">
  <h:outputText value="Ajax Push/CDI Message Consumer    " />
 </f:facet>
 <f:facet name="controls">
  <h:outputLink value="#"
   onclick="#{rich:component('cdi_message_consumer_popup')}.hide(); return false;">
   <h:outputText value="X" styleClass="textHeader" />
  </h:outputLink>
 </f:facet>
 <h:form>
  <h:panelGrid columns="3">
   <a4j:push address="pushCdi" 
    onerror="alert('error: ' + event.rf.data)"
    ondataavailable="jQuery('<li />').prependTo('#messages').text(event.rf.data)">
   </a4j:push>
   <ul id="messages" />
  </h:panelGrid>
 </h:form>
</rich:popupPanel>















The message (simple string) is send to the server and pushed back to the browser. The original message is then cleaned:
















A big thank to my colleague Asha Ambikavijayakumaran for figuring out all the tricky details for the JBoss deployment for this Richfaces showcase!


All ingredients and open source code related to this recipe can be found at YummyCode on the JSF Plate project.





Saturday, February 9, 2013

Advanced RichFaces Extended Data Tables

 
With Mardi Gras and Carnival around the corner, this is crêpe season!

This post is the first of a set of recipes that describe useful tips and reusable code and patterns related to Java, JSF 2.0 and RichFaces 4.0.  In this article I am describing practical integration code when using advanced Richfaces Extended Data Tables.

The RichFaces showcase describes well how to start creating your own extendedDataTable. However, here are some additional personal ingredients that can be very handy when preparing an appealing stack of JSF based web pages.





1) Setting your Table

The first time your try to put together a RichFaces extendedDataTable, you might encounter the following behavior: your table does not look like as you expected it: columns have a default size (the length of the label) and the whole size is the size of your whole window, so you end up with a large white space where they are no columns:


 One reason could be that no column or table size has been specified:


 <rich:extendedDataTable id="table" value="#{countries.countryItems} var="country" >
    <f:facet name="header">
        <h:outputText value="Countries" />
    </f:facet>
    <rich:column>
        <f:facet name="header">
            <h:outputText value="Name" />
        </f:facet>
        <h:outputText value="#{country.name}" />
    </rich:column>
    <rich:column>
        <f:facet name="header">
            <h:outputText value="Capital" />
        </f:facet>
        <h:outputText value="#{country.capital}" />
    </rich:column>
    <rich:column>
        <f:facet name="header">
            <h:outputText value="Language(s)" />
        </f:facet>
        <h:outputText value="#{country.languages}" />
    </rich:column>
</rich:extendedDataTable>


One way to quickly fix this is to assign specific sizes to your columns and headers (in my case these are absolute values in pixels and have adjusted the values to take into account the height of a row and the presence of a vertical scroller).  I have also added single selection mode so I can click on a row to retrieve more information about a certain item:

<rich:extendedDataTable id="table" value="#{countries.countryItems}"
    var="country" selection="#{countries.selection}" 
    style="height:190px; width:503px;"
    selectionMode="single">
    <a4j:ajax execute="@form" event="selectionchange" listener="#{countries.selectionListener}"/>
        <f:facet name="header">
            <h:outputText value="Countries" />
        </f:facet>
        <rich:column width="100px">
            <f:facet name="header">
                <h:outputText value="Name" />
            </f:facet>
            <h:outputText value="#{country.name}" />
        </rich:column>
        <rich:column width="100px">
            <f:facet name="header">
                 <h:outputText value="Capital" />
            </f:facet>
            <h:outputText value="#{country.capital}" />
        </rich:column>
        <rich:column width="300px">
            <f:facet name="header">
                <h:outputText value="Language(s)" />
            </f:facet>
            <h:outputText value="#{country.languages}" />
        </rich:column>
</rich:extendedDataTable>
















2) Interaction improvements

Let say now that you want to add a button to load or refresh the information in the table and that this takes some time because you are connected to a remote service. You may want to show to the end-user an indicator that some processing or data retrieval is happening (for this example, I added a waiting function in the iem list bean to simulate a few seconds wait).

I propose to use an animated GIF and take advantage of the RichFaces a4j:status (an indicator of an Ajax request. It has two states: start and stop. The start state indicates that an Ajax request is in progress. When an Ajax response is returned, the component switches to the stop state).

In this case, I refer to a4j:status every time I click on the refresh button to download the countries statistics. I have also added an animated GIF file called processing.gif in my webapp/img folder and top aligned both the button and the ajax indicator into a JSF panel grid:


<h:panelGroup>
    <h:panelGrid columns="2" columnClasses="alignTop, alignTop">
        <a4j:commandButton value="Refresh" status="refreshTable"
     oncomplete="#{countries.refresh()}" />
        <a4j:status name="someProcessing">
            <f:facet name="start">
         <h:graphicImage value="/img/processing.gif" />
     </f:facet>
        </a4j:status>
    </h:panelGrid>
</h:panelGroup>

As a result, the processing indicator appears next to the button when it is clicked and disappear after the table has been refreshed.


















In fact, you can use the same indicator when selecting a row to display detailed information about an item if the retrieval of the additional information takes too long for the user (e.g. more than a couple of seconds):


<a4j:ajax execute="@form" event="selectionchange" status="someProcessing" listener="#{countries.selectionListener}" />


3) Adding some coloring and flavor

If you don't have a predefine look and feel (e.g. a reusable template or UI toolkit), you can easily use the themes and skins that come with RichFaces.  A skin can be quickly added to the web.xml file as follow:


<context-param>
    <param-name>org.richfaces.skin</param-name>
    <param-value>wine</param-value>
</context-param>

Some of my favorites predefined skins are deepMarine and wine:

 
















4) The missing ingredients

Even though the RichFaces Extended Data Tables have a lot of features such as filtering, sorting, scrolling, frozen columns, here are always missing ingredients that you would like to use to offer a better experience to the end user. One that you will not find in the ExtendedDataTable is the wrapping of text in a column or a robust column horizontal scrolling. Hopefully this feature will be added in future release.


5) Always give a tip if you can

Offering tips is generally a good practice. It makes feel everybody happy: the person who provides it knowing that he/she has done a good job, and the end-user who enjoys it and saves time using them.

In this example, I have added a column to to indicate which countries have a GDP above one Trillion US Dollars. When the use hovers the mouse above the checkbox or the name of the country, a tooltip appears and shows the GDP number for the selected country.

















Tooltips can be easily added as follow:

<rich:column styleClass="#{msg.status}" width="35px">
    <f:facet name="header">
        <h:outputText value="GDP > $1T" />
    </f:facet>
    <rich:tooltip mode="client" target="largeGDPCountry">
        <h:outputText value="#{country.name} - 2011 GDP: #{country.gdp} > $1T" />
    </rich:tooltip>
    <h:graphicImage id="largeGDPCountry" value="/img/checkmark.png" rendered="#{country.largeGdp}" alt="GDP" />
</rich:column>
<rich:column width="100px">
    <f:facet name="header">
        <h:outputText value="Name" />
    </f:facet>
    <h:outputText id="countryName" value="#{country.name}" />
    <rich:tooltip mode="client" target="countryName">
        <h:outputText value="#{country.name} - 2011 GDP: #{country.gdp} $M" />
    </rich:tooltip>
</rich:column>


Ingredients and open source code related to this recipe can be found at YummyCode on the JSF Plate project.

Friday, September 28, 2012

Multitenancy and Healthcare Software Applications

 
Virtualization abstracts  the running stack and components in order to have services users to appear to run on a separate physical machine has been an earlier attempt to lower the cost of resources. In fact, virtualization has brought tremendous progresses in heath care for the development, testing and running applications during the past 10 years or so. However multitenancy goes one step further.

Multitenancy is at the core of the design of Web based applications offered as Software as a Service (SaaS). In a multitenant software application, the service offered to each client organization (e.g. in healthcare that would be a physician office, a lab, a clinic ...)  is virtually partitioned. Data and configuration are separate for each organization that use the service. This is required to ensure the confidentiality of the patient records.

In a multitenancy architecture, the same set of hardware, network resources, software stack, application code base are shared between all users of the service. As a result, SaaS applications are managed and delivered more efficiently at a lower cost.



Here is a subset of the services management tasks that can be greatly simplified by a multitenancy architecture :
  • patch deployments
  • GUI, API and platform/stack upgrades
  • data migration
  • customizations
  • customer support
  • monitoring
  • reporting
The amount of resource: hardware, network and IT staff, dedicated to a specific application is drastically reduced from a model where every organization has its own instance. In addition to this, multitenancy tends to benefit the whole user set of a particular service, since defects fixes and new features are deployed incrementally very frequently. Agile development process methodologies such as Scrum are particularly suitable for this technology since development and deployment cycles can be extremely short.

This can be critical in healthcare when several organizations such as hospitals, labs and pharmacies using the same service, need to exchange data across an Health Information Exchange or a Regional Health Information Organization). In this case, all end-points of the HIE have to use the same data format , the same protocols and security scheme. Is parts or all of the end-points are running in a multitenant architecture, then the orchestration of all end-points is facilitated greatly.  For example, every time a new service functionality is deployed available, all end-points have access to it and are compatible. Moreover, maintenance such are the provisioning and re-provisioning of user credentials and security certificates is simplified. Finally monitoring and  reporting such as meaningful use are much easier to implement and deploy.

The unified architecture and deployment topology (for development, QA testing, staging and production), makes the application cheaper to develop, deploy and maintain. In healthcare software development, it can take more than a year to acquire not only the necessary IT skills, but also knowledge of the domain.This is why it is very difficult to hire, train  and keep qualified engineers, support and administration specialists, and the demand is growing.  With a multitenancy model, more and better services can be developed and maintained with the same engineering and IT workforce. The support specialists can then refocus their efforts on solving end-users problems related to healthcare rather than pure IT infrastructure and improve customer satisfaction overall.

Further more, multitenancy provides much greater performance, scalability and maintainability as applications are generally hosted on elastic cloud infrastructures and platforms. Even though more and more vendors offer cloud based products from basic elastic resources through infrastructure as a Service (IaaS), or a full customizable development and deployment cloud based platform (PaaS), professional healthcare IT professionals are still reluctant to have their patient's records hosted on commercial public clouds. Obviously, offloading generic healthcare related services that do not contain any PHI information (e.g. ICDx, HL7, SNOMED taxonomy and terminology services) can certainly be realized from private to public cloud if needed. On the other hand, when any patient demographic information or clinical data is included, healthcare IT decision makers needs assurances that the data is always secure and the applications and processes involved are in compliance with HIPAA regulation. One minimum requirement for example is that all protected data must be encrypted at rest and in flight at all time. Other legal requirements in certain states also require that the patient's data stays within the limit of the states and this can be an issue when physical servers on public clouds can reside anywhere.

The migration of legacy single tenant applications to multitenant based services is definitively challenging and requires new paradigms (e.g. metadata driven architecture and data models, polymorphic applications), new tools and platforms and engineers and IT personnel familiar with this new model and its related technologies. Multitenancy is an essential part of the whole cloud computing market for the healthcare industry that is estimated to grow to $5.4 billion by 2017.

Multitenancy is certainly one of the most critical technologies that will drastically help improve the efficiency of healthcare, reduce cost and will be the base of business intelligence and data warehousing solutions to make better health predictions and decisions for the overall population.

Wednesday, June 13, 2012

How to create a simple CXF based JAX-RS Client

 
In my previous blog post, I did explain how to create a REST API using CXF and Spring.

This time I would like to describe how to quickly create a client that can call the REST API while reusing the resources POJO classes,
so the un-marshalling is done by JAXB.

For this I am using the CXF WebClient which is very simple to use:

  • import WebClient from org.apache.cxf.jaxrs.client.WebClient
  • import your POJOs
  • import a JABX provider (I am using Jackson JAXB JSON provider)

 Here is a very simple standalone program that does exactly this (make sure your REST API has been deployed locally):
 
import com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider;
import org.apache.cxf.jaxrs.client.WebClient;
import java.util.ArrayList;
import java.util.List;

public class App 
{
    public static void main( String[] args )  throws Exception { 
      
     List<Object> providers = new ArrayList<Object>();
     providers.add( new JacksonJaxbJsonProvider() );
   
     WebClient client = WebClient.create("http://localhost:8080/poc_restapi_cxf/api", providers);
     client = client.accept("application/json").type("application/json").path("/order").query("id", "1");
   
     Order order = client.get(Order.class);
     System.out.println("Order:" + order.getCustomerName());
  
    }
}
With this very simple client program, the response to your request (JSON) is automatically unmarshalled to a Java object. 

If you are using maven, make sure you have the correct dependencies in your pom file:
    <dependency>
       <groupId>org.apache.cxf</groupId>
       <artifactId>cxf-rt-transports-http</artifactId>
       <version>${cxf.version}</version>
       <scope>provided</scope>
    </dependency>
   
    <dependency>
       <groupId>org.apache.cxf</groupId>
       <artifactId>cxf-rt-rs-extension-search</artifactId>
       <version>${cxf.version}</version>
       <scope>provided</scope>
    </dependency>
     
    <dependency>
       <groupId>org.apache.cxf</groupId>
       <artifactId>cxf-rt-rs-extension-providers</artifactId>
       <version>${cxf.version}</version>
       <scope>provided</scope>
    </dependency>
      
    <dependency>
    <groupId>com.fasterxml.jackson.jaxrs</groupId>
       <artifactId>jackson-jaxrs-json-provider</artifactId>
       <version>2.0.2</version>
    </dependency> 

Tuesday, May 29, 2012

REST API with CXF and Spring

 

For the past couple of years, I have developed REST APIs using RESTEasy since the target deployment platform was JBOSS. More recently I have considered using Apache CXF instead. One reason is that we wanted to use a single technology to create web services (we are using CXF for our SOAP based web services).

In this article I will show how to create a very simple REST web service using CXF and Spring and describe how to deploy it on JBOSS AS 7.0.

I have found several tutorials describing how to create CXF based REST web services but none with Spring  and working when deployed on JBOSS AS 7.0. Part of the proof of concept (POC) code sample I am describing in this article come from Sandeep Bhandari article "REST Web Service Using CXF - Beginner's Tutorial" which I enriched with Spring integration and deployment configuration for JBOSS AS 7.0.




In my POC example, there is not much differences for the POJO classes representing the order resources (I made them a little bit simple):








class Order
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name = "order")
public class Order {
 
    private String itemName;
    private int quantity;
    private String customerName;
    
    @XmlElement
    public String getItemName() { return itemName; }
    
    public void setItemName(String itemName) { this.itemName = itemName; }
    
    @XmlElement
    public int getQuantity() { return quantity; }
    
    public void setQuantity(int quantity) {
        this.quantity = quantity;
    }
    
    @XmlElement
    public String getCustomerName() { return customerName; }
    
    public void setCustomerName(String customerName) { this.customerName = customerName; }
}
 
class OrderList
import java.util.ArrayList;
import java.util.List;

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name = "OrderList")
public class OrderList {

    List orders;
   
    @XmlElement(name = "order")
    public List getOrder() {
        if (orders == null) {
            orders = new ArrayList();
        }
        return this.orders;
    }
}
 
The web.xml file specify only the CXF servlet:
<web-app>

    <display-name>Archetype Created Web Application</display-name>
   
 <servlet>
  <servlet-name>CXFServlet</servlet-name>
  <servlet-class>
   org.apache.cxf.transport.servlet.CXFServlet
  </servlet-class>
   <load-on-startup>1</load-on-startup> 
 </servlet>

 <servlet-mapping>
  <servlet-name>CXFServlet</servlet-name>
  <url-pattern>/api/*</url-pattern>
 </servlet-mapping>
 
</web-app> 
 
The file cxf-servlet.xml specify the service bean and the JAX-RS providers:
 <beans 
    xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
 xmlns:beans='http://www.springframework.org/schema/beans'
 xmlns:jaxrs="http://cxf.apache.org/jaxrs"
 xmlns:context="http://www.springframework.org/schema/context"
 xsi:schemaLocation="
 http://www.springframework.org/schema/beans 
 http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
 http://cxf.apache.org/jaxrs 
 http://cxf.apache.org/schemas/jaxrs.xsd
 http://www.springframework.org/schema/context 
 http://www.springframework.org/schema/context/spring-context.xsd">
  

  <jaxrs:server id="restContainer" address="/" >
  
            <jaxrs:serviceBeans>
        <ref bean="simpleService" />
     </jaxrs:serviceBeans>  
     
           <jaxrs:providers>
               <ref bean="jaxbProvider"/>
               <ref bean="jsonProvider"/> 
           </jaxrs:providers>
      
        </jaxrs:server>
     
     <bean id="simpleService" class="com.acme.poc.restapi.cxf.service.SimpleServiceImpl" />
  <bean id="jaxbProvider" class="org.apache.cxf.jaxrs.provider.JAXBElementProvider"/>  
  <bean id="jsonProvider" class="org.codehaus.jackson.jaxrs.JacksonJsonProvider" />
  
</beans> 
 
The SimpleService interface: 
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;  

@Path("/order/")
public interface SimpleService {
 @GET
 @Produces("application/xml")
 @Path("{orderId}")
 public Order getOrderXml(@PathParam ("orderId") int id);
 
 @GET
 @Produces("application/json") 
 @Path("/")
 public Order getOrderJson(@QueryParam("id") @DefaultValue("-1") String strId);
 
 @GET
 @Produces("application/xml")
 @Path("all")
 public OrderList getAllOrders();
} 
 
The SimpleServiceImpl class: 
import java.util.ArrayList;
import java.util.List;

public class SimpleServiceImpl implements SimpleService {
 
 List list = new ArrayList();
 
 public SimpleServiceImpl () {
         Order order = new Order();
         order.setItemName("Veggie Pizza");
         order.setQuantity(9);
         order.setCustomerName("OptumInsight");
         list.add(order);
         
         order = new Order();
         order.setItemName("Green Salad");
         order.setQuantity(2);
         order.setCustomerName("OptumInsight");
         list.add(order);
  }
 
 @Override
    public Order getOrderXml(int id) {
   return getOrder(id);
    }
 
 @Override
 public Order getOrderJson(String strId) {
  int id = Integer.valueOf(strId);
  return getOrder(id);
 }
 
 @Override
 public OrderList getAllOrders() {
  OrderList fullList = new OrderList();
        for(Order order : list) {
         fullList.getOrder().add(order);
        }
        return fullList;
 }
 
 // Common method returning an Order POJO
 public Order getOrder(int id) {
  if ((id > 0) && (id <= list.size())) {
   return list.get(id - 1);
  }
         else
          return null;
 }
}
 
Finally the pom.xml file for maven: 
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.acme.poc.restapi</groupId>
  <artifactId>poc_restapi_cxf_client</artifactId>
  <version>1.0</version>
  <packaging>jar</packaging>

  <name>poc_restapi_cxf_client</name>
  <url>http://maven.apache.org</url>
  
    <properties>
      <spring.version>3.1.0.RELEASE</spring.version>
      <cxf.version>2.6.0</cxf.version>
      <jackson.version>1.9.7</jackson.version>
      <junit.version>4.8.1</junit.version>    
   </properties>
  
   <dependencies>
   
     <dependency>
        <groupId>org.apache.cxf</groupId>
        <artifactId>cxf-rt-transports-http</artifactId>
        <version>${cxf.version}</version>
   <scope>provided</scope>
     </dependency>
   
     <dependency>
      <groupId>org.apache.cxf</groupId>
      <artifactId>cxf-rt-rs-extension-search</artifactId>
      <version>${cxf.version}</version>
    <scope>provided</scope>
     </dependency>
     
     <dependency>
      <groupId>org.apache.cxf</groupId>
      <artifactId>cxf-rt-rs-extension-providers</artifactId>
      <version>${cxf.version}</version>
    <scope>provided</scope>
     </dependency>
  
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>${junit.version}</version>
      <scope>test</scope>
    </dependency>
    
  </dependencies>
  
  <build>
    <finalName>poc_restapi_cxf_client</finalName>
     <plugins>
         <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>2.3.2</version>
            <configuration>
               <source>1.6</source>
               <target>1.6</target>
               <encoding>UTF-8</encoding>
            </configuration>
         </plugin>
    </plugins>
  </build>
</project>



The file jboss-deployment-structure.xml is used for JBOSS deployment: 
<jboss-deployment-structure>
 <deployment>
  <dependencies>
   <module name="org.apache.cxf" services="import">
    <imports>
     <include path="**" />
    </imports>
   </module>
  </dependencies>
 </deployment>
</jboss-deployment-structure>
 
 
In addition to this, before you deploy on JBOSS, you need to make some modifications on your web application server:

1) Download the latest edition of CXF (2.6.0) and placed just one jar from the distribution into the folder /modules/org/apache/cxf/main/cxf-2.6.0.jar (This contains all of the CXF codebase, except the dependencies)
  
2) Open /modules/org/apache/cxf/main/module.xml
   Remove all resource elements (the JARs)
   Add a new resource element similar to the deleted ones with cxf-2.6.0.jar being the only Jar referenced
   Add dependency to module named: javax.ws.rs.api :


<module xmlns="urn:jboss:module:1.1" name="org.apache.cxf">
   <resources>
        <resource-root path="cxf-2.6.0.jar"/>
        <!-- 
        <resource-root path="cxf-api-2.4.4.jar"/>
          ...
        <resource-root path="cxf-xjc-ts-2.4.0.jar"/> 
        -->
    </resources>
     <dependencies>
        <module name="asm.asm" />
        <module name="javax.api" />
        <module name="javax.annotation.api" />
        <module name="javax.jms.api" />
        <module name="javax.jws.api" />
        <module name="javax.mail.api" />
        <module name="javax.resource.api" />
        <module name="javax.servlet.api" />
        <module name="javax.ws.rs.api" />
        <module name="javax.xml.bind.api" services="import"/>
        <module name="com.sun.xml.bind" services="import"/>
        <module name="javax.wsdl4j.api" />
        <module name="javax.xml.soap.api" />
        <module name="javax.xml.stream.api" />
        <module name="javax.xml.ws.api" />
        <module name="org.apache.commons.lang" />
        <module name="org.apache.neethi" />
        <module name="org.apache.velocity" />
        <module name="org.apache.xml-resolver" />
        <module name="org.apache.ws.xmlschema" />
        <module name="org.apache.ws.security" />
        <module name="org.apache.santuario.xmlsec" />
        <module name="org.springframework.spring" optional="true"/>
    </dependencies>
</module> 
 
3) Create folder /modules/org/springframework/spring/main/
   Create module.xml
   Copy all the text from the CXF module.xml into this new one
   Erase the last dependency (itself)
   Erase the resource against cxf JAR  (because this is the copy for spring)
   Download latest Spring framework, and copy all the Spring jars into the folder
   Add all of these JARs to the module.xml inside tag.
   Add dependency to module named: org.apache.commons.logging 


<module xmlns="urn:jboss:module:1.1" name="org.springframework.spring">
    <resources>
  <resource-root path="spring-aop-3.1.0.RELEASE.jar" />
  <resource-root path="spring-asm-3.1.0.RELEASE.jar" />
  <resource-root path="spring-beans-3.1.0.RELEASE.jar" />
  <resource-root path="spring-context-3.1.0.RELEASE.jar" />
  <resource-root path="spring-core-3.1.0.RELEASE.jar" />
  <resource-root path="spring-expression-3.1.0.RELEASE.jar" />
  <resource-root path="spring-web-3.1.0.RELEASE.jar" />
        <!-- Insert resources here -->
    </resources>
    <dependencies>
        <module name="asm.asm" />
        <module name="javax.api" />
        <module name="javax.annotation.api" />
        <module name="javax.jms.api" />
        <module name="javax.jws.api" />
        <module name="javax.mail.api" />
        <module name="javax.resource.api" />
        <module name="javax.servlet.api" />
        <module name="javax.xml.bind.api" services="import"/>
        <module name="com.sun.xml.bind" services="import"/>
        <module name="javax.wsdl4j.api" />
        <module name="javax.xml.soap.api" />
        <module name="javax.xml.stream.api" />
        <module name="javax.xml.ws.api" />
        <module name="org.apache.commons.lang" />
        <module name="org.apache.commons.logging" />
        <module name="org.apache.neethi" />
        <module name="org.apache.velocity" />
        <module name="org.apache.xml-resolver" />
        <module name="org.apache.ws.xmlschema" />
        <module name="org.apache.ws.security" />
        <module name="org.apache.santuario.xmlsec" />
    </dependencies>
</module>