Friday, August 31, 2012

Using Custom Log Files with Log4j - BPEL

In day to day development, every application requires logging of data/errors in the log files.
In BPEL code development, we may use the following lines in a Java Embedding activity to log texts and errors in the Server log files (i.e servername-diagnostic.log)

com.collaxa.ServerLogger.error("SOA_5007", "Severity :3", "SFO-SOA_5007 generic process failed");   
java.lang.String ErrorMsg = (String)getVariableData("ErrorMessage");       
com.collaxa.ServerLogger.error(ErrorMsg);]

But a server log contains a clutter of information apart from our application specific logged messages. It would be a good thing to do if we can have a custom log file for our application specific logging.

Log4j is a wonderful logging API, which we are going to use in our implementation. We are going to have 2 step configuration  - 
 - Environment Specific Configurations
 - Application Specific Configurations

Environment Specific Configurations
1. There are two ways of adding a custom jar for use in your application  - 
a. Copy log4j-1.2.16.jar to //soa/modules/oracle.soa.ext_11.1.1 and execute ANT script in this directory. This will recreate the oracle.soa.ext.jar file adding the log4j lib to the classpath.

Prerequisites:  

Option 1
a) cd  to directory of oracle.soa.ext_11.1.1 
b) >  C:\\\modules\org.apache.ant_1.7.1\bin\ant (in windows)
bash$  ./u01//modules/org.apache.ant_1.7.1/bin/ant (in Unix)

Option 2

In WINDOWS

In environmental variables, set 
ANT_HOME  = F:\oracle\Middleware\modules\org.apache.ant_1.7.1
Path = %ANT_HOME%\bin

Then from cmd go the directory and type ant and hit enter.

In UNIX

For C shell (csh), edit the startup file (~/.cshrc): 
set path=(/usr/local/jdk1.6.0/bin )

For bash, edit the startup file (~/.bashrc): 
PATH=/usr/local/jdk1.6.0/bin:
export PATH

For ksh, the startup file is named by the environment variable, ENV. To set the path: 
PATH=/usr/local/jdk1.6.0/bin:
export PATH

For sh, edit the profile file (~/.profile): 
PATH=/usr/local/jdk1.6.0/bin:
export PATH

Then load the startup file and verify that the path is set

b. Place the jar in /user_projects/domains/domainName/lib

2. Create a new folder for Log4j configuration and log files like /Log4jConfigFiles

3. Add to this folder the configuration files (log4jConfig.xml and log4j.dtd, for example)

4. Set the log file name and path (/Log4jConfigFiles/customErrorLog.log, for example) in the log4jConfig.xml

5. Change the setDomainEnv script(.cmd for windows or .sh for Unix) found in /user_projects/domains//bin to point to Log4j configuration file:

In Unix
JAVA_OPTIONS="-Dlog4j.configuration=file /Log4jConfigFiles/log4jConfig.xml" 

In Windows
set JAVA_OPTIONS=-Dlog4j.configuration=file:"/Log4jConfigFiles/log4jConfig.xml"

6. Restart the SOA managed server. 

Application Specific Configurations

1. Import  log4j-1.2.16.jar to the project libs (right click in the project name and select “Project Properties”, go to “Libraries and Classpath” and add the jar file)

2. Insert a Java Embedding activity

3. In the BPEL source code, import the Logger class adding the code below before the “bpelx:exec” created for the Java Embedding component


4. Edit the Java Embedding activity and insert the necessary log instructions like to test the functionality:

Logger mLogger = Logger.getLogger("myCustomLog");  
mLogger.info(" >>>>>>>>> This is my first log4j statement ****************");  
mLogger.debug(">>>>>>>>>>>>>>>Logger Debug Stmt");  
mLogger.error(">>>>>>>>>>>>>>>Logger Errorrr"); 
java.lang.String ErrorTrace = ((org.w3c.dom.Element)getVariableData("inputVariable","payload","/client:process/client:input")).getFirstChild().getNodeValue(); 
mLogger.info("erroorrr trace ::::"+ErrorTrace); 
mLogger.info(ErrorTrace);

All the files mentioned in this post can be downloaded from here .

You can also find a working SOA project inside the downloaded zip named "TestCustomLog.zip" implementing the above described functionality.


________________
thanks, D


Wednesday, February 29, 2012

Using Query By Example feature of DB Adapter - using SQL 'and' clause dynamically

QueryByExample option of the DB Adapter forms (infers) a SELECT statement at runtime, dynamically from the XML input that you provide while invoking the adapter service. So, it is not necessary to write a design time SELECT query.

Usecase
Say we have a query

SELECT * FROM departments WHERE location_id=1700 AND department_id=30

now, we require that if deparment id is supplied in the input only then the portion "AND department_id=30" will be used in the query.

To explain this, the default HR schema of the Oracle database and the DEPARTMENTS table in that schema can be used.

So, our input schema goes this way -



Here, we supply dept_id and loc_id as the input to fetch records using the DB Adapter service.

Configure the database adapter to use QueryByExample and select the table Departments

Our BPEL flow looks like  -



Assign the bpel inputs to the Departments collection elements of the adapter



Populate the output.
Now, test the composite first with input loc_id as 1700. You can see the output returns multiple records.
Now, test again with loc_id as 1700 and dept_id as 30. You can see the recods are filtered and the query returns a single record.

The working Jdev project can be found here .
[Note: You need to configure the datasource, connection pool and have a JNDI name jndi/hrS in the adapter configuration, to make this code functional w/o change]









Thursday, January 26, 2012

Storing and retrieving shared resources like xsd, wsdl, dvm etc in SOA MDS

Its a common idea to share reusable artifacts across composites in Oracle SOA Suite 11g. SOA MDS provides us with the option and has its own advantages.

1. For deploying any shared resource in SOA MDS, we need to create a generic project in Oracle JDeveloper and create necessary folders under it and store the dvm file.
In our example, DTEMS is the project created and the hierarchy of folders is
TestingDvm -> dvm ->idName.dvm (this folder structure will not be visible in JDeveloper, but only in the project workspace).

2. Now, in JDeveloper right click the project (here DTEMS), go to Project Properties -> Deployment.
Click New, select Archive Type as JAR File, name the jar and click OK.
Now in JAR Options, uncheck “Include Manifest File




From Project Output -> Contributors deselect all.
Go to Filters and check the folder under which the dvm files are located (TestingDvm here) and click OK
Now, the archive is created named “DvmArchive


3. Now, we need to create a SOA Bundle for packaging the created JAR and deploy it in server.
For that, go to Application Properties of the application under which the project is created and then go to Deployments.

Select Archive Type as SOA Bundle, name the bundle and click OK
In the next screen, go to Dependencies, check the archive (containing the jar) created before (DvmArchive) and click OK
Now, the SOA Bundle named “dvmSOABundle” is created.

4. Now we need to Deploy this SOA bundle to the server.


5. Now, to see the deployed shared resources , we need to create a SOA-MDS connection (DB based connection)


6. Now you can see the resources in the desired folder structure under the /apps directory as below


7. And we are done; the resource can be accessed in the project as ---
              "oramds:/apps/TestingDvm/dvm/idName.dvm"


Sunday, January 08, 2012

Export/Import OSB Projects using WLST with Apache Ant - OSB 11g

In this post, we are going to export and import (deploy) OSB projects. Oracle has provided some standardized Python (infact Jython - the java version of Python) scripts which will be processed by  WebLogic Scripting Tool (WLST). So, lets go straight into "how-to" of doing things.

We are going wrap the WLST scripts from ANT tasks using weblogic server provided <wlst> tag for Ant. And our WLST is going to process the import (import.py) and export (export.py) scripts.

1. Set JAVA_HOME
JAVA_HOME= <location of java home>
export JAVA_HOME
echo $JAVA_HOME

2. Set CLASSPATH. CLASSPATH variable should contain weblogic.jar, alsb.jar and com.bea.common.configfwk_1.3.0.0.jar .
FMW_HOME=/u01/app/oracle/product/fmw
CLASSPATH=$FMW_HOME/wlserver_10.3/server/lib/weblogic.jar:$FMW_HOME/Oracle_OSB1/lib/alsb.jar:$FMW_HOME/Oracle_OSB1/modules/com.bea.common.configfwk_1.3.0.0.jar
export CLASSPATH
echo $CLASSPATH

[Note: mutiple paths are seperated by colon(:) in Unix]

3. Now, place the 4 files (build.xml, build.properties, export.py and import.py) in a specific location in the server, say /tmp/OSBScripts.

Few considerations for build.properties
     a. fmw.home=/u01/app/oracle/product/fmw
                           here, mention the path of FMW home

     b. wls.username= weblogic
         wls.password=abc123
                         here, specify the username and password used to connect to server

     c. wls.server  = t3://lpdwa1109.trcw.us.aexp.com:7002
                         here,
                               - t3 protocol is used
                               - port should be the admin server port

     d. export.project=DummyTest
                        here, mention the name of the project that needs to be exported.

     e. export.jar=/tmp/debadri/sbconfig_DummyTest.jar
                        here, specific the jar file name and the location where the project will be exported.

     f. export.customFile=/tmp/debadri/bamdatecheck.xml
                       here, mention the location and name of customization file, if any

     g. import.jar= /tmp/debadri/sbconfig_DummyTest.jar
                       here, mention the name and location of the JAR file which needs to be imported.

     h. import.customFile = None
                      here, name and location of customization file to be applied to the imported jar if any.

Few considerations for build.xml
      a.  <property name="domain.export.script" value=" /tmp/OSBScripts/export.py"/>
      b.  <property name="domain.import.script" value=" /tmp/OSBScripts/import.py" />
                        Always better to specify the full path of export.py and import.py.
      c. We are going to specify the script to execute in the "fileName" property of <wlst>

Here's the oracle doc link to get an insight into using other attributes of <wlst> in running WLST from Ant for WLS 10.3.5

4. Run ant targets from the location where build.xml is placed.

>/tmp/OSBScripts $ <FMW_HOME>/modules/org.apache.ant_1.7.1/bin/ant exportFromOSB
OR
>/tmp/OSBScripts $  <FMW_HOME>/modules/org.apache.ant_1.7.1/bin/ant importToOSB


Here, exportFromOSB - Ant target that exports OSB project from server
          importToOSB -   Ant target that deploys OSB project from local system to the server


[Note: The wlst task is predefined in the version of Ant shipped with WebLogic Server. If you want to use the task with your own Ant installation, add the following task definition in your build file: 
<taskdef name="wlst" classname="weblogic.ant.taskdefs.management.WLSTTask"/>]

All the files (build files and Jython scripts) referred in this link can be found here

______________
thanks, D


Sunday, January 01, 2012

Working with SOAP Attachment using Java Callout in OSB 11g


Our use case is to receive an attachment (zip/pdf/doc) which comes as a part of SOAP request and place it in a particular directory.

First, we are going to have a java class which writes the attachment content into a file. As our main purpose is to show how to handle attachment, we are keeping the java code simple. 

WRITING A POJO

1. We will write a java class (BinaryCtxWriter.java), which has a static method accepting a string and a byte array as input params. The method’s purpose is to write the contents of the attached file into a particular directory.

2. Export the class as a JAR (BinaryCtxWriter.jar).

OSB STANDPOINT

1. Create an OSB project and copy BinaryCtxWriter.jar in here.

2. First we need to create a WSDL(PSInterface.wsdl) for the proxy service which will accept an attachment. 
Here, it should be noticed that the request message has 2 parts. One for the message body and the other for attachment.  To handle multiple parts in a message structure, we will be using RPC style SOAP binding. The operation input has a MIME binding.

3. Create a proxy service based on this WSDL. The OSB message flow looks like this



4. For every attachment, OSB keeps the attachment in memory and gives us a reference handler to that location. The context variable "attachments" get populated once any attachment is received. Under "attachments", each "attachment" element contains an individual attachment.
This reference can be accessed as 

                           $attachments/ctx:attachment/ctx:body/ctx:binary-content

In the assign action, we assign the expression $attachments/ctx:attachment/ctx:body/ctx:binary-content 
to a variable. (say “attachmentData”) .


5. Now, we make a Java Callout to the static method that we exposed in the BinaryCtxWriter.jar. 
Assign, the expression $body/soap:submitAttachment/submitAttachment/fileName/text() to the java string argument.
Assign the variable $attachmentData to the byte[] argument.

6. In the response pipeline, we are having the proxy to reply with ‘OK’.
   This is done by replacing the body variable with

<ns0:submitAttachmentResponse xmlns:ns0="http://www.debadri.com/SOAPAttachment/"> 
<submitAttachmentResponse> 
<response>OK</response> 
</submitAttachmentResponse>
</ns0:submitAttachmentResponse>

7. Next, we explicitly delete the "attachments" variable. This is done so as to prevent the client of the proxy service from receiving the attachment again as a part of SOAP message.
In the delete action, in the Variable section mention "attachments"


8. Deploy the OSB application (sbconfig_HandlingSOAPAttachment.jar)

Note: To test this we can use soapUI, Java client or any other WS client. Strangely, testing with OSB test console somehow doesn't function.



All the source code files referred in this post can be downloaded from here


________________
thanks, D


Sunday, December 18, 2011

Exploring Oracle SOA INFRA table - querying Oracle SOA dehydration store

Suppose, we have a scenario to find the number of instances for a particular composite for a particular date range.One way of doing it would be via /em console, but that can be toiling work as we don't get the count displayed for instances searched between a date range.

So, whats the alternative!
Yes, we have something called SOA dehydration store where all composite instances are persisted. And we are going to query the particular table to get the count of instances.

1. Connect to SOA INFRA dehydration store. Setup the database connection.

Host Name: database host name
SID or Service Name: as required.
Port: JDBC port
Username: usually its "DEV_SOAINFRA"
Password: here goes the password for the user

2. Usually, if you connect though any IDE (say Oracle Jdeveloper), its gives you the database structure in the form of a tree. There in, the table "CUBE_INSTANCE" in the SOA INFRA schema contains all the details of instances per composite. A quick description of the table shows this  -


desc CUBE_INSTANCE;
Name                           Null                     Type                                                                                                                                                                                        
---------------------     -------            ---------------
CIKEY                         NOT NULL  NUMBER          
CREATION_DATE     NOT NULL  TIMESTAMP(6)                                                                                                                                                                                
CREATOR                                         VARCHAR2(100)                                                                                                                                                                              
MODIFY_DATE                                TIMESTAMP(6)                                                                                                                                                                                
MODIFIER                                        VARCHAR2(100)                                                                                                                                                                              
STATE                                               NUMBER                                                                                                                                              
PRIORITY                                         NUMBER                                                                                                                                                                                      
TITLE                                                NVARCHAR2(100)                                                                                                                                                                              
STATUS                                            NVARCHAR2(100)                                                                                                                                                                              
STAGE                                              VARCHAR2(100)                                                                                                                                                                              
CONVERSATION_ID                      VARCHAR2(256)                                                                                                                                                                              
ROOT_ID                                          VARCHAR2(100)                                                                                                                                                                              
PARENT_ID                                      VARCHAR2(100)                                                                                                                                                                              
SCOPE_REVISION                          NUMBER                                                                                                                                                                                      
SCOPE_CSIZE                                 NUMBER                                                                                                                                                                                      
SCOPE_USIZE                                 NUMBER                                                                                                                                                                                      
PROCESS_TYPE                              NUMBER                                                                                                                                                                                      
METADATA                                     NVARCHAR2(1000)                                                                                                                                                                            
EXT_STRING1                                 VARCHAR2(100)                                                                                                                                                                              
EXT_STRING2                                VARCHAR2(100)                                                                                                                                                                              
EXT_INT1                                        NUMBER                                                                                                                                                                                      
TEST_RUN_ID                                VARCHAR2(100)                                                                                                                                                                              
TEST_RUN_NAME                         VARCHAR2(100)                                                                                                                                                                              
TEST_CASE                                     VARCHAR2(100)                                                                                                                                                                              
TEST_SUITE                                    VARCHAR2(100)                                                                                                                                                                              
ECID                                                 VARCHAR2(100)                                                                                                                                                                              
CMPST_ID                                       VARCHAR2(100)                                                                                                                                                                              
OUTCOME                                       VARCHAR2(100)                                                                                                                                                                              
TRACKING_LEVEL                        VARCHAR2(16)                                                                                                                                                                                
AT_COUNT_ID                                NUMBER                                                                                                                                                                                      
AT_EVENT_ID                                 NUMBER                                                                                                                                                                                      
AT_DETAIL_ID                                NUMBER                                                                                                                                                                                      
VERSION                                         NUMBER                                                                                                                                                                                      
AG_ROOT_ID                                  VARCHAR2(100)                                                                                                                                                                              
AG_MILESTONE_PATH                 VARCHAR2(100)                                                                                                                                                                              
CACHE_VERSION                          NUMBER                                                                                                                                                                                      
PARENT_REF_ID                            VARCHAR2(150)                                                                                                                                                                              
COMPONENTTYPE    NOT NULL VARCHAR2(10)                                                                                                                                                                                
NOTM                                               NUMBER                                                                                                                                                                                      
COMPOSITE_NAME  NOT NULL  VARCHAR2(500)                                                                                                                                                                              
DOMAIN_NAME                             VARCHAR2(50)                                                                                                                                                                                
COMPONENT_NAME  NOT NULL VARCHAR2(300)                                                                                                                                                                              
COMPOSITE_LABEL                         VARCHAR2(50)                                                                                                                                                                                
COMPOSITE_REVISION  NOT NULL VARCHAR2(50)                                                                                                                                                                                
CREATE_CLUSTER_NODE_ID              VARCHAR2(100)                                                                                                                                                                              
LAST_CLUSTER_NODE_ID                   VARCHAR2(100)



3. The below query gives you the count of CLOSED AND COMPLETED instances in a specified date range for a particular composite(say here "ConfigurationDataEBF"). You can also fetch other details or add other filter conditions with different table fields.

select count(*) from CUBE_INSTANCE where COMPOSITE_NAME = 'ConfigurationDataEBF' and STATE='5' and CREATION_DATE between '02-Oct-11' and '17-Nov-11' order by CREATION_DATE;


The STATE field descriptions are provided in the table below





_____________
thanks, D






RESTful Service Testing Using soapUI

soapUI is a wonderful tool for web services testing.
In this post, I am going to show how we can configure REST services in soapUI for testing.

We need to have soapUI version which supports REST (this test was performed wiith soapUI 3.6).

1. Suppose, we have a REST service endpoint  like https://osb-dbpm.intra.com/dbpm1/PSLoggingRestEBF (in this case, an OSB proxy service which accepts any XML message, with no WSDL interface )

2. First, we need to create a new soapUI project , with "Add REST Service" option checked.


3. Now, we need to put the host name without the context path of the service (Over here https://osb-dbpm.intra.com )


4. Give the Resource Path/Endpoint in the next screen (i.e /dbpm1/PSLoggingRestEBF ).

You can also paste the full URL here and on clicking Extract Params, it will keep the resource context path only from the full URL.


5.  Next, we need to add a method for accessing the new resource. Give a method name & select the HTTP Method (here POST)




6. Now, we can fire a request to the created method. Here, we need to validate few things as shown in the screen below:

  • Correct host Name
  • Correct full path of the resource 
  • Correct Media Type  (here text/xml is selected as we are sending an XML msg) 
** If your endpoint is that of a synchronous service, you will be able to see the response in the response panel of soapUI.





t