Ok

En poursuivant votre navigation sur ce site, vous acceptez l'utilisation de cookies. Ces derniers assurent le bon fonctionnement de nos services. En savoir plus.

Blog de Nicolas DUMINIL Simplex Software - Page 17

  • Make services, not scripts !

    As I’m saying often, scripts are the level zero of the software development and integration. By scripts, I’m reffering to these sequences of command lines ran by the Unix shell. And when I say that they represent the level zero of the software, I don’t mean to deny their utility to automate simple processes like copy a set of files, zip/unzip archives, deploy/undeploy stauff, etc. What I mean is that, while they might be practical ways to quickly perform repetitive actions, like checking-out dozens of projects from an SCM (Source Code Manager) repository, their utilisation for important things, like infrastructure management, should really be forbidden.

     

    I’m currently working in a DevOps team of a big french gouvernment administration, where the infrastructure is quite impressive, consisting in more than 600 platforms, each one having several dozens of WebLogic domains.  And as surprizing as it might seem, all the infra-structure services consisting in installing binaries, configuring domains, application servers, databases, clusters, web servers, deploying applications, etc., is done in shell scripts having thousands of lines. These scripts look like a massive spaghetti pile, having often several thousands of lines, without any structure or clear defined interface and where evrything is done via sed and awk. And of course, to cap it all, nobody in the team has the mastership of what exactly happens in those scripts.

     

    Different consultants, including myself, have tried to sensibilize the management to the huge technological debt they will have probably to pay for a very longtime, thanks to the choices they made and, while they become aware of this situation, they still don’t seem to be at 100% convinced. They don’t understand what’s the point as far as everything seems to almost work.  Different approaches are in-progress trying to introduce different open-source DevOps virtualisation and install engines solutions, like Vagrant, Ansible, etc. But the effort is far from being trivial as this requires to dig in thousands of lines of spagetti like scripts, to extract functionality and to think how it could be re-designed and re-implemented with tools like ansible or equivalent.

     

    However, as far as I’m concerned, I’m still not confortable with this approach as replacing a scripting language, like the Unix Shell (Bourne Shell, C Shell, K Shell, BASH or whatever) by an automation engine, like ansible, doesn’t fondamentally change anything. While a more modern solution then using poorly designed and untested in-house scripts, while supported and professionally documented, an automation engine like ansible is not yet the tool to be used in order to implement SOA infrastructure services. As highlited by the SOA advocates, the infrastructure services are an important part of the enterprise services set and as such, they have to satisfy the following requirements :

     

    • Modularity and granularity. In an SOA based infrastructure, services are modular and self-contained. They may be composed from other modular services, and can be mixed and matched as needed to create new composite services. Granularity is a critical quality for services—the more coarse-grained a service is, the richer or larger the function offered by the service. Coarse-grained services provide a greater level of functionality within a single service operation. This helps to reduce complexity and network overhead by reducing the steps necessary to fulfill a given infrastructure activity. Often this is accomplished by composing smaller tasks into a single coarse-grained operation. Fine-grained service operations provide the exchange of small amounts of information to complete a specific discrete task. These requirements of modularity and granularity cannot be achieved in scripting languages as they are too primitive and too closed to operating system and their commands and utilities to provide so high level concepts.
    • Encapsulation. Services exhibit a strict separation of the service interface (what a service does) from the service implementation (how it is done). Encapsulation hides the service’s internal implementation details and data structures from the published interface operations and semantic model. Encapsulation is impossible to be achieved in scripting languages because they don’t have the notion of interface and because implementation is all what the scripts are about. Consequently, scripts don’t expose any semantic element.
    • Loose coupling. Coupling describes the number of dependencies between a service consumer and provider. Loosely coupled services have few, well-known and managed dependencies. Tightly coupled services have many known and, more importantly, unknown dependencies. The degree of coupling directly affects the flexibility and extensibility of a system. From this point of view, it’s obvious that scripts can only be tightly coupled and, hence, unflexible and unextendible.
    • Isolation of responsibilities. Services are responsible for discrete tasks or the management of specific resources. A key characteristic of service design is the isolation of responsibility for specific functions or information into a single service. This provides one (and only one) place for each function to be performed, providing consistency and reducing redundancy. But when you look at how scripts are written, even when they are written by experienced people, having a real and solid culture and expertize in the services world, you notice how far you are from notions like isolation of responsibilities.
    • Autonomy. Autonomy is the characteristic that allows services to be deployed, modified, and maintained independently from each other and the solutions that use them. An autonomous service’s life cycle is independent of other services. As opposed to this concept, a script is something which heavily depends on the context it was written for and which doesn’t provide any designed to change feature or ability.
    • Reuse. Together, modularity, encapsulation, loose coupling, isolation of responsibilities, and autonomy enable services to be combined into multiple processes or accessed by multiple service consumers from multiple locations and in multiple contexts. In other words, services are shared and reused as building blocks in the construction of processes or composite services. This is absolutelly not the case of the scripting technology which doesn’t provide any of these advantages.
    • Dynamic discovery and binding. Services can be discovered at design time through the use of a design-time service repositories. Additionally, service consumers can be dynamically bound to providers during run time. In this scenario, the consumer asks the registry for a specific service and is routed and bound dynamically to the appropriate service provider. The dynamic binding of a service consumer to the service provider  enhances loose coupling and enables additional capabilities such as mediation. Once again, using scripting languages, we are very far from this scenario.
    • Stateless. Service operations are stateless. This means that they neither remember the last thing they were asked to do nor care they what the next is. Services are not dependent on the context or state of other services — only on their functionality. Stateless services provide better flexibility, scalability, and reliability. Again, when you look at scripts where nothing is stateless, which depend on lots of things, including but not limited to the current folder in the file-systems, it becomes clear that they aren’t share the same play-ground.
    • Self-describing. The service contract provides a complete description of the service interface, its operations, the input and output parameters, and schema. The contract may also contain pre and postconditions and constraints about the operations. In the case of scripts, there is no any contract, any interface or any schema. The well behaved scripts use to provide a –help switch explaining the required parametters and their meaning, but this is their maximum. They are not only not auto-describing but even not discribing at all.
    • Composable. Services can be composed from other services and, in turn, can be combined with other services to compose new services or processes. Whoever ever tried to compose scripts or to chain them knows how difficult this exercice is. Besides sourcing scripts defining environment variables definitions in the context of other scripts, any other attempt of superior composition or aggregation is quite impossible, given their un-flexibility, their statefullness, their un-modularity and their un-autonomy.
    • Governed by policy. Relationships between service consumers and providers (and between services and service domains) are governed by policies and service level agreements (SLAs). Policies describe how different consumers are allowed to interact with the service. In other words, what they are allowed to do. Scripts are at ages from such a processing model hence they are not mature enough to be used in SLA based environments and those having to guarantee a given quality of service (QOS).
    • Independent of location, language, and protocol. Services are designed to be location-transparent and protocol/platform-independent. In other words, they are accessible to any authorized user, on any platform, from any location (within reason). As opposed to them, scripts require the user to know by hard the 120 characters long path on the file systems they are stored, together with SSH connection credentials and other horrors that make them simply unsable.

     

    My conclusion is that, unless you need to automate simple processes consisting in running a sequence of OS commands, or even more complex processes like saving and restoring data bases or file-systems, in your daily infrastructure tasks you need to define discrete functionality units and to make them available through a contract, while making sure they are modular and in the right granularity, loose coupled, autonom, reusable, stateless, self-describing, etc. Meaning that you need to forget scripting languages. Yes, this is true even for scripting languages like Python, Jython, etc. And what other technology is the most appropriated for that ? Well, I know this is hard to be accepted by system administrators, infrastructure architects, DBAs and other production and operations engineers but, as unbeleivable as it might be, the technology you’re looking for is Java.

  • Intra-composite Routing Development – Oracle SOA Suite vs JBoss Fuse Service Works

    This is a 2nd article comparing some of the Oracle SOA Suite 12c features with JBoss Fuse Service Works. The 1st article was focusing on the BPEL development while this 2nd part is demonstrating how to use both tools in developing intra-composites routing. So, this article compares the Oracle Mediator included in the Oracle SOA Suite 12c release with Switchyard 2.0 included in JBoss FSW 6.0.0.GA. For the purposes of the presented samples, I’m using :

    Both packages require registration in order to be downloaded.

    The project

    In order to compare the two product stack I’m using a simple use case :

    • a JAX-WS web service accepting an XSD based grammar is exposed to process purchase orders ;
    • a mediator transforms the associated SOAP payload in an appropriated format as required for the persistence service ;
    • a persitence service persist the purchase orders into the persistence store.

    The following diagram illustrates this process.

    Mediator.PNG

    Using SOA Suite and JDeveloper

    To provide a solution to the use case above with SOA Suite and JDeveloper is quite straightforward. I need to create a new application and a new SOA project in JDeveloper. This results in the creation of a new SCA composite. Here, using the JDeveloper Component Palette, I create an SCA service in the « Exposed Services » pane of the SCA Editor. In order to do this I choose the component named « SOAP » in the Components pane and I drag it on the canvas, in the « Exposed Services » pane. The service wizard opens and let me choose the following properties :

    • The name of the service
    • The SCA type service or reference (here a service)
    • The WSDL URL. Here I can use an existent WSDL located either on the local file system, or deployed on a WebLogic application server, or in the code repository (MDS – MetaData Store), or in an UDDI/WSIL repository. If I don’t have an existent WSDL, which will be our use case here, the tool will generate it automatically, based on the input and output flows, described by an XSD grammar. In this case, I will use the XSD file named po.xsd, located in my project’s Schema directory. I can also choose the generated service type as being one way, synchronous and asynchronous. I choose one-way. I need to configure the location, on the local file system, where the generated WSDL will be saved, its port type and the transaction propagation option which, in this case, will be NEVER.

    The service wizard will generate the required JAX-WS web service and its associated WSDL. Now it’s time to create the mediator.

    From the Components pane of the SCA Editor I select the Mediator component and I drag it on the Components pane of the SCA Editor. This will be all I need to do, at this stage, as far as the mediator is concerned.

    Now I attack the last element of my design, the database adapter. From the Components pane I select the Database Adapter component and I drag it on the References pane of the SCA Editor. The Database Adapter wizard which opens let me configure the following properties :

    • The JDBC connection to be used to access my database. I’ll use the Oracle XE 11g database which comes with the appliance. Here, besides the JDBC connection name which has a meaning only in JDeveloper, I need to provide a JNDI name that I will use later in order to configure the associated datasource in the application server.
    • The operation type to be performed to the database which could be : calling a stored procedure or performing one of the following SQL requests :
      • insert or update
      • delete
      • select
      • query by example
    • The set of tables to be used by the operations configured above. In this example I’m using a single table, named ORDERS, that I created previously.
    • When several database tables are to be used then their relationship may be also selected and configured. This doesn’t happen in this case as there is only one database table.
    • The columns of the database table which are to be used in the operations described above. Given that in my case I’m just inserting data into the database, I check all the defined columns but the primary key which will be initialized based on a native Oracle sequence number. Accordingly, the next step of the wizard is to allow me to create this sequence number, or to select it if it already exists, and to associate it with the database table’s primary key.
    • The last thing to do is to configure some obscure JCA endpoint properties and the best choice, at least at this stage, is to accept the default values.

    All the required components are in place now, as the figure below shows and we need to wire them now. This is done very easy by dragging arrows between components, first between the inboud web service and the mediator, next between the mediator and the outbound database adaptor.

    Mediator.PNG

     

    Our mediator needs to perform transformations such that to adapt and mediate the content of the SOAP payload to the WSDL based database adapter input. Double-clicking the mediator, the Mediator Editor opens and let us define the required transformation, as follows :

    • In the Transformation section of the Mediator Editor, there is an icon serving to handle an XSL mapping file describing the transformation required between the left and the right side of the mediator. We may use an existent mapping file, if we have one, or create a new one. In this case we’ll create a new one as we don’t have any.
    • The XSLT Map Editor opens and allows us to define the required transformation. On the left side of the editor we have the inbound data, the PurchaseOrder structure as described by the input XSD file, while on the right side of the editor we have the outbound data, a collection of Orders types, as defined by the WSDl automatically created as an interface of the Database adaptor service. To map the inbound elements to the outbound one sis very simple, just click an element on the left side and drag it on the corresponding element on the right side. The image below shows the resulting mapping.

    XSLT Mapping Editor.PNG 

    That’s all folks. Now, I just need to deploy my project on the application server by right-clicking it and selecting the « Deploy » option. The deployment should work without error and, once terminated, I can use the Oracle Enterprise Manager console to test it.

    Using JBoss FSW and JBoss Developer Studio

    To do the same exercise with JBoss FSW and JBoss Developer Studio, one needs to create first a switchyard project. Here, in the switchyard project configuration wizard, we can choose the implementation support, the gateway bindings and the test frameworks to be used with our switchyard composite. For our use case we will choose a bean implementation, the JPA and SOAP gateway bindings and the http test mixin.

    Our new SCA composite gets created and we can start our design. The first thing to do is to expose our JAX-WS service, as we did previously. In the Palette pane, I select the Service element in the Core category and I drag it on the canvas. An SCA service is automayically created and positioned on the left side of the canvas. Here I need to choose an interface type between the following :

    • A Java interface
    • A WSDL
    • An ESB interface requiring to configure an input, an output and a fault type

    This is the first surprize because, as oposed to the SOA Suite, here we need a WSDL for our service and we cannot create it on the fly. A WSDL is not a business artifact but a technical one. While it is mandatory for exposing JAX-WS web services, we cannot expect that business analysts, who are the final target of these kind of tools, use and understand it. Instead, business analysts are concerned by the enterprise data, expressed by XSD grammars and the tool should be able to generate the required WSDL based on this XSD grammar. It’s already difficult to train business analyst such that they succeed to express their enterprise data in the form of XSD grammars, if additionally we need to get them authoring WSDL contracts, then we need to transform them into real developers. So we got stucked here even before having started.

    Okay, let’s suppose we have a WSDL for the service we will expose, which is a very unlike case. I’m not talking here about an external service, having a clear defined contract, but about an ad-hoc internal service, which contract shall be made on the fly, based on the service input, output and fault specifications. In my case, in order to ba able to continue my implementation, I just used the WSDL created previously by SOA Suite, which I ammenended such that to adapt it to my needs here. I stored it in the project and now I can use it, by choosing WSDL as the type of the interface and browsing the project to select the required file. I need to give a name to the service, like OrderWebService and that’s it, my service is created.

    Now I need to add a binding to my service and, in this case, the binding is a SOAP one. So, in the Palette I select the SOAP binding and I drag it onto my service. Here, in the SOAP Binding Details window, the only mandatory field is the WSDL Url which is automatically initialized with the location of the WSDL used as the service interface during the service creation step. I also need to give an arbitrary name to this binding, a context path and a service port. In my case the context path is « orders » and the server port is 18001. This means that my service could be tested, using the http mixin, using the URL localhost :180001/orders.

    The next step is to create an SCA component associated to my service. This is done by clicking the Component element in the Palette pane, the Core category, and draging it on the canvas. The new created component is automatically placed in the middle on the canvas. I gave it the name OrderComponent. Now, I need to provide an implementation to this component and this implementation will be a CDI bean. Hence, in the Implementation category of the Palette I click the Bean element and I drag it onto my OrderComponent component. The Bean Implementation details dialog opens and here I have to create a Java class which is the implementation of the OrderComponent component. If this class already exists, I can browse for it but, in my case it doesn’t, so by clicking on Bean Class link, I can create it. So, I click the link and the New Bean Service Class dialog opens. Here, the interface type is automatically configured as being Java and, the first thing I need to do, is to configure the service interface. Again, if I have an already existent interface then I can browse for it but, in my case, I haven’t, so I will creatre it by clicking the Interface link. The Java Interface dialog opens and here I create an interface named OrderService. Back to the New Bean Service Class dialog, the name of my implementation is automatically proposed OrserServiceBean, which I will accept. The Component OrderComponent, together with its associated Java interface and implementation, respectivelly OrderService and OrderServiceBean, are created.

    To resume, I have now an SCA service, named OrderWebService, bound to a SOAP service, having OrderProcessing.wsdl as a contract. The body of this service is the SCA component named OrderComponent, which implements the interface named OrderService. The OrderComponent is implemented as a CDI bean named OrderServiceBean. This is the class to which my SCA service, Order WebService, delegates all the operations it is responsible of. So, this class is the class which will receive a purchase order and will get it persistent, hence I have to provide the required code here.

    The good news is that, as opposed to my previous implementation using SOA Suite, where I was using a Database Adapter, here I will use JPA (Java Persistence API). Oracle SOA Suite doesn’t have a JPA adapter and the standard way to implement persistence is using the Database Adapter, which is not JPA compliant. But this is not the case of FSW so let’s take advantage of the full JPA support.

    The way that FSW provides JPA support is very straightforward. The only thing one needs to do is to have an interface and to use the with it FSW out-of-the-box JPA binding facility. In our case, what we want to achieve is to be able to persist instances of our purchase orders. So, we need to provide a JPA entity to model the purchase order and to use it as the value of the <jpa :entityClassName /> element, belonging to the JPA binding. To do that, I select the Reference widget in the Core tab of the Palette and I drag it on the right side of the canvas. The New Reference wizzard is displayed. Here, I need first to define the interface to the service I’m referencing. I have the choice between a Java, a WSDL or an ESB interface. I will chose the Java interface  and I can either select an existent or create a new one. I don’t have any existing interface hence I’ll create a new one  by clicking the link labeled Interace. The code below shows the interface I have created.

    package fr.simplex_software.soa.order_service;

     

    public interface OrderRepository

    {

      public void persistOrder (PurchaseOrderEntity purchaseOrder);

    }

     

    It has only one mthod, called persistOrder which, as its name implies, will persist the purchase order entity passed as an argument.  The listing below shows the PurchaseOrderEntity.

    package fr.simplex_software.soa.order_service;

    import java.math.*;
    import javax.persistence.*;
    import fr.simplex_software.soa.order_service.jaxb.*;

    @Entity
    @Table(name="ORDERS")

    public class PurchaseOrderEntity
    {
      private Long id;
      private String custID;
      private String orderId;
      private String productName;
      private String itemType;
      private BigDecimal price;
      private BigDecimal quantity;
      private String status;
      private String ccType;
      private String ccNumber;

      public PurchaseOrderEntity()
      {}

      public PurchaseOrderEntity (PurchaseOrder po)
      {
        this.ccNumber = po.getCcNumber();
        this.ccType = po.getCcType();
        this.custID = po.getCustID();
        this.itemType = po.getItemType();
        this.orderId = po.getOrderId();
        this.price = po.getPrice();
        this.productName = po.getProductName();
        this.quantity = po.getQuantity();
        this.status = po.getStatus();
      }

      @Id
      @GeneratedValue(strategy=GenerationType.IDENTITY)
      @Column(name="ORDER_REF_ID", unique=true, nullable=false)
      public Long getId()
      {
        return id;
      }

      @Column(name="CUSTOMER_ID")
      public String getCustID()
      {
        return custID;
      }

      public void setId(Long id)
      {
        this.id = id;
      }

      public void setCustID(String value)
      {
        this.custID = value;
      }

      @Column(name="ORDER_ID")
      public String getOrderId()
      {
        return orderId;
      }

      public void setOrderId(String value)
      {
        this.orderId = value;
      }

      @Column(name="PRODUCT_NAME")
      public String getProductName()
      {
        return productName;
      }

      public void setProductName(String value)
      {
        this.productName = value;
      }

      @Column(name="ITEM_TYPE")
      public String getItemType()
      {
        return itemType;
      }

      public void setItemType(String value)
      {
        this.itemType = value;
      }

      @Column(name="PRODUCT_PRICE")
      public BigDecimal getPrice()
      {
        return price;
      }

      public void setPrice(BigDecimal value)
      {
        this.price = value;
      }

      @Column(name="PRODUCT_QUANTITY")
      public BigDecimal getQuantity()
      {
        return quantity;
      }

      public void setQuantity(BigDecimal value)
      {
        this.quantity = value;
      }

      @Column(name="CREDIT_CARD_STATUS")
      public String getStatus()
      {    return status;

      }

      public void setStatus(String value)
      {
        this.status = value;
      }

      @Column(name="CREDIT_CARD_TYPE")
      public String getCcType()
      {
        return ccType;
      }

      public void setCcType(String value)
      {
        this.ccType = value;
      }

      @Column(name="CREDIT_CARD_NUMBER")
      public String getCcNumber()
      {
        return ccNumber;
      }

      public void setCcNumber(String value)
      {
        this.ccNumber = value;
      }
    }

    The code above shows a simple JPA entity defining a few columns and an auto-increment ID field. We’re using a MySQL database as JPA data-store. Now, our SCA component, named OrderComponent, will reference a service via an SCA reference, named OrderRepositoryReference, which binds to the FSW out-of-the-box JPA implementation the OrderRepository interface. The image below shows our SCA composite.

    switchyard.jpg

    The relevant XML content of this SCA composite is shown below :

    <?xml version="1.0" encoding="UTF-8"?>

    <sy:switchyard xmlns:bean="urn:switchyard-component-bean:config:1.1" xmlns:jpa="urn:switchyard-component-camel-jpa:config:1.1" xmlns:sca="http://docs.oasis-open.org/ns/opencsa/sca/200912" xmlns:soap="urn:switchyard-component-soap:config:1.1" xmlns:sy="urn:switchyard-config:switchyard:1.1" xmlns="urn:switchyard-config:switchyard:1.1" xmlns:transform="urn:switchyard-config:transform:1.1" name="order-service" targetNamespace="urn:fr.simplex_software.soa:order-service:1.0">

      <sca:composite name="order-service" targetNamespace="urn:fr.simplex_software.soa:order-service:1.0">

        <sca:service name="OrderWebService" promote="OrderComponent/OrderService">

          <sca:interface.wsdl interface="wsdl/OrderProcessing.wsdl#wsdl.porttype(OrderProcessing)"/>

          <soap:binding.soap name="OrderWebServiceBinding">

            <soap:contextMapper soapHeadersType="VALUE"/>

            <soap:wsdl>wsdl/OrderProcessing.wsdl</soap:wsdl>

            <soap:socketAddr>:18001</soap:socketAddr>

            <soap:contextPath>orders</soap:contextPath>

          </soap:binding.soap>

        </sca:service>

        <sca:reference name="OrderRepositoryReference" multiplicity="0..1" promote="OrderComponent/OrderRepositoryReference">

          <sca:interface.java interface="fr.simplex_software.soa.order_service.OrderRepository"/>

          <jpa:binding.jpa name="order-jpa-binding">

            <jpa:entityClassName>fr.simplex_software.soa.order_service.PurchaseOrderEntity</jpa:entityClassName>

            <jpa:persistenceUnit>order-pu</jpa:persistenceUnit>

            <jpa:transactionManager>#jtaTransactionManager</jpa:transactionManager>

            <jpa:produce>

              <jpa:usePersist>true</jpa:usePersist>

            </jpa:produce>

          </jpa:binding.jpa>

        </sca:reference>

        <sca:component name="OrderComponent">

          <bean:implementation.bean class="fr.simplex_software.soa.order_service.OrderServiceBean"/>

          <sca:service name="OrderService">

            <sca:interface.java interface="fr.simplex_software.soa.order_service.OrderService"/>

          </sca:service>

          <sca:reference name="OrderRepositoryReference">

            <sca:interface.java interface="fr.simplex_software.soa.order_service.OrderRepository"/>

          </sca:reference>

        </sca:component>

      </sca:composite>

      <sy:transforms>

        <transform:transform.jaxb from="java:fr.simplex_software.soa.order_service.jaxb.PurchaseOrderResponse" to="{http://simplex_software.fr/soa/order}PurchaseOrderResponse" contextPath="fr.simplex_software.soa.order_service.jaxb"/>

        <transform:transform.jaxb from="{http://simplex_software.fr/soa/order}PurchaseOrder" to="java:fr.simplex_software.soa.order_service.jaxb.PurchaseOrder" contextPath="fr.simplex_software.soa.order_service.jaxb"/>

      </sy:transforms>

    </sy:switchyard>

    We’re almost done ! The only missing part are the transformations. Looking at our OrderProcessing.wsdl, which is our service’s contract, we can see that it accepts an input of the type PurchaseOrder, defined as a complex element in the po.xsd. This complex element, passed to our service as an XML document, needs to be transformed into a PurchaseOrderEntity class instance, such that to be persisted. So we need a transformer able to transform a PurchaseOrder complex element into a Java class, in occurrence a JPA entity. These conversions between XSD elements and Java classes are known under the name of unmarshalling/marshalling process and the part of the Java specifications dealing with them is named JAX-B (Java Architecture for XML Binding).

    Accordingly, we need to build the Java classes equivalent to our XSD complex elements defined in the schema imported by our service’s contract such that to be able to unmarshall into them the content of the XML payload and to marshall them into XML payloads. We didi it as a separate maven project using the jaxb2-maven-plugin to compile the our schema grammar po.xsd into Java classes. The result of this compilation, done by XJC, the JAX-B compiler, is represented by the classes PurchaseOrder and PurchaseOrderResponse, which are the input and output types of our service.

    So, by the XJC compilation process, we generated Java classes that may be marshalled into XSD complex elements of type PurchaseOrder and PurchaseOrderResponse and which could store the data resulted from their unmarshalling process. The only thing that we have to do now is to provide the mecanich associated to this marshalling/unmarshalling process and this is simply done by the following sequence of our switchyard.xml file :

      <sy:transforms>

        <transform:transform.jaxb from="java:fr.simplex_software.soa.order_service.jaxb.PurchaseOrderResponse" to="{http://simplex_software.fr/soa/order}PurchaseOrderResponse" contextPath="fr.simplex_software.soa.order_service.jaxb"/>

        <transform:transform.jaxb from="{http://simplex_software.fr/soa/order}PurchaseOrder" to="java:fr.simplex_software.soa.order_service.jaxb.PurchaseOrder" contextPath="fr.simplex_software.soa.order_service.jaxb"/>

      </sy:transforms>

     

    What this sequence is saying is that we are using theout-of-the-box switchyard  JAX-B transformers to transform :

    • from the XSD complex element {http://simplex_software.fr/soa/order}PurchaseOrder to the JAX-B generated class simplex_software.soa.order_service.jaxb.PurchaseOrder
    • and from the JAXB-generated class simplex_software.soa.order_service.jaxb.PurchaseOrderResponse into the XSD complex element {http://simplex_software.fr/soa/order}PurchaseOrderResponse

    Now, back to the implementation of our service, the OrderServiceBean CDI class, the only thing we have to do is to add our business logic consisting in :

    • Injecting the Switchyard JPA Binding OrderRepository implementation
    • Using the JPA service to store the input PurchaseOrder into the database
    • Insatiate an PurchaseOrderResponse and return it to the caller

    All this as shown by the code below :

    @Service(OrderService.class)

    public class OrderServiceBean implements OrderService

    {

      private static Logger logger = Logger.getLogger(OrderServiceBean.class);

      @Inject

      @Reference("OrderRepositoryReference")

      private OrderRepository store;

     

      @Override

      public PurchaseOrderResponse processOrder(PurchaseOrder order)

      {

        logger.info("*** processOrder: " + order.getOrderId());

        store.persistOrder(new PurchaseOrderEntity(order));

        PurchaseOrderResponse resp = new ObjectFactory().createPurchaseOrderResponse();

        resp.setAccepted(true);

        resp.setOrderId("1234");

        resp.setStatus("Accepted");

        return resp;

      }

    }

    Last but not least, our SCA composite may be unit tested using the Switchyard unit test frameworks based on the notion of MixIn, as explained by the Switchyard documentation. Here is a simple test :

    @RunWith(SwitchYardRunner.class)

    @SwitchYardTestCaseConfig(config = SwitchYardTestCaseConfig.SWITCHYARD_XML, mixins = {CDIMixIn.class, HTTPMixIn.class, TransactionMixIn.class})

    public class OrderWebServiceTest

    {

      private HTTPMixIn httpMixIn;

      private static Logger logger = Logger.getLogger(OrderWebServiceTest.class);

     

      @Test

      public void testProcessOrder() throws Exception

      {

        logger.info("*** Entered in testProcessOrder");

        httpMixIn.setContentType("application/soap+xml");

        httpMixIn.postResourceAndTestXML("http://localhost:18001/orders/OrderProcessingService", "/xml/soap-request.xml", "/xml/soap-response.xml");

      }

    }

    Of course, for more realistic tests in a integration context we use as usual SoapUI, on the behalf of which we generated the soap-request.xml and soap-response.xml files used above.

    Conclusions

    In this exercice we tried to implement the same business case using two SOA stacks, The Oracle one and the RedHat one. It’s difficult to make a real comparation of these two SOA stacks based on such simple business case, however my conclusions are as follows :

    • Oracle SOA Suite is a more mature product, providing all the required tools and wizzards. While it is easier to be used by a non-developer population, like business analysts, thanks to its quite impressive powership and its coverage of a big diversity of cases that typically appear in the design process, it is less opened to Java standards and specifications. Many functionalities, such as persistence, are achieved on the behalf of sprcific adapters. Its support of XML based transformations, like XSLT, XQuery, XPath, is very complete, however its support for JAX-B is limited to the one provided by JDeveloper.
    • JBoss Fuse Service Works is a more recent product which doesn’t beneficiate yet of all the tools and wizzards. However, its support of the Java standards and specifications is more consistent. Its integration with maven is absolutelly natural, and it directly supports JPA, JAX-B, CDI, EJB, Camel, and other Java or open standards. While its utilisation by business analysts might become a nightmare, it is really designed on the purpose to be a software developer tool. It dramatically lacks tools like XQuery/XSLT/XPath wizzard and editors.

    To resume everything in one sentence, Oracle SOA Suite is more an XML set of tools dedicated to the business analysts, even if JDeveloper and WebLogic represent a very powerfull development pkatform, while JBoss Fuse Service Works is more adapted to developers who may use graphical design, component and palettes in order to build a basic layout or schelet but systematically need to go the hard way of the manually code writing, adapting and completing. In this respect, JBoss Fuse Service Works require a much more important learning curve with no obvious gains in productivity once this curved is absorbed. Oracle SOA Suite aims at being used by more or less any business analysts with few or none Java development skills.

  • Packaging JBoss EAP 6.4.0 with Docker

    Docker, Docker, Docker! During the last few years, I hear this name more and more in books and articles and in all the conferences and tech meetups that I attend. The arrival of Docker has been welcomed by the community with open arms and it has instantly become a hit. The Docker ecosystem has been rapidly expanding with many other companies providing services, support, and complimenting frameworks such as Apache Mesos and Amazon Elastic Beanstalk, just to name a few. Even Microsoft has embraced the technology and is working on providing Docker support in their Azure Cloud service. It goes to show !

    In this short post, I would like show how to pack a JBoss EAP 6.4.0 platform using Docker images/containers.

    JBoss EAP 6.4.0 is a Java EE 6 compliant application server, probably one of the most known on the application servers market, together with IBM WebSphere and Oracle WebLogic. It is an open-source application server maintained and distributed by RedHat and its community counterpart is Wildfly. While Docker has been used since a while to package Wildfly distributions, packaging JBoss EAP with Docker is something more recent, hence this blog ticket.

    A quite natural packaging of a JBoss EAP platform consists in two Docker images, one hosting the application server itself and the second the associated database, as shown below :

    docker1.jpg

     

     

     

     

     

     

     

     

     

     

    As the figure above is showing, the platform is packaged using n+1 containers, where n is the number of the JBoss EAP application servers, and the additional container is hosting the MySQL server instance. JBoss EAP requires a database for its internals. For licencing reasons, it comes with the H2 database, which is a Java in-memory database, usefull for rapid prototyping, but which has to be replaced with a production-ready databse server, as soon as we start to do more serious stuff. Here, we have chosen MySQL or, more precisely, MariaDB.

    All the containers are bridged, having a loopback network interface and a private network interface connected to the host through the network bridge. This way, any container can connect to any other but none can connect to the host and the host cannot connect to any container.

    Here are the step to be performed in order to build this architecture :

    1. Get the JBoss EAP 6.4.0 Docker image from DockerHub.

      docker pull docker.io/dboss/docker-jboss-eap

    2. Get the MariaDB image from DockerHub

      docker pull docker.io/mysql

    3. Make sure that the images above have been pulled out and are present on the local host

      docker images

    4. Run a MySQL Server container based on the docker.io/mysql image

      docker run -d --name mysqld --expose 3306 –e MYSQL_ROOT_PASSWORD=password docker.io/mysql:latest

    5. Make sure that the MariaDB container is running

      docker ps

    6. Attach an interactive terminal session to the MariaDB container. This operation is supposed to be done via the docker attach but, for some reason, the release I’m using (1.10.3 on CentOS 7) gets stuck while running this command. In order to work-around I’m using the following :

      docker exec –it mysqld /bin/bash

    7. In the current bash session, connect to the MariaDB server via the mysql client and create a new database named test.

      mysql –u root –p password
      mysql>show databases;

      mysql>create database jbossdb;
      mysql>quit

    8. You just created a new MySQL database. Now you may exit the bash session and commit a new Docker image containing this new databse you just added.

      docker commit –m «Have added a new test database»
         -a «Nicolas DUMINIL <nicolas.duminil@simplex-software.fr»
         mysqld docker.io/mysql:testdb

    9. Using the command docker images you can check whether the new image, identified by io:mysql:testdb, has been created

    10. Now that the database server is running and that the databse jbossdb has been created, it’s time to start a second container to configure and run JBoss EAP.

      docker --name jboss-eap-6.4.0 –p 8080:8080
         –p 9990:9990 /opt/jbossas/bin/standalone.sh
         –b 0.0.0.0 –bmanagement=0.0.0.0

    11. Using the command docker ps you can check whether the container named jboss-eap-6.4.0 is running. Now, you need to create a new management user.

      /opt/jbossas/bin/add-user.sh

      The script add-user.sh will guide you to create the new user. Once done, you will be abale to connect to the JBoss EAP Admionisration Console, at localhost :8080, using the new created user.

    12. Modify the application server configuration such that to add the required modules for the MySQL Server. The following directory structure and files need to be added to the /opt/jbossas/modules

      /opt/jbossas
      |
      |-- modules
        |
        |-- com
          |
          |-- mysql
            |
            |-- main
              |
              |-- module.xml
              |-- mysql-connector-java-5.1.20.jar

      And the module.xml file is as follows :

      <?xml version="1.0" encoding="UTF-8" standalone="no"?>
      <module xmlns="urn:jboss:module:1.0" name="com.mysql">
        <resources>
          <resource-root path="mysql-connector-java-5.1.20-bin.jar"/>
        </resources>
        <dependencies>
          <module name="javax.api"/>
          <module name="javax.transaction.api"/>
        </dependencies>
      </module>

    13. Modify the configuration files such that to remove the H2 database driver and datasources and to add the MySQL database drivers and datasources. The JBoss EAP platform may be executed in either domain or standalone mode. Additionally, there are five different profiles : standalone, standalone-full, standalone-ha, standalone-full-ha and standalone-osgi. Depending on the mode and on the profile you’ll be using to run the patform, you need to modify the associated configuration XML file. For example, for running JBoss EAP in standalone mode, the file to be modified id /opt/jbossas/standalone/configuration/standalone.xml. This could be done by either directly modifying this XML file using your prefered text editor, or by using JBoss CLI (CommandLine Interpreter). For example, the following CLI file will do the thing.

      #Script to replace the H2 datasource by MySQL ones
      connect
      batch

      # Default profile
      # Remove the datasources and the H2 driver
      data-source remove --name=ExampleDS
      /subsystem=datasources/jdbc-driver=h2:remove

      # Add MySQL JDBC driver
      /subsystem=datasources/jdbc-driver=MySQL:add(
          driver-name=MySQL,
          driver-module-name=com.mysql,
          driver-xa-datasource-class-name=com.mysql.jdbc.jdbc2.optional.MysqlXADataSource
      )
       
      # Add a non-XA datasource
      data-source add
          --name=ExampleDS
          --driver-name=MySQL
          --jndi-name=java:jboss/datasources/ExampleDS
          --connection-url=jdbc:mysql://localhost:3306/test
          --user-name=root
          --password=California1
          --max-pool-size=25
      data-source  enable --name=ExampleDS

      # Add an XA datasource
      xa-data-source add
          --name=ExampleXADS
          --driver-name=MySQL
          --jndi-name=java:jboss/datasources/ExampleXADS
          --user-name=root
          --password=California1
          --recovery-username=root
          --recovery-password=California1
          --use-ccm=false
          --max-pool-size=25
          --blocking-timeout-wait-millis=5000
          --new-connection-sql="set datestyle = ISO, European;"
      /subsystem=datasources/xa-data-source=ExampleXADS/xa-datasource-properties=ServerName:add(value=localhost)
      /subsystem=datasources/xa-data-source=ExampleXADS/xa-datasource-properties=PortNumber:add(value=3306)
      /subsystem=datasources/xa-data-source=ExampleXADS/xa-datasource-properties=DatabaseName:add(value=test)
      xa-data-source enable --name=ExampleXADS
       
      # Execute and reload
      run-batch
      :reload

    14. Commit all the modifications you just done

      docker commit –m «Have configured MySQL drivers and datasources»
        -a «Nicolas DUMINIL <nicolas.duminil@simplex-software.fr»
        jboss-eap-6.4.0 docker.io/dboss/docker-jboss-eap:mysql

    15. Now, stop the jboss-eap-6.4.0 container and restart it linked to the mysqld container.

      docker stop jboss-eap-6.4.0
      docker --name jboss-eap-6.4.0 –p 8080:8080
      --link mysqldb
        –p 9990:9990 /opt/jbossas/bin/standalone.sh
        –b 0.0.0.0 –bmanagement=0.0.0.0

    Congratulations, you have now a full JBoss EAP 6.4.0 platform running on your host. For any additional application server you want to run, you need to create a new container from the same image docker.io/dboss/docker-jboss-eap :mysql. And if you want to share this new images, you can also push them back to DockerHub