Introduction to Java Services Orchestration for Actions In developing Web applications, we often see that business flow and logic are implemented together in actions, such as backing-beans in JavaServer Faces (JSF) and action classes in Struts. With the help of existing frameworks, e.g., Enterprise JavaBeans and Spring, we can separate business logic, but business flow remains embedded. Business process management (BPM) standards, e.g., Business Process Modeling Notation (BPMN) and Business Process Execution Language (BPEL), provide a way to separate business flow by describing it with XML-based documents. This approach also provides the benefit of being able to design applications based on service-oriented architecture (SOA). However, this approach doesn’t work well with “actions” in Web applications. The granularity of actions is too low for BPM/workflow products. They target higher scopes such as B2B applications and enterprise application integration, and assume business analysts will describe the processes as shown in Figure 1. But with lower granularity, like actions, the potential for flow reuse is greater. For a smaller scope, in this article, I propose the use of J-SOFA (Java Services Orchestration for Actions) for Java developers. J-SOFA is a framework for orchestrating services that correspond to a method of a class—either a plain-old Java object (POJO) or Web service. Due to the differences in granularity, J-SOFA doesn’t support asynchronous messaging, state management, monitoring, and so on, functionalities that BPM/workflow products available today support; but such unsupported functionalities could be supplied by working with said BPM/workflow products. This article’s services orchestration framework focuses specifically on improving reusability of business flow as well as services. Figure 2 illustrates that separated flows can be reused from other applications. Sample action in JSF Let’s take a look at some sample action code in a Web application developed using JSF. Our example is a simplified model search application, which responds with model information corresponding to the model ID the user entered. You can download all the source code for this sample from Resources. In the search form JSP (JavaServer Pages) page, there is a text box and a Submit button for entering the model ID. The JSP page invokes the showModel() method in a backing bean named ModelBean, as shown in Listing 1: Listing 1. inputText and Submit button in search.jsp <h:inputText id="modelId" value="#{ModelBean.modelId}" /> <h:commandButton type="submit" value="Submit" action="#{ModelBean.showModel}" /> To generate the model information page (search result page), the Model object and a list of features are created in showModel() and set into the properties: Listing 2. showModel() method in backing bean public String showModel() { if (modelId > 0) { ModelService modelService = new ModelService(); BeanUtils.copyProperties(this, modelService.create(modelId)); setFeatures(modelService.getFeatures(modelId)); } ... } Advanced developers can separate business logic from the action as shown in the above code. The logic for creating Model and features is implemented as a model service and is called through the interface. However, could we keep this method simple even if someone else took over maintenance of this backing bean? Doing so might prove difficult because all developers don’t understand the benefits of isolation between presentation and business tiers. If a developer with a different perspective handles maintenance, she/he might add business logic in showModel(). This situation is not unusual in projects because the programming language, like Java in this sample, allows us to implement any logic using its powerful expression ability. Therefore, we should use another language to implement business flow, instead of Java. From a framework point of view, it is important to prevent developers from indulging in putting flow and logic together. The language for describing business flow should make it difficult to implement logic, but at the same time, be expressive as a programming language. Current framework approaches need to be enhanced with BPM/workflow concepts. For this problem, I propose describing the flows as an XML-based document (process definition XML), which specifies which services need to be invoked and in which order. Thus, using J-SOFA, the flow in the showModel() method can be represented as follows: Listing 3. process.xml </pre> <process> <if test="${modelId > 0}"> <service name="modelService" operation="create"> <parameter value="${modelId}" type="int" /> <return name="model" /> </service> <pre class="prettyprint"><code/></pre> <service name="modelService" operation="getFeatures"> <parameter value="${modelId}" type="int" /> <return name="features" /> </service> </if> </process> <pre class="prettyprint"><code> In the XML, two operations of modelService are invoked using service tags, which correspond to methods implemented in the service component. They can be controlled by conditional and loop tags such as if, choose, or forEach. However, they aren’t as expressive as programming languages. In addition, J-SOFA doesn’t provide a way to execute methods in the model and features objects obtained from the service tags, except through getter methods. These constraints will complicate a developer’s ability to describe business logic in the XML document; however, they will help lead the developer to decide which business logic should be implemented in the service classes. With services-implemented business logic, we can develop applications based on SOA, which can quickly adopt various changes of the business model. Typical Web application frameworks such as JSF and Struts don’t support services orchestration. So we must write the following code to execute the process in the showModel() method: Listing 4. showModel() method to invoke the process </pre> public String showModel() { ProcessInstance process = new ProcessInstance("process.xml"); <pre class="prettyprint"><code/></pre> ProcessContext context = new ProcessContext(); context.put("modelId", modelId); process.execute(context); <pre class="prettyprint"><code/></pre> BeanUtils.copyProperties(this, context.get("model")); setFeatures((List) context.get("features")); ... } <pre class="prettyprint"><code> However, if the framework supported the functionality to invoke processes, we would not need to create actions. Instead, we would need to: Create process definition XML Create service components to be invoked from processes Write code to show values returned from the process in JSP page In this section, I explained that process definition XML defines a process for an action; however, some of the definitions can usually be reused in the real world. In the next section, I use another example to show how to reuse flows. Inheritable XML While creating processes, we often find some flows that can be shared with other processes. For example, I’ve created four pages, as shown in Figure 3: Model Overview, Model Features, and two types of Category Index pages. All the pages contain the same header and footer. Also the first two model pages use a Model object to show the model information, e.g., model name, and the last two category pages use a Category object. Finally, each page has its own page-specific processing. In this case, each flow, e.g., Model Features, can be expressed using the subProcess tag, which executes another process called the “sub-process”: Listing 5. modelFeatures.xml calling sub-processes (Note: In and after this listing, child tags in the service tag are omitted to simplify code) <process> <subProcess path="page.xml" /> ---------- (1) <subProcess path="model.xml" /> ---------- (2) <service name="modelService" operation="getFeatures" /> ----- (3) </process> The page and model processes are hidden in each sub-process, but we can still find a sequential flow from (1) to (3). So if we need to modify the flow, e.g., change the order to (2), (3), (1), the change would have to be realized in other processes as well. To resolve this problem, J-SOFA supports an approach based on inheritance. The basic idea is to provide a mechanism that allows overriding tags in a base process with the tags in the derived process. We can create a derived process using the extends attribute in the process tag. In this sample, the hierarchy of processes can be represented as shown in Figure 4. Figure 4. The hierarchy of processes Header and footer are defined in a base process, and model and category are defined as derived processes, which inherit tags for header and footer from the base process. Each process that represents a specific page can be described by extending from a model or category process. In page.xml, we generate a header and footer; however, we don’t know what contents are shown (model or category?). At the moment, the abstract tag, which is expected to be overridden by another tag in the derived process, can be applied: Listing 6. page.xml (base process) <process> <service id="header" name="commonService" operation="getHeader" /> <service id="footer" name="commonService" operation="getFooter" /> <abstract id="contents" /> </process> The model.xml, shown in Listing 7, is represented as a derived process from the page.xml. So page.xml is specified in the process tag’s extends attribute. In this XML block, we describe only the tags that we want to override. In this case, the group tag in model.xml overrides the abstract tag, which has the same ID "contents" in page.xml. At this time, we know the Model object must be created; however, we cannot determine which page calls this process. Hence, we delay the creation of a concrete process again, using the abstract tag for page-specific contents: Listing 7. model.xml (derived process) <process extends="page.xml"> <group id="contents"> <service name="modelService" operation="create" /> <abstract id="pageContents" /> </group> </process> The page-specific contents are described in modelFeatures.xml, shown in Listing 8, inherited from model.xml. All the services we need to create, except the features list, are already defined in the base process, so we can just override the abstract tag with the service tag to invoke the getFeature() operation. This way, developers can focus on describing processes related to the specific page. Listing 8. modelFeatures.xml (concrete process) <process extends="model.xml"> <service id="pageContents" name="modelService" operation="getFeatures" /> </process> When the process instance is instantiated, the three XML documents, page.xml, model.xml, and the modelFeatures.xml, are composed before execution, as illustrated in Listing 9. Listing 9. Composed process for Model Features <process> <service id="header" name="commonService" operation="getHeader" /> <service id="footer" name="commonService" operation="getFooter" /> <group id="contents"> <service name="modelService" operation="create" /> <service id="pageContents" name="modelService" operation="getFeatures" /> </group> </process> With the use of XML inheritance, developers can reuse the business flow described in the base process. Developers can also provide abstract processes, which define common flows, for other developers who describe page-specific processes. Conclusion The concept of describing business flow in XML-based documents is already implemented in BPM and workflow products. However, so far, it has been mainly used for higher-level business concerns. In this article, we have seen that the idea is also applicable in Web applications’ actions. The services orchestration framework will help direct developers in deciding which flows should be described in process XML and what logic should be implemented as services. As a result, applications will be designed and developed based on SOA, and reusability will be improved. Masayuki Otoshi develops Web applications for a manufacturing company as a senior developer. He is also in charge of the design and development of its frameworks. Web DevelopmentJavaTechnology Industry