Wednesday Jan 08, 2014

Service Enablement of CORBA Applications through Oracle Service Bus

An quick overview in the definition of an ESB will tell us that one of its main responsibilities is among other things, the enablement of existing systems to provide new fresh services, using the same or maybe different protocols and/or contracts. This is when the ESB make magical things happen, virtualizing existing services and making them available for the outside world, abstracting from the applications that will consume the service details about the underlying system.

With this statement in mind, it is reasonable to think that an good ESB must be able to handle different types of systems and technologies found in legacy systems, no matter if this system was built last year, five years ago or even in the last decade. Those systems represents the assets of an organization in terms of their business building blocks, so there is a huge chance that those systems carries a substantial number of business services that could be leveraged by an SOA initiative.

CORBA is a distributed technology very powerful, that was pretty popular in the 90's and the beginning of 2000 year. Many industries that demands an robust infrastructure to handle their business transactions, critical by nature and extreme sensitive in terms of performance and reliability, relied on CORBA as technology implementation. It is pretty common to find communications companies like internet providers, mobile operators and pre-paid services chain that built its foundation (also known as engineering services) on top of CORBA systems.

This article will show how to enable CORBA systems through OSB, the ESB implementation from Oracle that is part of the SOA Suite. Through the steps showed here, you will be able to leverage existing CORBA systems and expose that business logic (defined as CORBA objects) in different transports, protocols and contracts, making the reuse of that business logic both possible and viable. This article will not cover any CORBA specific ORB to make the techniques available here reproducible in different contexts.

The Interface Definition Language

The definition of any CORBA object is written in an neutral description language called IDL, acronym of Interface Definition Language. For this example, I will consider that OSB will service enable an functionality that sends SMS messages, and this functionality is currently implemented as an object of an CORBA system. The IDL of this object is described below:

module corbaEnablementExample
{

    struct Message
    {

        string content;
        string phoneId;

    };

    interface SMSGateway
    {

        oneway void send(in Message message);

    };

};

As you can see, this is a very simple object that accepts an message as main parameter and the message has attributes that represents the content to be sent as an SMS message, and the mobile phone number that will receive the content.

The CORBA Server Application

It does not matter for the didactic of this article in which programming language the server part of the CORBA application will be implemented. What really matters is which ORB the CORBA server application will register its implementation stub. To illustrate the example, lets suppose that this CORBA object is implemented in Java.

package corbaEnablementApplication;

import org.omg.CORBA.ORB;
import org.omg.CORBA.Object;
import org.omg.CosNaming.NameComponent;
import org.omg.CosNaming.NamingContextExt;
import org.omg.CosNaming.NamingContextExtHelper;
import org.omg.PortableServer.POA;
import org.omg.PortableServer.POAHelper;

import corbaEnablementExample.SMSGateway;
import corbaEnablementExample.SMSGatewayHelper;

public class ServerApplication {

	public static void main(String[] args) {
		
		ORB orb = null;
		Object tmp = null;
		POA rootPOA = null;
		SMSGatewayImpl impl = null;
		Object ref, objRef = null;
		SMSGateway href = null;
		NamingContextExt ncRef = null;
		NameComponent path[] = null;
		
		try {
			
			System.setProperty("org.omg.CORBA.ORBInitialHost", "soa.suite.machine");
			System.setProperty("org.omg.CORBA.ORBInitialPort", "8001");
			orb = ORB.init(args, null);
			
			tmp = orb.resolve_initial_references("RootPOA");
			rootPOA = POAHelper.narrow(tmp);
			rootPOA.the_POAManager().activate();
			
			impl = new SMSGatewayImpl();
			ref = rootPOA.servant_to_reference(impl);
			href = SMSGatewayHelper.narrow(ref);
			
			objRef = orb.resolve_initial_references("NameService");
			ncRef = NamingContextExtHelper.narrow(objRef);
			
			path = ncRef.to_name("sms-gateway");
			ncRef.rebind(path, href);
			
			System.out.println("----------------------------------------------------");
			System.out.println("  CORBA Server is Running and waiting for Requests  ");
			System.out.println("----------------------------------------------------");
			
			orb.run();
			
		} catch (Exception ex) {
			ex.printStackTrace();
		}
		
	}

}

The code listing above shows an CORBA server application that connects onto a ORB available on one 8001 TCP/IP port. After retrieve the POA from the ORB, it get access to the naming service that will be used to register the object implementation. Finally, the application binds the object implementation under the name of "sms-gateway", the name which the CORBA object will be known from the outside world. In order to test this CORBA server application, start an ORB under the port 8001 and execute the program using one JVM. If you don't have any commercial ORB available, you can use the ORB which comes with the JDK. Just enter in the /bin folder of your JDK and type:

orbd -ORBInitialHost soa.suite.machine -ORBInitialPort 8001

To check if this remote object is working properly, you need to write an CORBA client application. Here is an example of an CORBA client written upon the same IDL interface which the server was written:

package corbaEnablementApplication;

import java.util.Random;
import java.util.UUID;

import org.omg.CORBA.ORB;
import org.omg.CORBA.Object;
import org.omg.CosNaming.NamingContextExt;
import org.omg.CosNaming.NamingContextExtHelper;

import corbaEnablementExample.Message;
import corbaEnablementExample.SMSGateway;
import corbaEnablementExample.SMSGatewayHelper;

public class ClientApplication {
	
	private static final Random random = new Random();

	public static void main(String[] args) {
		
		ORB orb = null;
		Object objRef = null;
		NamingContextExt ncRef = null;
		SMSGateway smsGateway = null;
		
		try {
			
			System.setProperty("org.omg.CORBA.ORBInitialHost", "soa.suite.machine");
			System.setProperty("org.omg.CORBA.ORBInitialPort", "8001");
			orb = ORB.init(args, null);
			
			objRef = orb.resolve_initial_references("NameService");
			ncRef = NamingContextExtHelper.narrow(objRef);
			
			smsGateway = SMSGatewayHelper.narrow(ncRef.resolve_str("sms-gateway"));
			Message message = createNewRandomMessage();
			smsGateway.send(message);
			
		} catch (Exception ex) {
			ex.printStackTrace();
		}
		
	}

	private static Message createNewRandomMessage() {
		String content = UUID.randomUUID().toString();
		String phoneId = String.valueOf(random.nextLong());
		Message message = new Message(content, phoneId);
		return message;
	}

}

The Business Services Layer

In order to OSB get access to the remote object, it is necessary to create an mechanism that can translate the IIOP protocol (the protocol used in pure CORBA systems) for one protocol that OSB can understand, which could be RMI/IIOP or pure RMI. To accomplish that, the best way is to implement the wrapper pattern. Write down one EJB 3.0 service that encapsulates the CORBA remote object, and delegates its service calls to this object. The interface for this EJB 3.0 service should be something simpler like this:

package com.oracle.fmw.soa.osb.corba;

public interface SMSGateway {
	
	public void sendMessage(String content, String phoneId);

}

The implementation of this EJB 3.0 service should perform a job similar to the CORBA client application described previously, but quite different in terms of how it connect to an ORB:

package com.oracle.fmw.soa.osb.corba;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.ejb.Remote;
import javax.ejb.Stateless;

import org.omg.CORBA.ORB;
import org.omg.CORBA.Object;
import org.omg.CosNaming.NamingContextExt;
import org.omg.CosNaming.NamingContextExtHelper;

import corbaEnablementExample.Message;
import corbaEnablementExample.SMSGatewayHelper;

@Remote(value = SMSGateway.class)
@Stateless(name = "SMSGateway", mappedName = "SMSGateway")
public class SMSGatewayImpl implements SMSGateway {
	
	private corbaEnablementExample.SMSGateway smsGateway;
	
	@Resource(name = "namingService")
	private String namingService;
	
	@Resource(name = "objectName")
	private String objectName;
	
	@PostConstruct
	@SuppressWarnings("unused")
	private void retrieveStub() {
		
		ORB orb = null;
		Object objRef = null;
		NamingContextExt ncRef = null;
		
		try {
			
			orb = ORB.init();
			objRef = orb.resolve_initial_references(namingService);
			ncRef = NamingContextExtHelper.narrow(objRef);
			smsGateway = SMSGatewayHelper.narrow(ncRef.resolve_str(objectName));
			
		} catch (Exception ex) {
			
			throw new RuntimeException("EJB wrapper failed in the retrieval of the CORBA stub.", ex);
			
		}
		
	}

	@Override
	public void sendMessage(String content, String phoneId) {
		
		smsGateway.send(new Message(content, phoneId));
			
	}

}

The code is very similar to the CORBA client application showed before, with one important difference: it has no information about which ORB to connect. In this case, the EJB will reside in on WebLogic JVM. Each WebLogic JVM has one ORB implementation out-of-the-box. So when you write EJB objects that will wrap-up CORBA remote objects, you don't need to worry about which ORB to use. WebLogic it is already an ORB.


Note: as explained before, this article will not enter in details of any commercial ORB available, in defense of the clarity and didactic of the article. But keep in mind that the steps shown here for the stub retrieval can be quite different if you are using another ORB. If you are using Borland VisiBroker for instance, there is a unique way to access the ORB which is using an service called "Smart Agent", which dynamically finds another objects in the network. IONA Orbix has another unique way to connect to an ORB, which is by the use of the domain configuration location of the Orbix network.


Create one WebLogic domain and execute one or more WebLogic managed servers, and re-run the CORBA server application again. Remember that now, the CORBA server application should point to the WebLogic port since the ORB now should be the one available in the WebLogic subsystem. If you check the JNDI tree of the WebLogic JVM, you should see something like this:

This means that the remote CORBA object was properly registered in the CosNaming service available in the WebLogic ORB. Package the EJB 3.0 implementation into a JAR or an EAR and deploy it in the same WebLogic JVM that the CORBA remote object was registered. Now we have everything in place to start the development of the OSB project. For the purposes of this article, I will assume that the EJB 3.0 object is available under the following JNDI name: "SMSGateway#com.oracle.fmw.soa.osb.corba.SMSGateway".

The OSB Project

In the OSB side, all you have to do is to create an business service that points to one or more endpoints of the EJB 3.0 that is running in the one or more servers of the WebLogic domain. In order to accomplish that, you will need to teach OSB about how to communicate with this foreign WebLogic domain. This is done creating an JNDI provider for the OSB configuration scheme:


OSB also needs to access the EJB 3.0 interfaces (and any other helper classes) to instantiate client proxies, so you need to package all the EJB 3.0 artifacts (except of course from the enterprise bean implementation) and deploy it onto your OSB project:

Now we have everything in place. It is time to create the business service that will point to the EJB 3.0 wrapper. Create one business service and set its service type to "Transport Typed":

Configure the business service protocol as "EJB" and set its endpoint URI to the prefix "ejb:" plus the name of the JNDI provider and plus the JNDI name of the EJB 3.0:

Finally, you need to configure the client interface of the EJB 3.0 endpoint in the business service configuration page. Check the "EJB 3.0" checkbox and choose from the drop-down list which interface will be used for message communication.

Finish the creation of the business service and save the changes. You can now test your business service using the testing tool available on OSB:

After making an request to the business service using the OSB testing tool, you can check the CORBA server application log to see the results of this invocation. Here is an example:

With the business service in place, you can easily create one or more proxy services to access the remote CORBA object with minimal effort. For the OSB perspective, it is all about routing messages to the business service that you created, making the fact that this business service is a CORBA remote object really irrelevant.

No matter what will be your use case, now you have the CORBA remote object available in OSB for virtually anything. You can expose it directly using one of the available transports, you can forward messages for it in the middle of your pipeline, you can use it as enrichment mechanism using service callouts or you can just use the business service as one of the choices of an dynamic routing. If you choose to expose this business service into a new protocol, you can play with SOAP, REST, HTTP, JMS, Email, Tuxedo, File and FTP with zero-coding. OSB will take care of the protocol translation during messages exchanges.

You can download the project artifacts created in this article here.

Tuesday Oct 11, 2011

Getting Started with Oracle Tuxedo: Creating a COBOL-based Application

This article will show how COBOL developers can create, with minimum effort, robust distributed and service-oriented applications using the facilities offered by Oracle Tuxedo. Through a step by step example, you will learn how to configure and setup an Oracle Tuxedo development environment, how to implement COBOL code that enable client and server interactions and how to deploy and test the application into Oracle Tuxedo. For this article, is expected that you have a basic knowledge of the Linux operating system and basic knowledge about programming, if you are not a COBOL developer of course.

What is exactly the Oracle Tuxedo?

Simply put, Oracle Tuxedo is an application server for non-Java developers. This means that developers of programming languages like C/C++, COBOL, Python and Ruby can implement distributed applications using enterprise features like messaging, clustering, security, load-balancing, scalability and thread management from an middleware implementation. The main difference is that the platform itself are not based on Java, and the programming language used to develop the applications are not restricted to Java.

Historically speaking, the concept of an application server had been used in distributed architectures to promote loosely coupling between client and server applications (reason because it's commonly named as middleware) and the reuse of common features that, in the old days, developers had to write every time they need to create a distributed application, features like messaging, clustering, security, load-balancing scalability and thread management, most of them, features that represent critical non-functional requirements. Instead of create every time those features, you can just delegate to a middleware that host those features and reuse across different applications, since they will offer the same behavior for every application. Another key thing about application servers is the fact that they introduce a programing model that forces developers to focus only in business logic instead of basic infrastructure.

With this programming model in mind, you can write distributed applications without worrying about that they are distributed, meaning that you don't have to worry about how client applications invokes services from server applications, how the message are serialized and unserialized between remote computers and how cross-cutting concerns (aspects) are applied at every interaction. Oracle Tuxedo has been very popular in the market as an application server, and it has more than 25 years of maturity and evolution.

In fact, the firsts line of code of Tuxedo was written in 1983 at the AT&T laboratories. Years later, Novell acquired the Unix System Laboratories, the AT&T division responsible for the Tuxedo development. In a exclusive formal agreement, BEA Systems started the development of Tuxedo in non-Netware platforms and became the principal maintainer and distributor of Tuxedo technology. Since the acquisition by Oracle in 2008, Tuxedo was renamed to Oracle Tuxedo and now are part of the Oracle Fusion Middleware stack, being massively optimized year after year.

COBOL? Why not C/C++ or Java?

You probably are wondering why this article will be focused in the COBOL programming language instead of more popular and equally powerful programming languages like C/C++ or Java. COBOL is a structured programming language largely used worldwide at many organizations, due to it's popularity in the 80's and the 90's and the highly mainframe adoption. In fact, most banking organizations today runs their critical transactions at mainframes and those transactions are written in COBOL. Even in the x86 architectures we found many applications written at this programming language, so it is a little bit fair with COBOL developers dedicate this article for them.

In the C/C++ world, the concept and usage of application servers are pretty common. In the Java world is almost a rule of development, so it's natural for Java developers (actually, Java EE developers) use application servers. Unfortunately, this scenario does not apply for COBOL developers. Having said that, Oracle Tuxedo was designed from the source to handle C/C++ implementations, and if you are a C/C++ developer, you will not find any difficulties to work with Oracle Tuxedo. It is unnecessary to say that, if you are a Java developer, there are a bunch of application server implementations available in the market today, like Oracle WebLogic and Oracle GlassFish. There is no need to use Oracle Tuxedo as application server.

Setting Up an Oracle Tuxedo Development Environment for COBOL

Let's start the development of a simple distributed application using Oracle Tuxedo and the COBOL programming language. For this article, I have used a Linux operating system (Fedora 14) as platform. If you intend to use another operating system, check if both Oracle Tuxedo and the COBOL compiler supports it. The first thing to configure is a proper COBOL compiler. Oracle Tuxedo does not distribute any compiler, neither for C/C++. You need to use a certified compiler in order to develop using Oracle Tuxedo. Fortunately, there are many COBOL compilers available today. Oracle certifies two compilers in particular: Micro Focus COBOL compiler and COBOL-IT compiler suite. The main difference between this two implementations are the fact that Micro Focus COBOL compiler are proprietary, and demands that you pay licenses to use it. COBOL-IT on the other hand are free and open source. The company basically gives you support and consultancy through subscriptions. For this article, we will use COBOL-IT in the development of the example.

You will need a C/C++ compiler too. During the compilation of COBOL source code files, Oracle Tuxedo translate COBOL code to native C/C++ code, and after that, it compiles it to the target platform as a native executable. This means that implicitly, a C/C++ program compilation occurs, even being you used COBOL as programming language. There no restrictions about which C/C++ compiler to use. If you are a Linux user, the ANSI GNU compiler will be available already in the platform. Depending of your Linux distribution, some other packages must be installed too.

Download the COBOL-IT compiler suite clicking here. The COBOL-IT compiler suite installation is pretty simple. Just download the zipped files and unzip into a folder of your preference. In my environment, I have unzipped in the /home/riferrei/cobol-it-std-64 folder. After unzip the files, you need to define two environment variables:

      COBOLITDIR=/home/riferrei/cobol-it-std-64

      PATH=$PATH:$COBOLITDIR/bin

After defining these two environment variables, you are ready to use your COBOL-IT compiler suite. Let's create a simple "Hello World" COBOL application to certify that the COBOL-IT compiler are really working. Create a file in your environment named hello.cbl, and in this file write the following COBOL code:

       IDENTIFICATION DIVISION.
       PROGRAM-ID. 'hello'.
       ENVIRONMENT DIVISION.
       INPUT-OUTPUT SECTION.
       FILE-CONTROL.
       DATA DIVISION.
       FILE SECTION.

       WORKING-STORAGE SECTION.

       01  HELLOMSG    PIC X(80).

       LINKAGE SECTION.

       PROCEDURE DIVISION.

       MAIN SECTION.
            MOVE "Hello World using COBOL" TO HELLOMSG
            DISPLAY HELLOMSG
            ACCEPT  HELLOMSG
            EXIT PROGRAM.

To compile this source code and to generate a native executable program, you need to use the COBOL-IT compiler, using the following command:

     cobc -x hello.cbl

As you can see, the COBOL-IT compiler used in the command cobc available in the /bin installation directory of COBOL-IT compiler suite. After type this command,  you should see a native executable program generated in the same directory of the file hello.cbl. Executing this program should generate, unsurprisingly, a console output with the following message: "Hello World using COBOL".

Now that your COBOL-IT compiler suite are up and running, it is time to move forward and start the configuration of Oracle Tuxedo. For this article, I have used the 11g R1 version of Oracle Tuxedo, which in the time of the development of this article was the latest version available. Oracle Tuxedo is freely available for learning and evaluation. You can download the installation software here. Install the software following the recommendations documented in the Oracle Tuxedo installation guide. I will not repeat those instructions here since you can easily follow from the official documentation.

The configuration of Oracle Tuxedo is very straightforward. In the essence, you have to define a series of environment variables that change the behavior about how Oracle Tuxedo will compile, execute and manage the COBOL applications. It is important no remember that the instructions available here applies exclusively for COBOL development with Oracle Tuxedo. If you want to use Oracle Tuxedo with C/C++ programming language, there are another instructions available. I summarized the list of environment variables that, for the development of this article, you need to define.

It is a good idea to put those environment variables in the system scope. If you are a Linux operating system user, could be e good idea define those environment variables in the .bash_profile configuration file of your home directory.

Creating a COBOL-based Application using Oracle Tuxedo

When you develop applications using Oracle Tuxedo, you actually create a distributed application. This means that you should create at least two applications: The client-tier, which will be the "presentation layer" for the end-user, and the server-tier, which provides one or more services interfaces to be consumed from the client-tier. If you look closely, It is basically the same architecture that Java EE provides. The programming model used in Oracle Tuxedo can be ATMI and CORBA. For this article, I will use ATMI since is the only programming model available for COBOL programming language. But for most advanced applications, specially those ones based on C/C++ programming language, I encourage you to use CORBA instead of ATMI. This approach frees your code from Oracle Tuxedo specific API's, turning your business logic actually portable between other CORBA implementations like Progress Orbix, Micro Focus Visibroker, etc.

We will create a simple example of distributed application where the server-tier expose a service that takes a string as parameter and converts to the upper case mode. The client-tier will actually take an string from the command-line and send it as parameter to the server-tier for processing. The first thing to do is to create a folder that will be our application directory. Create a folder named MY_TUX_APP. After this, you need to define two environment variables:

      APPDIR=/home/riferrei/MY_TUX_APP

      TUXCONFIG=$APPDIR/tuxconfig

These two environment variables are used in the deployment phase of the Oracle Tuxedo development, which means that they are applied to every application that are deployed. The other environment variables are defined only once and reused across different deployments. Enter in the $APPDIR directory. Let's start the development of the application by the server-tier layer. Create a file named serverApp.cbl and write the following COBOL code:

        IDENTIFICATION DIVISION.
        PROGRAM-ID. serverApp.
        AUTHOR. TUXEDO DEVELOPMENT.
        ENVIRONMENT DIVISION.
        CONFIGURATION SECTION.
        DATA DIVISION.
        WORKING-STORAGE SECTION.

        01  TPSVCRET-REC.
        COPY TPSVCRET.

        01  TPTYPE-REC.
        COPY TPTYPE.

        01 TPSTATUS-REC.
        COPY TPSTATUS.

        01  TPSVCDEF-REC.
        COPY TPSVCDEF.

        01  LOGMSG.
                05  FILLER        PIC X(10) VALUE  
                        "server :".
                05  LOGMSG-TEXT   PIC X(50).
        01  LOGMSG-LEN            PIC S9(9)  COMP-5.

        01 RECV-STRING            PIC X(100).
        01 SEND-STRING            PIC X(100).

        LINKAGE SECTION.

        PROCEDURE DIVISION.

       START-FUNDUPSR.
           MOVE LENGTH OF LOGMSG TO LOGMSG-LEN. 
           MOVE "Started" TO LOGMSG-TEXT.
           PERFORM DO-USERLOG. 

           MOVE LENGTH OF RECV-STRING TO LEN.
           CALL "TPSVCSTART" USING TPSVCDEF-REC 
                        TPTYPE-REC 
                        RECV-STRING
                        TPSTATUS-REC.      

           IF NOT TPOK
                MOVE "TPSVCSTART Failed" TO LOGMSG-TEXT
                    PERFORM DO-USERLOG 
                PERFORM EXIT-PROGRAM 
           END-IF.

           IF TPTRUNCATE 
                MOVE "Data was truncated" TO LOGMSG-TEXT
                    PERFORM DO-USERLOG 
                PERFORM EXIT-PROGRAM 
           END-IF.

           INSPECT RECV-STRING CONVERTING
           "abcdefghijklmnopqrstuvwxyz" TO
           "ABCDEFGHIJKLMNOPQRSTUVWXYZ".
           MOVE "Success" TO LOGMSG-TEXT.
           PERFORM DO-USERLOG.

           SET TPSUCCESS TO TRUE.
           COPY TPRETURN REPLACING 
                DATA-REC BY RECV-STRING.

       DO-USERLOG.
           CALL "USERLOG" USING LOGMSG 
                LOGMSG-LEN 
                TPSTATUS-REC.
       EXIT-PROGRAM.
           MOVE "Failed" TO LOGMSG-TEXT.
           PERFORM DO-USERLOG.
           SET TPFAIL TO TRUE.
           COPY TPRETURN REPLACING 
                DATA-REC BY RECV-STRING.

This COBOL application receives a string parameters and converts to the upper case mode. You can see in the code that every interaction or "phase" are sent to a logger mechanism called user-log. This a interesting approach supported by Oracle Tuxedo that enable developers to debug "what is happening" in runtime. Functions like TPSVCSTART and USERLOG are included in the source code dynamically, are are part of the Oracle Tuxedo ATMI API. To compile this application and generate a native executable program, type the following command:

      buildserver -C -o serverApp -f serverApp.cbl -s serverApp

An native executable program named serverApp will be generated in the current directory. Let's understand which each parameter of the buildserver command does. The "-C" parameter tells to Oracle Tuxedo that a COBOL compilation will be done. Without this parameter, Oracle Tuxedo assumes that a C/C++ compilation will occur. The "-o" parameter tells what will be the name of the native executable program. The "-f" parameter tells which source code must be compiled. Finally, the "-s" parameter tells what service will be published when this server get up and running.

Let's create the client-tier application. Being in the same folder ($APPDIR), create a file named clientApp.cbl, and inside this file, write the following COBOL code:

        IDENTIFICATION DIVISION.
        PROGRAM-ID. clientApp.
        AUTHOR. TUXEDO DEVELOPMENT.
        ENVIRONMENT DIVISION.
        CONFIGURATION SECTION.
        SPECIAL-NAMES.
            SYSERR IS STANDARD-ERROR.

        DATA DIVISION.
        WORKING-STORAGE SECTION.

        01  PARM-CNT PIC 9(05).

        01  TPTYPE-REC. 
        COPY TPTYPE.

        01  TPSTATUS-REC. 
        COPY TPSTATUS.

        01  TPSVCDEF-REC. 
        COPY TPSVCDEF.

        01  TPINFDEF-REC VALUE LOW-VALUES.
        COPY TPINFDEF.

        01  LOGMSG.
            05  FILLER		PIC X(8) VALUE  "client:".
            05  LOGMSG-TEXT	PIC X(50).
        01  LOGMSG-LEN		PIC S9(9)  COMP-5.

        01  USER-DATA-REC	PIC X(75).
        01  SEND-STRING		PIC X(100) VALUE SPACES.
        01  RECV-STRING		PIC X(100) VALUE SPACES.

        PROCEDURE DIVISION.
        START-CSIMPCL.
          MOVE LENGTH OF LOGMSG TO LOGMSG-LEN. 
          ACCEPT PARM-CNT FROM ARGUMENT-NUMBER.
          IF PARM-CNT IS NOT EQUAL TO 1 THEN
              DISPLAY "Usage: clientApp String"
              STOP RUN
          END-IF.

          ACCEPT SEND-STRING FROM ARGUMENT-VALUE.
          DISPLAY "SEND-STRING:" SEND-STRING.
      
          MOVE "Started" TO LOGMSG-TEXT.
          PERFORM DO-USERLOG.
      
          PERFORM DO-TPINIT. 
          PERFORM DO-TPCALL. 
          DISPLAY "RECV-STRING:" RECV-STRING.
          PERFORM DO-TPTERM. 
          PERFORM EXIT-PROGRAM. 
      
        DO-TPINIT.
          MOVE SPACES TO USRNAME.
          MOVE SPACES TO CLTNAME.
          MOVE SPACES TO PASSWD.
          MOVE SPACES TO GRPNAME.
          MOVE ZERO TO DATALEN.
          SET TPU-DIP TO TRUE.

          CALL "TPINITIALIZE" USING TPINFDEF-REC 
                USER-DATA-REC 
                TPSTATUS-REC.      
      
          IF NOT TPOK
                MOVE "TPINITIALIZE Failed" TO LOGMSG-TEXT
                PERFORM DO-USERLOG
                PERFORM EXIT-PROGRAM
          END-IF.
      
        DO-TPCALL.
          MOVE 100 TO LEN.
          MOVE "STRING" TO REC-TYPE.
      
          MOVE "serverApp" TO SERVICE-NAME.
          SET TPBLOCK TO TRUE.
          SET TPNOTRAN TO TRUE.
          SET TPNOTIME TO TRUE.
          SET TPSIGRSTRT TO TRUE.
          SET TPCHANGE TO TRUE.
       
          CALL "TPCALL" USING TPSVCDEF-REC 
                TPTYPE-REC 
                SEND-STRING
                TPTYPE-REC 
                RECV-STRING
                TPSTATUS-REC. 
      
          IF NOT TPOK
                MOVE "TPCALL Failed" TO LOGMSG-TEXT
                PERFORM DO-USERLOG 
          END-IF.
      
        DO-TPTERM.
          CALL "TPTERM" USING TPSTATUS-REC.      
          IF  NOT TPOK
                MOVE "TPTERM Failed" TO LOGMSG-TEXT
                PERFORM DO-USERLOG
          END-IF.
      
        DO-USERLOG.
          CALL "USERLOG" USING LOGMSG 
                LOGMSG-LEN 
                TPSTATUS-REC.
      
        EXIT-PROGRAM.
          MOVE "Ended" TO LOGMSG-TEXT.
          PERFORM DO-USERLOG.
          STOP RUN.

Let's compile this client-tier application. To do this, just type the following command:

      buildclient -C -o clientApp -f clientApp.cbl

As you can see, the parameters used in the compilation are the same that we used in the compilation of the server-tier, with the exception of the parameter "-s" in which of the client-tier are unnecessary. At this point, you should have two executable applications in the directory, one name clientApp and another named serverApp. To start the deployment phase of this application, it is necessary to create the configuration file for it. This configuration file are called UBBCONFIG file. The UBBCONFIG file acts as the external configuration descriptor that defines the application. If you are familiar with Java EE development, think in this configuration file as a deployment descriptor. In the directory of the application, create a file named ubbConfig and edit this file as showed in the listing below:

*RESOURCES
IPCKEY	123459

DOMAINID	ubbConfig
MASTER		simple
MAXACCESSERS	5
MAXSERVERS	5
MAXSERVICES	10
MODEL		SHM
LDBAL		N

*MACHINES
DEFAULT:

APPDIR="/home/riferrei/MY_TUX_APP"
TUXCONFIG="/home/riferrei/MY_TUX_APP/tuxconfig"
TUXDIR="/home/riferrei/oracle/tuxedo11gR1"

riferrei_linux_64	LMID=simple

*GROUPS
GROUP1
	LMID=simple	GRPNO=1	OPENINFO=NONE

*SERVERS
DEFAULT:
		CLOPT="-A"

serverApp	SRVGRP=GROUP1 SRVID=1

*SERVICES
serverApp

There are one section of this configuration file that you must change to get the example working, the "MACHINES-DEFAULT" section. Change the variables "APPDIR", "TUXCONFIG" and "TUXDIR" to reflect your file system format and directories location. You also need to change the hostname of the server. As you can see in the UBBCONFIG file, there is a mapping between the machine "riferrei_linux_64" to the element "LMID=simple". Change the hostname to reflect the hostname of your machine. I have found some problems when I used hostnames with special characters like "-" or ".". If some problems occurs in the UBBCONFIG loading, maybe this could be the cause.

Deploying and Testing the Application in Oracle Tuxedo

It is time to deploy and test the application. Every application in Oracle Tuxedo must have a binary version of their UBBCONFIG file. To generate this binary version, Oracle Tuxedo gives you a very simple utility program named tmloadcf. Being in the application directory of the application, type the following command:

     tmloadcf ubbConfig

A binary version of the UBBCONFIG file named tuxconfig will be generated in the current directory. Now we are all set. Let's start the deployment of the application and begin the tests. To deploy the application and start the server service, type the following command:

     tmboot -y

You should see in the console that a few messages will appear. Which these messages basically says is about the correct execution of the admin and server services, which means that they will be ready to accept client requests and ready to process the incoming messages. Type the following command:

     ./clientApp "Oracle Tuxedo"

With this command, we actually execute the client-tier application and we pass a string from the command line parameters. After type the command above, you should see in the console the following output:

     SEND-STRING:Oracle Tuxedo
     RECV-STRING:ORACLE TUXEDO

This means that our server-tier application received the message and passed to the serverApp service. The service on the other hand transformed the string passed as parameter to the upper case format and sent back to the caller application. In the "middle" of these two applications, Oracle Tuxedo did take care of the messaging and transaction execution. To shutdown the services and the server application, type the following command:

     tmshutdown

I have recorded a video that capture the entire application development since the compilation process. If you feel that some step was not done correctly, run the video below to follow step by step the sequence of commands needed to compile, deploy and test the application created at this article.


Conclusion

This article gave you an overview about Oracle Tuxedo e how it can be used to create distributed applications using the COBOL programming language. It showed how to set up a development environment that enable COBOL developers to build a simple but complete application in Oracle Tuxedo. I hope that this article could help you and your team to explore the features that only Oracle Tuxedo offers.

About

Ricardo Ferreira is just a regular person that lives in Brazil and is passionate for technology, movies and his whole family. Currently is working at Oracle Corporation.

Search

Categories
Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today