JNDI usage in ADF Application Module for Data base connectivity

October 18, 2012 3 comments
The application module created in ADF Application connects to a given data base using two options. JDBC URL and JDBC Data source.

Open the AM in jdeveloper -> Configuration tab. Edit the existing AM Configuration.


JDBC URL -> In this type of connection, the end point information is directly hard coded on the source code [DB details like host:port:sid and DB credentials like username/password] and is generally picked up from connections.xml. This isn’t ideal – reason being, every change in DB connection requires application redeployment which isn’t a good idea. Or if I want to deploy same code [EAR] to multiple environments like Dev, QA 1, QA 2 each having its own DB, every time I need to change the DB details on my code and generate EAR and deploy.

JDBC Data Source -> This works based on JNDI names. JNDI names are unique names that we use in our code and is configured in WLS. At runtime, java code looks for a mapping registration of that name on the deployed server and once it finds it, it uses the corresponding end points registered there. For eg, in weblogic, register a data source called AdfAppDB with JNDI name as “jdbc/AdfAppDBDS”. Make the application Module configuration use this JNDI name – hence no data base connection credentials/end point info is hardcoded in the source code. Every environment will have its own DB configured which will be looked up at runtime dynamically by ADF using JNDI mapping and respective DB end point would be resolved.

Now the way ADF uses the JDBC data source would be interesting. If I provide the exact JNDI name as the data source JNDI
“jdbc/AdfAppDBDS” as given in above example, things will not work since ADF has its own JNDI parsing mechanism for data source lookups. I will try to explain the behavior in which ADF would parse the JNDI connection for AM DB configuration and resolve it to right value at runtime.

Defining the data source in weblogic:
To defining a data source in weblogic, navigate to Weblogic console -> Services -> Data source. Create a new data source with name “
AdfAppDB” and JNDI name as “jdbc/demo/AdfAppDBDS”. Make sure you test the connection and target it to the right server.

Testing AM with JDBC URL:
In the application, create a DB Connection named “
AdfAppDB”.


Navigate to AM configuration -> edit the default configuration and make it use JDBC URL connection type with “AdfAppDB”.

Run the AM and you will see that all works fine.

I have a sample TestPage.jsf which I run and I can see that employee data comes all fine.

Either open the connections.xml or edit the connection for
AdfAppDB, make it use an invalid DB and you will see that the page doesn’t load with DB connection errors. This confirms that when you have a JDBC URL connection type set on application module, the connection is picked up from connections.xml of deployed application.

Testing the page with JDBC Datasource:
Now on the AM, let’s use the data source that we created on the “Defining the data source in weblogic” step so that AM would do a JNDI lookup at runtime to weblogic to identify appropriate connection. To do this, first
Navigate to AM configuration -> edit the default configuration and make it use JDBC data source connection type with “AdfAppDB” connection JNDI details selected as shown below.

Now when you run the AM, the data comes up all fine and is good. Run the TestPage.jsf – you will see that the page errors with below exception.
Caused by: javax.naming.LinkException:  [Root exception is javax.naming.NameNotFoundException: Unable to resolve ‘jdbc.AdfAppDBDS’. Resolved ‘jdbc’; remaining name ‘AdfAppDBDS’]; Link Remaining Name: ‘jdbc/AdfAppDBDS’
at weblogic.jndi.internal.WLNamingManager.getObjectInstance(WLNamingManager.java:104)
at weblogic.jndi.internal.BasicNamingNode.resolveObject(BasicNamingNode.java:884)
at weblogic.jndi.internal.ApplicationNamingNode.resolveObject(ApplicationNamingNode.java:187)
at weblogic.jndi.internal.BasicNamingNode.resolveObject(BasicNamingNode.java:856)
at weblogic.jndi.internal.BasicNamingNode.lookup(BasicNamingNode.java:209)

Root cause: The JNDI name defined on weblogic is “jdbc/demo/AdfAppDBDS” where as what we have selected on the code is “java:comp/env/jdbc/AdfAppDBDS”. Of this, “java:comp/env/” part will be dynamically attached at runtime by WLS and hence that can be ignored. “demo” is missing in the JNDI name “jdbc/demo/AdfAppDBDS”. So let’s update the JNDI name alone manually on AM configuration to use “java:comp/env/jdbc/demo/AdfAppDBDS”. Now nothing is wrong here – let’s run the page and try.


Still the same error – but this time with a different JNDI name.
Caused by: javax.naming.NameNotFoundException: While trying to look up comp/env/jdbc/demo/AdfAppDBDS in /app/webapp/JndiDemoApplication-ViewController-context-root/26713680.; remaining name ‘comp/env/jdbc/demo/AdfAppDBDS’
at weblogic.jndi.internal.BasicNamingNode.newNameNotFoundException(BasicNamingNode.java:1139)
at weblogic.jndi.internal.ApplicationNamingNode.lookup(ApplicationNamingNode.java:144)
at weblogic.jndi.internal.WLEventContextImpl.lookup(WLEventContextImpl.java:254)
at weblogic.jndi.internal.WLContextImpl.lookup(WLContextImpl.java:411)

To understand why this comes up again, let’s split the JNDI name used on the AM Configuration – java:comp/env/jdbc/demo/AdfAppDBDS.
java:comp/env – is added by WLS automatically at runtime
jdbc/ADF Expects ALL JNDI names used by it to start with jdbc/. Hence its a MUST that when you are using a Data source connection for your AM, that data source JNDI name must start with jdbc/.
demo/AdfAppDB
– Even though ADF will do the JNDI mapping to the JNDI name on WLS, it still tries to find this name defined on connections.xml. Even if it is a invalid DB, that’s fine. But this connection name should be exactly present on connections.xml. This is the reason why it is failing second time above. We have connection name as AdfAppDB but not as demo/AdfAppDB.
DS – ADF Expects ALL JNDI names used by it to end with the string DS. Hence its a MUST that when you are using a Data source connection for your AM, that data source JNDI name must end with DS.

Now in our case, the WLS Data source has JNDI name “jdbc/demo/AdfAppDBDS” which is fine. ADF expects the data source name to end with DS which is met here.

We know that AM is fine. Based on above summary, what is missing is that connection name definition on connections.xml. Hence let’s define a new connection named “demo/AdfAppDB” and rerun the page and it works like charm now.


Thanks,
Kavin.

Run JAX-WS Proxy for message_protection enabled web service with simple JSE Client

October 5, 2012 Leave a comment

One of the most widely used pattern to invoke an ADF BC Web service or a SOA Composite Service from java is JAX-WS Proxy. The case that I am discussing here is invoking a Web service secured with a message_protection policy using a JAX-WS JSE client by using the client policy –  oracle/wss11_saml_or_username_token_with_message_protection_service_policy.

Now to invoke the service secured with above OWSM policy from J2EE client, we can generate a JAX-WS proxy as given on documentation pointed above and use connection.xml as an option to inject end point dynamically by creating an ADF Web Service Connection.

 Context ctx = ADFContext.getCurrent().getConnectionsContext();
 WebServiceConnection wsc = (WebServiceConnection) ctx.lookup("MyAppModuleService");
 MyAppModuleService proxy = wsc.getJaxWSPort(MyAppModuleService.class);
 

This approach of using connections.xml to manage end point would work only when your JAX-WS proxy code is going to executed in a J2EE Application context where the app knows about connections.xml. But if you execute the same API with a simple JSE client, it would fail since a simple java program has no idea of connections.xml. There are two cases that comes to my mind immediately where I want to execute my JAX-WS proxy code in a simple JSE client.

1) During development of my web proxy, I don’t want to run my UI everytime to test the web proxy. Instead I want a simple approach to test my web proxy code.
2) I am exposing a service from my product secured with oracle/wss11_saml_or_username_token_with_message_protection_service_policy which wouldn’t allow me to test with default end point tester. Hence if I want to write some automated test mechanism for my service, then a simple JSE client comes very handy to test message_protection enabled services.

Now this can be done in two ways. But in each, the complication lies in how we will be applying the client policy and other request parameters for encryption and signature requirement for message_protection_client policy.


Prerequisite: This requires some security related files to be pre-configured to inject the client policy in a JSE client. Hence you need to configure jps-config.xml and default-keystore.jks. jps-config.xml to inject the keystore and default-keystore.jks that would have the encryption keys.

Copy the default-keystore.jks: Download the default-keystore.jks file from this location to a location where the JSE client can access.

Setting up jps-config.xml: Store the contents of below file in a location as jps-config.xml. Make sure to replace the “keystore” serviceInstance tag location value with the location where the default-keystore.jks file has been saved.

<?xml version = '1.0' encoding = 'UTF-8'?>
 <jpsConfig xmlns="http://xmlns.oracle.com/oracleas/schema/11/jps-config-11_1.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.oracle.com/oracleas/schema/11/jps-config-11_1.xsd jps-config-11_1.xsd">
    <serviceProviders>
       <serviceProvider type="CREDENTIAL_STORE" name="credstore.provider" class="oracle.security.jps.internal.credstore.ssp.SspCredentialStoreProvider">
          <description>Credential Store Service Provider</description>
       </serviceProvider>
       <serviceProvider class="oracle.security.jps.internal.keystore.KeyStoreProvider" name="keystore.provider" type="KEY_STORE">
         <description>PKI Based Keystore Provider</description>
         <property value="owsm" name="provider.property.name"/>
       </serviceProvider>
    </serviceProviders>
    <serviceInstances>
       <serviceInstance name="credstore" provider="credstore.provider">
          <property name="location" value="./"/>
       </serviceInstance>
       <serviceInstance location="D:\default-keystore.jks" provider="keystore.provider" name="keystore">
         <description>Default JPS Keystore Service</description>
         <property value="JKS" name="keystore.type"/>
         <property value="oracle.wsm.security" name="keystore.csf.map"/>
         <property value="keystore-csf-key" name="keystore.pass.csf.key"/>
         <property value="sign-csf-key" name="keystore.sig.csf.key"/>
         <property value="enc-csf-key" name="keystore.enc.csf.key"/>
      </serviceInstance>
    </serviceInstances>
    <jpsContexts default="Application1">
       <jpsContext name="Application1">
          <serviceInstanceRef ref="credstore"/>
          <serviceInstanceRef ref="keystore"/>
       </jpsContext>
    </jpsContexts>
 </jpsConfig>

Find the keystore password: The password for the default-keystore.jks give above is welcome1. But in case if you want to find it yourself, you can get it using below command.
This should be executed after setting java path.

 set PATH=C:\Program Files\Java\jre6\bin
 keytool -list -v -keystore default-keystore.jks -storepass welcome1



Option 1: Run the main method on <Port>Client.java file that is generated by JAX-WS Proxy..

While generating JAX-WS proxy, it will generate the <Port>Client.java file which will have a main method. <Port> is the Port defined on your Web service that you can find it on the WSDL <service> tag.

In this main method, just add the WS call, run the main method and see what happens. Eg,

 @WebServiceRef
 private static EmpDeptBCService_Service empDeptBCService_Service;

 private static final AddressingVersion WS_ADDR_VER = AddressingVersion.W3C;

 public static void main(String[] args) {
     empDeptBCService_Service = new EmpDeptBCService_Service();

     BindingProvider wsbp = (BindingProvider)empDeptBCService;

     Map<String, Object> requestContext = wsbp.getRequestContext();
     requestContext.put(BindingProvider.USERNAME_PROPERTY, "weblogic");
     requestContext.put(BindingProvider.PASSWORD_PROPERTY, "weblogic1");

     try {
         EmployeesVOSDO emp = empDeptBCService.getEmployeesVO1(201);
         System.out.println(emp.getFirstName().getValue());
     } catch (ServiceException e) {
         e.printStackTrace();
     }
 }

Above code snippet will throw Invalid security error. Because this JSE client does not have any idea about FMW configuration files like connections.xml, jps-config.xml or default-keystore.jks which are responsible for injecting message encryption, OWSM client policies etc at runtime in a J2EE client.

To make this JSE client on <Port>Client.java work, in this main method, we can attach the client policy, inject the jps-config.xml and default-keystore.jks and set the required keystore and encryption keys required for web service call encryption. Finally invoking this main method will invoke the service. Hence I modify the code as below.

 @WebServiceRef
 private static EmpDeptBCService_Service empDeptBCService_Service;

 private static final AddressingVersion WS_ADDR_VER = AddressingVersion.W3C;

 public static void main(String[] args) {
     SecurityPolicyFeature[] securityFeature =
         new SecurityPolicyFeature[] { new SecurityPolicyFeature("policy:oracle/wss11_username_token_with_message_protection_client_policy") };

     EmpDeptBCService empDeptBCService =
         empDeptBCService_Service.getEmpDeptBCServiceSoapHttpPort(securityFeature);

     BindingProvider wsbp = (BindingProvider)empDeptBCService;

     Map<String, Object> requestContext = wsbp.getRequestContext();
     requestContext.put(BindingProvider.USERNAME_PROPERTY, "weblogic");
     requestContext.put(BindingProvider.PASSWORD_PROPERTY, "weblogic1");

     System.setProperty("oracle.security.jps.config","D:\\jps-config.xml");

     requestContext.put(ClientConstants.WSS_KEYSTORE_TYPE, "JKS");
     requestContext.put(ClientConstants.WSS_KEYSTORE_LOCATION, "D:\\default-keystore.jks");
     requestContext.put(ClientConstants.WSS_KEYSTORE_PASSWORD, "welcome1");

     try {
         EmployeesVOSDO emp = empDeptBCService.getEmployeesVO1(201);
         System.out.println(emp.getFirstName().getValue());
     } catch (ServiceException e) {
         e.printStackTrace();
     }
 }

Option 2: Invoke using ServiceDelegate

ServiceDelegate is an alternate option to obtain port to the service created through JAX-WS proxy and invoke the service end point. Below is the sample JSE model of invocation of the service using the JAX-WS Proxy with ServiceDelegate as JSE client.

public class InvokeUsingServiceDelegate {
 public InvokeUsingServiceDelegate() {
 super();
 }

 private static final String serviceNamespace = "http://go2kavinkumar.com/adf/sample/model/applicationModule/common/";
 private static final String serviceName = "EmpDeptBCService";
 private static final String servicePort = serviceName + "SoapHttpPort";

 public static void main(String... args) {
     InvokeUsingServiceDelegate invokeUsingServiceDelegate = new InvokeUsingServiceDelegate();

     String endPoint ="http://localhost:7101/empDeptService/EmpDeptBCService?WSDL";
     URL wsdlUrl=null;

     try {
         wsdlUrl = new URL(endPoint);
     } catch (MalformedURLException e) {
         e.printStackTrace();
     }
     ServiceDelegateImpl serviceDelegate = new ServiceDelegateImpl(wsdlUrl, new QName(serviceNamespace,serviceName),oracle.webservices.OracleService.class);
     EmpDeptBCService port = serviceDelegate.getPort(new QName(serviceNamespace, servicePort), EmpDeptBCService.class);

     BindingProvider wsbp = (BindingProvider)port;

     Map<String, Object> requestContext = wsbp.getRequestContext();
     requestContext.put(BindingProvider.USERNAME_PROPERTY, "weblogic");
     requestContext.put(BindingProvider.PASSWORD_PROPERTY, "weblogic1");

     System.setProperty("oracle.security.jps.config", "D:\\jps-config.xml");

     try {
         InputStream clientPolicy = EmpDeptBCService.class.getResourceAsStream("webservices-client.xml");
         requestContext.put(oracle.webservices.ClientConstants.CLIENT_CONFIG, fileToElement(clientPolicy));
     } catch (IOException e) {
         e.printStackTrace();
     } catch (Exception e) {
         e.printStackTrace();
     }

     requestContext.put(ClientConstants.WSS_KEYSTORE_TYPE, "JKS");
     requestContext.put(ClientConstants.WSS_KEYSTORE_LOCATION, "D:\\default-keystore.jks");
     requestContext.put(ClientConstants.WSS_KEYSTORE_PASSWORD, "welcome1");

     try {
         EmployeesVOSDO emp = port.getEmployeesVO1(201);
         System.out.println(emp.getFirstName().getValue());
     } catch (ServiceException e) {
         e.printStackTrace();
     }
 }

 private static Element fileToElement(InputStream f) throws IOException, Exception{
     DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
     builderFactory.setValidating(false);
     builderFactory.setNamespaceAware(true);
     builderFactory.setIgnoringElementContentWhitespace(true);
     builderFactory.setIgnoringComments(true);
     return builderFactory.newDocumentBuilder().parse(f).getDocumentElement();
 }
 }

While using the ServiceDelegate approach, the client policy has to be has to be physically attached with it using CLIENT_CONFIG properly in the request context. Hence it is obtained from below file in above code.

webservices-client.xml content:

 <oracle-webservice-clients>
 <webservice-client>
 <port-info>
 <policy-references>
 <policy-reference uri="oracle/wss11_username_token_with_message_protection_client_policy" category="security"/>
 </policy-references>
 </port-info>
 </webservice-client>
 </oracle-webservice-clients>

As you can see in above cases, we just injected the jps-config.xml and the default-keystore.jks with the keystore password. That has taken care of the message encryption/signature for message_protection.

In case if the service is secured with non-message_protection policy like “wss_saml_or_username_token_service_policy”, then just using respective client policy as SecurityPolicyFeature in option 1 or in webservices-client.xml in option 2 would have worked. We don’t need manual injection of jps-config.xml or default-keystore.jks as those are required only for message encryption or signing when there is message_protection involved.


Thanks,
Kavin.

How to start weblogic managed servers without manually entering the password

August 3, 2012 2 comments

While starting a managed server in weblogic, we start with below command.

<domain_home>/bin/startManagedWebLogic.sh soa_server1 t3://localhost:7001

This command will prompt to manually enter the username and password for the AdminServer. There are two ways of preventing that and here I am going to talk about it.

Option 1: Setting the java options for username and password.

Set below java option on your terminal before starting the managed server.

export JAVA_OPTIONS=”-Dweblogic.management.username=weblogic -Dweblogic.management.password=weblogic1″

After setting this, when the WLS Managed server startup kicks off, it will pick up the username and password from above properties and wouldn’t ask for manual entry of Adminserver username or password.

Option 2: Setting up boot.properties

While starting weblogic server [including AdminServer], it will check for a file called boot.properties in <domain_home>/servers/AdminServer/security. This file can hold the property values for username and password and if the right values are present, WLS isn’t going to prompt for manual authentication. This file will be present by default for AdminServer and that’s why while starting AdminServer, it doesn’t prompt for username and password.  To test, remove this file from servers/AdminServer/security and start your AdminServer – you will see that even AdminServer start up prompts you for entering username and password manually.

Enriching this concept for managed server, create a file boot.properties in the managed server folder.

Eg:

mkdir <domain_home>/servers/soa_server1/security

Create a new file called boot.properties and enter below property values.

username=weblogic
password=weblogic

Now save this file and start the managed server as usual.

<domain_home>/bin/startManagedWebLogic.sh soa_server1 t3://localhost:7001

This time also, it wouldn’t prompt to enter the username and password manually.

NOTE that when the server is started for the first time, it will automatically encrypt BOTH username and password stored on this file.

Thanks,

Kavin.

Correlation Set in BPEL to Interrupt BPEL

February 19, 2012 14 comments

Its been quite sometime since I blogged last – got very busy for past few months. Back now with something that I feel interesting.

Use case: A composite instance triggers a BPEL component. The BPEL component may invoke many asynchronous flows or it might be in wait state using “wait” activity or it might use a Human task and wait till human task completes. These scenarios might dehydrate BPEL. In this case, I take a scenario where I want to terminate the BPEL component instance when BPEL process is waiting for some legitimate reason.

Technical solution: The composite exposes a service with two operations. One MainOperation that would initiate the main flow of the BPEL. Two InterruptOperation that would trigger the OnMessage event handler of the same BPEL process and terminate the corresponding component instance initiated through MainOperation using Correlation sets.

Sample app used below: http://kavin-sample-apps.googlecode.com/files/InterruptBPEL.rar

Description of the project:

Create a SOA Application and Project with an empty SOA Composite.

The input schema that I have chosen for this composite is below. This schema has two messages.

1) EmployeeDetails -> Detail sent to initiate the main BPEL flow which has the core business logic. EmployeeId in this message is used in correlation set.

2) InterruptPayload -> This is used by InterruptOperation that is used to terminate the BPEL instance. This also carries EmployeeId so that the main flow can be correlated.

Create a new BPEL Process. Choose Template as “Base on a WSDL” and create a new WSDL file. Choose an one way operation and name it as “EmployeeProcessingFlow”. This is going to be the operation that is going to execute the core business logic in the BPEL process. This operation would be using “EmployeeDetails” element in above schema.

Instead of creating a new composite service for the Interrupt flow, let us add an additional operation to the existing WSDL in the same port. This operation is going to use a newly defined WSDL message “InterruptMessage” that would point to “InterruptPayload” in above given schema.

<wsdl:message name="requestMessage">
<wsdl:part name="EmployeeDetailMessage" element="inp1:EmployeeDetails"/>
</wsdl:message>
<wsdl:message name="InterruptMessage">
<wsdl:part name="InterruptMessage" element="inp1:InterruptPayload"/>
</wsdl:message>
<wsdl:portType name="EmployeeProcessingPort">
<wsdl:operation name="EmployeeProcessingFlow">
<wsdl:input message="tns:requestMessage"/>
</wsdl:operation>
<wsdl:operation name="InterruptFlow">
<wsdl:input message="tns:InterruptMessage"/>
</wsdl:operation>
</wsdl:portType>

Open the newly created BPEL process – “EmployeeProcessingProcess.bpel”. Add an OnMessage Event Handler to the global scope. This branch is going to wait for the incoming request from “InterruptFlow” operation of “EmployeeProcessingService”.

Now let’s correlate the receive and OnMessage entry point of EmployeeProcessingProcess into a single flow using correlation sets. To know more about correlation sets, refer to this section of Oracle SOA Suite Developers Guide. Basically correlation set is a way to attach a business specific key information to a BPEL instance so that the specific instance can be fetched at runtime and process can be executed further.

To start with, edit the receive activity of the BPEL process and add a new Correlation. Create a new Correlation set – “EmployeeFlowCorrelationSet”  with a property to bind the business object specific unique key – BindEmployeeId. Add the EmployeeId element from the Input message of the receive activity as a “Property Alias” for Property. Make sure “Initiate” property of this correlation in this receive activity to “yes”.

Tip: In above screenshot, NOTE that there is no icon to “choose” Query declaratively. So point the cursor there and press Ctrl+Enter so that it would show the message automatically to select.

Add a wait activity after receive and set wait time to 5 minutes to simulate the use case. On OnMessage branch, do a terminate to cancel the BPEL flow. So when the first message comes from “EmployeeProcessingFlow”, the BPEL will be in wait state for 5minutes. In the interim, when message from “InterruptFlow” comes, then it would be correlated with old instance and the instance would be terminated. If certain clean up need to be done before termination, then it can be included in OnMessage branch before Terminate.

Edit the OnMessage branch and bind the same correlation. In this OnMessage branch, the EmployeeId from InterruptMessage has to be set as Property Alias for the existing correlation set.

That completes the coding 🙂

Testing the project:

Now deploy the composite to EM and access the end point using the default end point tester URL.

http://localhost:7001/soa-infra/services/default/InterruptBpelFlow/EmployeeProcessingService_ep

Select the operation “EmployeeProcessingFlow” that handles main flow. Enter an EmployeeId value like “349827495” and a random Salary value and Invoke this to Initiate the composite main flow. This would initiate the BPEL process receive activity by setting EmployeeId as correlation id and put the BPEL in wait state for 5 minutes which can be seen from EM.

Now on the same URL [http://localhost:7001/soa-infra/services/default/InterruptBpelFlow/EmployeeProcessingService_ep], select the “InterruptFlow” operation with same EmployeeId as input so that it would correlate with above mentioned BPEL instance and terminate it.

Thanks for Reading and Keep Smiling 🙂

Kavin

Enable/Disable EDN Events Logging in SOA 11g

October 11, 2011 3 comments

Business Events Logging comes very handy when you want to debug issues with Business Events – like Event Name, Namespace, Payload, Security Subject, De-queue status etc. For this, you need to enable EDN Logging in first place. There are different modes to enable EDN Logging.

1) Through edn-db-log URL:

Launch edn-db-log URL  which will be available on your SOA Server – http://localhost:7001/soa-infra/events/edn-db-log.

Click Enable link on top.

Publish your business event.

Click on reload button on edn-db-log page.

This must show your business event on this page. It would appear twice. One is the enque of the business event and the other one is for de-queue of the business event for delivery. If you don’t see dequeue message, then your business event wont get delivered.

Once you have completed debugging your business event, click on disable link to disable edn logging. This would prevent unnecessary DB Growth on the EDN_LOG_MESSAGES table which stores the huge EDN message content. You can use the clear link on the edn-db-log page to clear the event log messages from the logs table.

2) Using edn_enable_logging procedure:

SOA Ships a PL-SQL Procedure to update EDN Logging values.

DECLARE
ENABLEDINPUT NUMBER;
BEGIN
ENABLEDINPUT := 1;
edn_enable_logging(ENABLED=>ENABLEDINPUT);
commit;
END ;

Once logging is enabled, you can publish your business event and monitor the event log from EDN_LOG_MESSAGES table. Again once your debugging is completed, disable EDN Logging immediately.

3) Directly update the DB Table:

Enabling/Disabling the logging on edn-db-log UI is going to update the EDN_LOG_ENABLED table. A value 0 on this table indicates that the EDN Logging is disabled. A value 1 indicates that EDN Logging is enabled.

insert into edn_log_enabled values (1);
commit;

NOTE: Using this step is highly discouraged. One of the main reasons being, this table carries only one record on one existing column whose value can be 1 or 0. So you must delete the previous record before inserting using above command.

delete from edn_log_enabled;
insert into edn_log_enabled values (0);
commit;

Always for a backend update, it is recommended to go with option 2.

Thanks for Reading and Keep Smiling :-)

Kavin.

Enable/Disable Business Events Delivery in EDN

October 11, 2011 Leave a comment

In SOA 11g, Business events framework, below is the option that is used to control the delivery of business events to the target consumers.

Login to Enterprise Manager -> Expand SOA. Right click on soa_server1 -> Administration -> System Mbean browser. Expand Application Defined MBeans -> oracle.as.soainfra.config -> Server:****** -> EDNConfig -> edn.

You can see a property called Paused. When this property is set to true, then it temporarily suspends the delivery of business events.When this value is false, events are delivered as usual.

This comes very handy when you are debugging event subscription issues where you can see event properly in EDN Log, but the composite subscribing to that business event isn’t fired.

Thanks for Reading and Keep Smiling :-)

Kavin.

Access Composite/Component details in Java Embedding Activity in BPEL

September 30, 2011 Leave a comment

Use case: We can use ora:getCompositeInstanceId() or ora:getComponentInstanceId() Xpath expressions in BPEL Process to get the composite instance id and the component instance id. In this post, I am going to talk about how to get the same in,

1) Java code

2) Java Embedding Activity in BPEL Process.

Sample Project: http://kavin-sample-apps.googlecode.com/files/JavaEmbedding.rar

Description:

1) Access composite/component instance id in Java code:

Below is the java code to access composite instance id from a component instance id in the java code.

package kavin.soa.samples.facade;

import java.util.Hashtable;

import java.util.List;

import javax.naming.Context;

import oracle.soa.management.facade.Component;
import oracle.soa.management.facade.ComponentInstance;
import oracle.soa.management.facade.Composite;
import oracle.soa.management.facade.Locator;
import oracle.soa.management.facade.LocatorFactory;
import oracle.soa.management.util.ComponentInstanceFilter;

public class FetchComposite {
public FetchComposite() {
super();
}

private static void getConnection() {
Locator locator = null;
Hashtable jndiProps = new Hashtable();
jndiProps.put(Context.PROVIDER_URL, "t3://localhost:7001/soa-infra");
jndiProps.put(Context.INITIAL_CONTEXT_FACTORY,
"weblogic.jndi.WLInitialContextFactory");
jndiProps.put(Context.SECURITY_PRINCIPAL, "weblogic");
jndiProps.put(Context.SECURITY_CREDENTIALS, "weblogic1");
jndiProps.put("dedicated.connection", "true");

String componentInstanceID = "120005";

try {
locator = LocatorFactory.createLocator(jndiProps);
Composite composite =
(Composite)locator.lookupComposite("default/JavaEmbedding!1.0");
Component javaEmbeddingComponent =
(Component)locator.lookupComponent("default/JavaEmbedding!1.0/JavaEmbeddingProcess");

ComponentInstanceFilter compInstFilter =
new ComponentInstanceFilter();
compInstFilter.setCompositeDN(composite.getDN());
compInstFilter.setComponentName("JavaEmbeddingProcess");
compInstFilter.setId(componentInstanceID);

List<ComponentInstance> compInstances =
javaEmbeddingComponent.getInstances(compInstFilter);
if (compInstances != null) {
System.out.println("====JavaEmbeddingInstances===");
for (ComponentInstance compInst : compInstances) {
String compositeInstanceId =
compInst.getCompositeInstanceId();
String componentStatus = compInst.getStatus();
System.out.println("Composite Instance ID is " +
compositeInstanceId);
System.out.println("Component Status is " +
componentStatus);
}
}
} catch (Exception e) {
System.out.println("Exception in getting locator/composite details");
}
}

public static void main(String... a) {
getConnection();
}
}

Tips from above code:

  • If you see in above code, we are having the component instance ID and from that we are trying to retrieve the related composite instance ID. Reason being, I was trying to write java version of my requirement in BPEL. In BPEL Java Embedding activity, API is available to directly get the component instance ID without any complexity.  You would understand that more clearly when you read section 2 of this post.
  • Locator -> Object used to locate and fetch composite/component instances and details.
  • LocatorFactory -> Used to fetch the locator object. If a context is already established, the JNDI Properties are not required and the overloaded version, createLocator() can be used.
  • Composite -> Used to get the composite object. NOTE that this is the entire composite object as a whole and not a composite instance. It takes the composite JNDI name in pattern <partition-name>/<composite-name>!<revision-id>. Eg: default/JavaEmbedding!1.0
  • Component -> Used to get the components of the provided JNDI name. The JNDI name is of format <partition-name>/<composite-name>!<revision-id>/<component-name>. Eg, default/JavaEmbedding!1.0/JavaEmbeddingProcess where JavaEmbeddingProcess is my BPEL Component Name.
  • ComponentInstanceFilter/CompositeInstanceFilter -> Filters that can be applied on top of Composite/Component objects to query for instances. Applying filter optimizes the query.
  • ComponentInstance/CompositeInstance -> Used to get a specific Component/Composite Instance whose properties like state/instance id can be obtained.

Over all, above code assumes that Component instance ID is available, fetches all Components of type “default/JavaEmbedding!1.0/JavaEmbeddingProcess”, filters them based on CompositeDN, ComponentName, ComponentInstanceId. Ideally this would give only one result which is going to be the Component Instance. Using that Component Instance, the Composite Instance ID corresponding to that Component is retrieved.

2) Access composite/component instance id in Java Embedding activity in BPEL code:

This part talks about implementing above use case in BPEL Process within a Java Embedding Activity. Java Embedding Activity has an out of the box function called getInstanceId() which returns the Component Instance ID of the particular component. Hence retrieving component instance id in java embedding activity in BPEL isn’t a problem at all. Now how to get the Composite Instance ID. It can be done in two ways.

Option 1: Easiest option.

1) Create a variable compositeInstanceID in BPEL Process.

2) Using XPath, assign composite instance id to this variable using an assign activity.

<assign name="Assign1">
<copy>
<from expression="ora:getCompositeInstanceId()"/>
<to variable="compositeIdUsingXPath"/>
</copy>
</assign>

3) In Java Embedding Activity, Access this variable value using below code snippet.

String compositeInstanceId = getVariableData("compositeInstanceID");

addAuditTrailEntry("Composite instance ID is "+compositeInstanceId);

Where addAuditTrailEntry function is used to print the message on audit trail.

Option 2: Using the Java Code mentioned in 1st section of this post.

The first assign activity is a dummy place holder to add composite instance id and component instance id to a dummy variable which can be used to verify the code in java embedding activity at runtime.

<assign name="Assign1">
<copy>
<from expression="ora:getComponentInstanceId()"/>
<to variable="componentIdUsingXPath"/>
</copy>
<copy>
<from expression="ora:getCompositeInstanceId()"/>
<to variable="compositeIdUsingXPath"/>
</copy>
</assign>

“Dehydrate1” -> Dehydration activity to force dehydration API. This is very very important for the Java code using Locator inside Java Embedding activity to work. NOTE that the out of box functions like getInstanceId() or getVariableData() that we use in Java Embedding activity would fetch the data from memory. But the Locator APIs would fetch the data from DB. Hence if you don’t force a dehyderation, then data isn’t available in DB and hence you may not see the results that you may like to see. Hence I am forcing the dehydration in my sample application.

Followed by  a series of imports of the class used in Java Embedding activity. This isn’t shown on the screenshot as the imports doesn’t come up on the designer.

<bpelx:exec import="oracle.soa.management.facade.Component"/>
<bpelx:exec import="oracle.soa.management.facade.ComponentInstance"/>
<bpelx:exec import="oracle.soa.management.facade.Composite"/>
<bpelx:exec import="oracle.soa.management.facade.Locator"/>
<bpelx:exec import="oracle.soa.management.facade.LocatorFactory"/>
<bpelx:exec import="oracle.soa.management.util.ComponentInstanceFilter"/>
<bpelx:exec import="java.util.List"/>

Next is the Java Embedding Activity to fetch the component instance id and composite instance id and print it on audit trail.

<bpelx:exec name="Java_Embedding1" version="1.5" language="java">
<![CDATA[/*Write your java code below e.g.
System.out.println("Hello, World");
*/
try {
String componentInstanceID = new Long(getInstanceId()).toString();
addAuditTrailEntry("Component Instance ID is "+componentInstanceID);

Locator locator = LocatorFactory.createLocator();
Composite composite = (Composite)locator.lookupComposite("default/JavaEmbedding!1.0");
Component javaEmbeddingComponent = (Component)locator.lookupComponent("default/JavaEmbedding!1.0/JavaEmbeddingProcess");

ComponentInstanceFilter compInstFilter = new ComponentInstanceFilter();
compInstFilter.setCompositeDN(composite.getDN());
compInstFilter.setComponentName("JavaEmbeddingProcess");
compInstFilter.setId(componentInstanceID);

List<ComponentInstance> compInstances = javaEmbeddingComponent.getInstances(compInstFilter);
if (compInstances != null) {
addAuditTrailEntry("====JavaEmbeddingInstances===");
for (ComponentInstance compInst : compInstances) {
String compositeInstanceId = compInst.getCompositeInstanceId();
String componentStatus = compInst.getStatus();
addAuditTrailEntry("Composite Instance ID is "+compositeInstanceId);
addAuditTrailEntry("Component Status is "+componentStatus);
}
}

} catch (Exception e) {
addAuditTrailEntry("Exception in getting locator/composite details");
}]]>
</bpelx:exec>

The logic is same as I explained in section 1. Get component instance id using getInstanceId API and use it to filter components and get the composite instance id.

The above given code can be easily extended to play around with the composite or component instance. If you have a use case that you are trying to solve, feel free to comment your requirement. I can help you to figure out.

Testing the sample composite project:

1) Deploy the composite project.

2) Open the end-point tester for this composite service through soa-infra URL.

http://localhost:7001/soa-infra/services/default/JavaEmbedding/JavaEmbeddingService_ep

Enter an input and click on invoke button.

3) Open the composite Audit trail from EM to see the printed values on audit trail.

Thanks for Reading and Keep Smiling 🙂

Kavin.