Pages

Tuesday, November 30, 2010

ADF Faces Rich Client Development

In this blogpost I will try to give you a jumpstart in javascript development. For ADF Faces RC development you need to have JDeveloper 11g together with Mozilla FireFox & the FireBug plugin.
This blogpost is inspired by the great work of Frank Nimphius ( Lot's of demos and a very good chapter in his book ) and a very nice blogpost of Chris how you can use hotkeys, to switch Tabs in UIShell.

Before you can start we need to add some context parameters to the web.xml
<context-param>
    <param-name>oracle.adf.view.rich.profiler.ENABLED</param-name>
    <param-value>true</param-value>
  </context-param>
  <context-param>
    <param-name>oracle.adf.view.rich.LOGGER_LEVEL</param-name>
    <param-value>ERROR</param-value>
  </context-param>
  <context-param>
    <param-name>oracle.adf.view.rich.LOG_WRITERS</param-name>
    <param-value>AdfConsoleLogWriter</param-value>
  </context-param>
  <context-param>
    <param-name>org.apache.myfaces.trinidad.DEBUG_JAVASCRIPT</param-name>
    <param-value>true</param-value>
  </context-param>
I set the oracle.adf.view.rich.LOGGER_LEVEL to ERROR because the RC frameworks generates a lot of INFO messages, so you won't see your own log messages.
The oracle.adf.view.rich.LOG_WRITERS parameter enables the Javascript Logger popup window, when the firebug console is enabled then this popup won't launch and the messages will be seen in the firebug console window.
The org.apache.myfaces.trinidad.DEBUG_JAVASCRIPT will allow to debug a javascript file in the firebug debug console.

The next step is to create a javascript file and put this in a new folder in the Web Content folder of your web application.

To load the javascript files in your ADF Web Application you can use af:resource
<af:resource type="javascript" source="js/keys.js"/>
When you do this in the JSPX page then every page / region or fragment can call these javascript methods.
<?xml version='1.0' encoding='UTF-8'?>
<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" version="2.1"
          xmlns:f="http://java.sun.com/jsf/core"
          xmlns:h="http://java.sun.com/jsf/html"
          xmlns:af="http://xmlns.oracle.com/adf/faces/rich">
  <jsp:directive.page contentType="text/html;charset=UTF-8"/>
  <f:view beforePhase="#{viewScope.HandleKeys.registerKeyboardMapping}">
    <af:document id="document" title="Client Side">
      <af:resource type="javascript" source="js/keys.js"/>
      <af:resource type="javascript" source="js/utils.js"/>
      <af:serverListener type="keyboardToServerNotify"
                         method="#{viewScope.HandleKeys.handleKeyboardEvent}"/>
      <af:form id="f1">
        <af:pageTemplate viewId="/oracle/ui/pattern/dynamicShell/dynamicTabShell.jspx"
                         value="#{bindings.pageTemplateBinding}" id="pt1">

To call a javascript method from your JSF page you can use af:clientListener where you need to provide the method name and how it is activated.
<af:clientListener method="numbersOnly" type="keyDown"/>

Here an example of a javascript method
function numbersOnly(evt){
     var _keyCode = evt.getKeyCode();
     var _filterField = evt.getCurrentTarget();
     var _oldValue = _filterField.getValue();
     
     AdfLogger.LOGGER.logMessage(AdfLogger.ERROR, "key: "+_keyCode);
     //check for characters
     if (_keyCode > 64 && _keyCode < 91){  
       _filterField.setValue(_oldValue);
       evt.cancel(); 
     }
  }
In this code the AdfLogger.LOGGER.logMessage will log a message in the firebug console or logging popup.

ADF 11g has a very large Javascript API which you can use in your own Web Application, to see the API, click here.

You can also pass on data to the javascript method. You can use the af:clientAttribute for this with as value a text or an EL expression.
<af:panelHeader text="Tab Order" id="ph4">
     <af:panelFormLayout id="pform" clientComponent="true">
      <af:inputText id="it3" label="Tab 1">
        <af:clientAttribute name="tabindex" value="1"/>
        <af:clientListener method="setTabIndex('1','4')" type="keyPress"/>
      </af:inputText>
      <af:inputText id="it4" label="Tab 3">
        <af:clientAttribute name="tabindex" value="3"/>
        <af:clientListener method="setTabIndex('1','4')" type="keyPress"/>
      </af:inputText>
      <af:inputText id="it5" label="Tab 4">
        <af:clientAttribute name="tabindex" value="4"/>
        <af:clientListener method="setTabIndex('1','4')" type="keyPress"/>
      </af:inputText>
      <af:inputText id="it6" label="Tab 2">
        <af:clientAttribute name="tabindex" value="2"/>
        <af:clientListener method="setTabIndex('1','4')" type="keyPress"/>
      </af:inputText>
     </af:panelFormLayout>
    </af:panelHeader>
To get the clientAttribute value in javscript you can use this in javascript , component.getProperty("tabindex") Or you can do a Javascript callback
function setTabIndex( min, max) {
     return function (evt) {
       var minTabIndex = min;
       var maxTabIndex = max;
       
       var keyCodePressed = evt.getKeyCode();
       var keyModifiers = evt.getKeyModifiers();
       var component = evt.getSource();
       var panelForm = component.getParent();

       if ( keyCodePressed == AdfKeyStroke.TAB_KEY ) {
         evt.cancel();
         var tabIndex = parseInt(component.getProperty("tabindex"));
       }
    }
  }

Next question will be, how can you invoke a method in a managed bean (serverside) from the clientside. For this we can use af:serverListener, but you can not invoke this managed bean method directly. You need to fire a client ADF Event from the clientListener method. like this AdfCustomEvent.queue( source, "clickOnRow", {}, false);
<af:table value="#{bindings.allDepartments.collectionModel}" var="row"
               rows="#{bindings.allDepartments.rangeSize}"
               emptyText="#{bindings.allDepartments.viewable ? 'No data to display.' : 'Access Denied.'}"
               fetchSize="#{bindings.allDepartments.rangeSize}"
               rowBandingInterval="0" rowSelection="single" id="departmentTable"
               width="400"
               selectedRowKeys="#{bindings.allDepartments.collectionModel.selectedRow}">
      <af:clientListener method="clickRow" type="click"/>
      <af:serverListener type="clickOnRow" method="#{Client.goCurrentRow}"/>
      <af:column sortProperty="departmentId" sortable="false"
                 headerText="#{bindings.allDepartments.hints.departmentId.label}"
                 id="c1">
       <af:outputText value="#{row.departmentId}" id="ot3">
        <af:clientAttribute name="departmentId" value="#{row.departmentId}"/>
        <af:clientListener method="showPopup('::deptPopup','dialog1','departmentId')"
                           type="click"/>
       </af:outputText>
      </af:column>
      <af:column sortProperty="departmentName" sortable="false"
                 headerText="#{bindings.allDepartments.hints.departmentName.label}"
                 id="c2" width="200">
       <af:outputText value="#{row.departmentName}" id="ot1"/>
      </af:column>
     </af:table>
Here is the javascript for the ADF Client Event.
function clickRow(evt) {
     var source = evt.getSource();
     AdfLogger.LOGGER.logMessage(AdfLogger.ERROR, "clickOnRow");
     AdfCustomEvent.queue( source, "clickOnRow", {}, false); 
  } 
And the managed bean method.
public void goCurrentRow(ClientEvent clientEvent) {
       // Determine which row is currently selected in the RichTable
       RichTable deptTable = (RichTable)clientEvent.getComponent();
       Iterator keys = deptTable.getSelectedRowKeys().iterator();
       while (keys.hasNext()) {
           Key key = (Key)((List)keys.next()).get(0);
           System.out.println(key.getKeyValues()[0]);
       }
   }

The only thing still to do is to debug the javascript methods. Start you Web application in FireFox and open the firebug application.  Click on the script Tab.

 Select the javascript file which you want to debug.

Set the breakpoint and debug through your application.

Here is my demo application with the following client examples ( thanks to Frank ).

  • Hotkeys for Tab switching
  • Tab Order
  • Clear validation messages
  • Type only numbers in a inputtext.
  • Click on a record and invoke a managed bean method
  • Click on a inputtext and display the value in a popup


Here you can download the demo workspace

Thursday, November 25, 2010

Start or Stop your SOA Suite 11g Composite in Java

In this short blogpost I will show you how can execute operations on a SOA Suite 11g Composite in java. The operations are start, stop, activate, retire, set the default version and list all the deployed composites.

I use for this the oracle.fabric.management.deployedcomposites.CompositeManager class ( located in the fabric runtime ) with its static methods.
The SOA ANT scripts also uses this class or you can do it yourself by looking up the right Composite MBean and invoke the same operations.

Before PS2 you could lookup the composite and call the start/ stop methods, but this not working anymore so now you need to use this ( or use the EM or the MBeans )
package nl.whitehorses.soa.client;

import oracle.fabric.management.deployedcomposites.CompositeManager;

public class ActivateComposite {

    public static void main(String[] args) {
      try {
           CompositeManager.initConnection("localhost", "8001", "weblogic", "weblogic1");

           CompositeManager.assignDefaultComposite(CompositeManager.getCompositeLifeCycleMBean(), "default/Helloworld!1.0");

           CompositeManager.stopComposite(CompositeManager.getCompositeLifeCycleMBean(), "default/Helloworld!1.0");

           CompositeManager.startComposite(CompositeManager.getCompositeLifeCycleMBean(), "default/Helloworld!1.0");

           CompositeManager.activateComposite(CompositeManager.getCompositeLifeCycleMBean(), "default/Helloworld!1.0");

           CompositeManager.retireComposite(CompositeManager.getCompositeLifeCycleMBean(), "default/Helloworld!1.0");

           System.out.println(CompositeManager.listDeployedComposites(CompositeManager.getCompositeLifeCycleMBean()));

           CompositeManager.closeConnection(); 

      } catch (Exception  e) {
          e.printStackTrace();
      } 
    }
}

With this as result.
Connecting to: service:jmx:t3://localhost:8001/jndi/weblogic.management.mbeanservers.runtime

Following 5 composites are currently deployed to the platform:

1. HttpBinding[1.0], mode=active, state=on, isDefault=true, deployedTime=2010-08-20T22:42:58.888+02:00
2. SoaSpring[1.0], mode=active, state=on, isDefault=true, deployedTime=2010-07-10T15:41:07.640+02:00
3. bpm[1.0], mode=active, state=on, isDefault=true, deployedTime=2010-07-10T15:58:13.853+02:00
4. Helloworld[1.0], mode=retired, state=on, isDefault=true, deployedTime=2010-09-22T02:37:50.924+02:00
5. BPELCorrelation[1.0], mode=active, state=on, isDefault=true, deployedTime=2010-09-01T22:14:59.374+02:00

Saturday, November 13, 2010

Global Transactions and Quality of Service in OSB

Last week I had a great OSB BlackBelt training of Samrat Ray and organized by the SOA Community  In this training we talked a lot about Global Transactions ( XA), QoS ( Quality of Service )  in combination with Transports and JCA Adapters. Because this is so important ( you dont want to lose a Message ) I decide to make a blog about this subject and I will explain the different scenarios options you have in the Oracle Service Bus.

Before I can start I need to create and configure some Queues. In this blogpost I will use JMS for the Proxy and the Business service but you can also use EJB, MQ or the Direct Binding ( SOA Suite 11g ) for the Business Service, they all support XA, HTTP transport does not support XA ).

First create the RequestQ Queue combined with an ErrorQ Queue ( Now failed messages will be redirected to this Queue and won't be lost in Space), a ReponseQ Queue and a DestinationQ Queue ( used in the Business service )

Here is a picture how you can define an Error Queue on the RequestQ.  Go to the Queue, select the Delivery Failure Tab in the Configuration Tab. Now you can set the Redirect Expiration Policy and select the Error destinations.


I start with a simple scenario.  Add a message in the RequestQ and we will expect the message in the ResponseQ.

Add a Proxy Service ( any XML) and select JMS as protocol. OSB generates a default url with an internal XA connection factory and add the Queue name to this URL.

Add the destination Queue in the Proxy Service by enabling the Is Response Required option. Use text as Response Message Type ( else it will be hard to read the message ) and provide the Response URI.

Leave the Message Flow empty and a message in the RequestQ ( Go to the Queue, monitoring tab and a create a new message).  Always change the Redelivery Limit  ( Don't use the value -1 )
You will this message in the ResponseQ.

So far so good, now let's raise an Error on the Response Channel and take a look at the results. In the message flow I added a PipelinePair with a stage and an Error activity.
What you will see the message is removed from the RequestQ and the ResponseQ only gets a message with a SERVER_ERROR header and the content is gone.
We can solve this by making a change in the Proxy Service. Enable the Same Transaction For Response option, the response Thread will take over the transaction so when now something happens the transaction will be roll backed.



Add a message to the RequestQ, ( set the Redelivery to 2 else you will get a loop ) what you will see that the message now is added to the ErrorQ and not to the ResponseQ. This is good behaviour. Now you can re-process this message again by moving it to the RequestQ or let an ErrorHospital handle it.

The next step is adding a business service ( also use JMS and a XA Connection Factory )  and make this part of the Global Transaction. Add a routing to this Business Service in the message flow of the Proxy Service. This will also add the message to the DestinationQ. Make sure  that the Message Type = text ( for this test only )
When you now put a message on the RequestQ, the message is also roll backed on the DestinationQ and only exists in the Error Queue.
When you disable the option Same Transaction for Response ( Default behavior ) then this message will be removed even when there is an error in the Response Channel of the Proxy Service.

The last part of this blog is taking a look at Quality of Service ( QoS ). QoS requires a transaction ( The Proxy Service need to start it ) and you can control, if the Business Service will take part on the Global Transaction. You need to add a Routing options activity to the request part of the Routing Node. First set QoS on Best Effort. Exactly Once is the default value when you use JMS and XA in the Proxy Service.

When you add a message on the RequestQ with a retry delivery of 5, You will see 6 messages in the DestinationQ. With Best Effort you will force the Business Service not to use the Global Transaction. Don't think you will like this,so let's change this to Exactly Once or remove this Routing Options action.



Conclusion: You need to think about your process and ask yourself is it a problem when your message is lost and what about when you deliver the same message again and again. Be aware one transaction for the request and response in the Proxy Service is not enabled by default and you need to configure it and test all the situations. Off course you need to use XA connection factories, Datasources and XA configured Resource Adapters.
HTTP Proxy or Business Services won't be part of XA. When you call a BPEL service you can use the Direct Binding transport for this.

Wednesday, November 3, 2010

Deploy your AQ , DB or JMS Resource Adapter to Weblogic and use it in OSB & SOA Suite

When you are familiar with SOA Suite 11g or Oracle Service Bus then you know, that sometimes you need to configure some Resource Adapters in WebLogic. This is necessary when you use the Database, AQ , JMS or Applications adapter in your Composite application or Proxy / Business Service. This task can't be scripted with WLST, The first time you need to generate a Deployment Plan and after that, you can add your EIS entries. In a Cluster environment you need to put this Deployment Plan on a shared storage or copy this to every server.
In this blogpost I will you show that you can deploy your own Resource Adapter with your EIS entries to the SOA Server or Cluster. This way you can separate EIS entries in their own Resource Adapter, so you don't have one big Deployment Plan. Reduce the human factor and just deploy it, no manual tasks after you SOA Composites deployments. And you can deploy it to a cluster and add these Resource Adapter files to your Subversion system.

Basically I do the following steps.
  • Extract the WebLogic Resource Adapters files to a local folder
  • Remove the jars, because these jars are already loaded in the original Resource Adapters
  • Edit the weblogic-ra.xml and remove the default entries and add your own
  • Pack the Resource Adapter
  • Undeploy the Resource Adapter on the WebLogic Server
  • Deploy the Resource Adapter
  • Set the deployment order after the original Resource Adapter
Here a picture of my JDeveloper project where I can do these tasks with the help of ANT and WLST.
 To make this work you need to add your WebLogic jar to the classpath of the ANT environment.


Change the weblogic-ra.xml with your own Entries.

And at last deploy all the Resource Adapters or just one

Here is the ANT properties file. With changing the EnvironmentName you can create a different set of Resource Adapters
FMW.home=C:/oracle/Soa11gPS2
WLS.home=${FMW.home}/wlserver_10.3
SOA.home=${FMW.home}/Oracle_SOA1
SOA.adapters.home=${SOA.home}/soa/connectors

WLS.fullclient=C:/java/wlfullclient.jar

AQ=AqAdapter
DB=DbAdapter
JMS=JmsAdapter

EnvironmentName=MyAdap

build.folder=build

serverURL=t3://laptopedwin:7001
user=weblogic
password=weblogic1

targets=soa_server1

The ANT Build file
<?xml version="1.0" encoding="UTF-8" ?>
<project default="init">

  <property file="build.properties"/>

  <taskdef name="wldeploy" classname="weblogic.ant.taskdefs.management.WLDeploy"/>
  <taskdef name="wlst"     classname="weblogic.ant.taskdefs.management.WLSTTask"/>

  <target name="initAdapters">
     <!-- make an environment folder   -->
     <delete dir="${EnvironmentName}" failonerror="true" />
     <mkdir  dir="${EnvironmentName}"/>
     <!-- unpack the adapters   -->
     <unjar src="${SOA.adapters.home}/${AQ}.rar" dest="${EnvironmentName}/${AQ}" />
     <unjar src="${SOA.adapters.home}/${DB}.rar" dest="${EnvironmentName}/${DB}" />
     <unjar src="${SOA.adapters.home}/${JMS}.rar" dest="${EnvironmentName}/${JMS}" />     
     <!-- remove the jars   -->
     <delete>
       <fileset dir="${EnvironmentName}" includes="**/*.jar"/>
     </delete>
  </target>

  <target name="packAdapters">
     <!-- make a build folder   -->
     <delete dir="${build.folder}"/>
     <mkdir dir="${build.folder}"/>
     <jar basedir="${EnvironmentName}/${AQ}" destfile="${build.folder}/${EnvironmentName}_AQAdapter.rar" />
     <jar basedir="${EnvironmentName}/${DB}" destfile="${build.folder}/${EnvironmentName}_DBAdapter.rar" />
     <jar basedir="${EnvironmentName}/${JMS}" destfile="${build.folder}/${EnvironmentName}_JMSAdapter.rar" />
  </target>

  <target name="deployAll" depends="packAdapters">
     <!-- deploy AQ   -->
     <antcall target="deployAQ"/>
     <antcall target="deployDB"/>
     <antcall target="deployJMS"/>
  </target>  

  <target name="deployAQ" depends="packAdapters">
     <!-- deploy AQ   -->
     <antcall target="undeploy" >
       <param name="deployment" value="${EnvironmentName}_AQAdapter"/>
     </antcall>
     <antcall target="deploy" >
       <param name="deployment" value="${EnvironmentName}_AQAdapter"/>
     </antcall>     
     <antcall target="changeDeploymentOrder" >
       <param name="deployment" value="${EnvironmentName}_AQAdapter"/>
     </antcall>     
  </target>  

  <target name="deployDB" depends="packAdapters">
     <!-- deploy AQ   -->
     <antcall target="undeploy" >
       <param name="deployment" value="${EnvironmentName}_DBAdapter"/>
     </antcall>
     <antcall target="deploy" >
       <param name="deployment" value="${EnvironmentName}_DBAdapter"/>
     </antcall>     
     <antcall target="changeDeploymentOrder" >
       <param name="deployment" value="${EnvironmentName}_DBAdapter"/>
     </antcall>     
  </target>  

  <target name="deployJMS" depends="packAdapters">
     <!-- deploy AQ   -->
     <antcall target="undeploy" >
       <param name="deployment" value="${EnvironmentName}_JMSAdapter"/>
     </antcall>
     <antcall target="deploy" >
       <param name="deployment" value="${EnvironmentName}_JMSAdapter"/>
     </antcall>     
     <antcall target="changeDeploymentOrder" >
       <param name="deployment" value="${EnvironmentName}_JMSAdapter"/>
     </antcall>  
  </target>  

  <target name="changeDeploymentOrder" >
    <wlst failonerror="true" debug="true" arguments="${user} ${password} ${serverURL} ${deployment}">
      <script>
          adminUser=sys.argv[0]
          adminPassword=sys.argv[1]
          adminUrl=sys.argv[2]
          deploymentAdapter='/AppDeployments/'+sys.argv[3]

          connect(adminUser,adminPassword,adminUrl)

          edit()
          startEdit()

          cd(deploymentAdapter)
          cmo.setDeploymentOrder(500)
         
          activate()
          disconnect()    
       </script>
    </wlst>
  
  </target>

  <target name="undeploy">
     <wldeploy action="undeploy" 
               name="${deployment}"
               user="${user}"
               password="${password}"
               adminurl="${serverURL}"
               targets="${targets}"
               failonerror="false">
     </wldeploy>
  </target>

  <target name="deploy">
     <wldeploy action="deploy" 
               name="${deployment}"
               source="${build.folder}/${deployment}.rar"
               user="${user}"
               password="${password}"
               adminurl="${serverURL}"
               targets="${targets}"
               upload="true"
               failonerror="true">
     </wldeploy>
  </target>



</project>

Here you can download my workspace.

Saturday, September 25, 2010

Using the Oracle IPlanet Web & Proxy Server for FMW ( Reverse proxy )

With the Sun acquisition Oracle also acquired the IPlanet / Sun One software. Two of these Sun One products will play an important role in the Fusion Middleware. The first is the Oracle IPlanet Web Server 7.0 ( Or Sun One , IPlanet, Netscape Server ), I already know this Web Server from the Netscape timearea and it work nice. The IPlanet Web server can replace the Oracle HTTP Server or the Apache Server. IPlanet has some great advantages like a nice console application where you can configure nodes, configurations and instances or you can also use the command line for this. And It looks like WebLogic ( AdminServer, Managed Server , Nodes and Clusters ).
The second is the Oracle IPlanet Proxy Server 4.0. This product will replace the current Oracle WebCache version in FMW 12c (cloud). Oracle IPlanet Proxy can cache and filter web content.
Both IPlanet product supports reverse proxying. This means it can be used in front of the WebLogic Servers. The IPlanet Proxy Server can also cache the WebLogic content and supports filtering, like passing on every request to the WebLogic instances (this is the case with IPlanet Web Server ) or only when it starts with /em or /console etc.
Both product can be downloaded in edelivery ( Search for Fusion Middleware ).

We start with the Oracle Iplanet Web Server.
IPlanet Web Server
First select the right Configuration and after that theVirtual Server which is part of this Configuration. Click on Setup Reverse Proxy. 



You need to use / as URI prefix and the Weblogic servers seperated with , in the value of the Server Names field.

Because everything is forwarded to the WebLogic Server we can disable Java in the Configuration part. ( less resources)

Deploy your configuration and restart the Instance.

That's all for the IPlanet Web Server.

IPlanet Proxy Server
For the IPlanet Proxy Server you need to do the following.

Click on the right server
 Go to Routing and click on Regular Expression.
Here you can do every url or just one. For all then use /.* else for example /console/.*
I will use in this example /console/.*

Select your URL and Click on Select

Go to Configure HTTP Request Load Balancing where you can provide the WebLogic Servers in the Server field.


And start or restart the IPlanet Proxy Server

Tuesday, September 7, 2010

SOAP over JMS with Oracle Service Bus 11g

In a previous blog I already showed you how you can do SOAP over JMS with a JAX-RPC Web Service. In this blogpost I will use OSB 11g ( Also works in 10.3 ). The OSB Proxy Services is also based on the JAX-RPC framework, so it works almost the same as a normal Java JAX-RPC Service.

You need to start with a new Proxy Service based on a WSDL

Choose for JMS. OSB will generates a default Endpoint Uri. You need to remember the QueueName of this Endpoint uri, you will use this in your Java proxy client.
OSB automatically creates a new Queue with this name when it does not already exists.

In the JMS Transport tab you need to select Is Response Required and JMSMessageID as Response Pattern.

In the Message Flow Tab I will use a simple File Busines Service and in the Response Action an Assign to set the WSDL response in the body variable.
In the Response Action you need add a Transport Header.

In the Transport Header you need to add the _wls_mimehdrContent_Type Header with as value 'text/xml; charset=utf-8' and use Inbound Response as Direction.
If you don't set this Transport Header you can get a content type null error on the JAX-RPC Client side
Deploy this project to the OSB Server.

Now you can download the WSDL of the Proxy Service in the SB Console, you need this to generate the JAX-RPC Client.

extract this jar and optional you can change the Endpoint to this Uri jms://servername:7001?URI=JMSProxyServiceRequest . Change the servername, the port number and change the Queue name.  That's enough to find the Queue.

The last step is to generate a Java Web Service Proxy client. Please read this blogpost how to generate a client.
This is the ANT Target I used to generate the client classes based on the WSDL
<target name="clientOSB">
  <clientgen wsdl="file:/c:/temp/jms/HelloworldNormal.wsdl"
             destdir="src" 
             packagename="nl.whitehorses.clientosb.jms"
             type="JAXRPC"/>
  <javac srcdir="src" 
         destdir="classes"
         includes="nl/whitehorses/clientosb/jms/**/*.java"/>
 </target>

And the java test client. If you change the WSDL Endpoint you don't need to set JmsTransportInfo
package nl.whitehorses.clientosb.jms;

import java.net.URISyntaxException;

import java.rmi.RemoteException;

import javax.xml.rpc.ServiceException;
import javax.xml.rpc.Stub;

import weblogic.wsee.connection.transport.jms.JmsTransportInfo;

public class TestService {

    public TestService() {
    }


    public static void main(String[] args) {

        try {
            HelloWorldServiceSoapHttpPortBindingQSService hello = new HelloWorldServiceSoapHttpPortBindingQSService_Impl();
            HelloWorldService port = hello.getHelloWorldServiceSoapHttpPortBindingQSPort();

            String uri = "jms://laptopedwin:7001?URI=JMSProxyServiceRequest";  
            JmsTransportInfo ti =  new JmsTransportInfo(uri);  
            ((Stub)port)._setProperty("weblogic.wsee.connection.transportinfo", ti);  
           
            System.out.println(port.sayHello());

        } catch (ServiceException e) {
            e.printStackTrace();
        } catch (RemoteException e) {
            e.printStackTrace();
        } catch (URISyntaxException e) {
            e.printStackTrace();
        }
    }

}
Here you can download the OSB workspace.

Saturday, August 21, 2010

The things you need to do for OWSM 11g policies

In Fusion Middleware 11g it is not so difficult to protect your JAX-WS Web services or your Composite Services. You just need to add an Oracle Web Service Manager service policy to this Web Service. So that's all the work for the developer or release manager. And now the work starts for the Administrator. This persons need to be familiar with the Enterprise Manager, WebLogic Console, OpenSLL and with the keytool utility of the JDK. In this blogpost I will show what you need to do if you choose for a particular OWSM Policy.


Let's start simple with one of the following policies
oracle/wss_http_token_service_policy
oracle/wss_username_token_service_policy

These policies can be used for HTTP Basic Authentication or for an Username Token in a SOAP message. The only thing you need to do for these policies is to add some Users to the myrealm Security Realm in the WebLogic Console.
On the client side you need to do the following.
execute = new Execute();
SecurityPolicyFeature[] securityFeatures =
            new SecurityPolicyFeature[] { new SecurityPolicyFeature("oracle/wss_username_token_client_policy") };
Request_Response_ptt request_Response_ptt = execute.getRequest_Response_pt(securityFeatures);
    
// Add your code to call the desired methods.
Map<String, Object> reqContext = ((BindingProvider) request_Response_ptt).getRequestContext();
reqContext.put(BindingProvider.USERNAME_PROPERTY, "test" );
reqContext.put(BindingProvider.PASSWORD_PROPERTY, "weblogic1" );
       
Request req = new Request();
req.setName("edwin");
req.setMessage("hi");
Response resp = request_Response_ptt.requestResponse(req);


The Message protection policies
oracle/wss10_message_protection_service_policy
oracle/wss11_message_protection_service_policy
When you choose for one of these policies you need to generate a Server certificate for encryption and put this in a Java keystore and for the Client side you also need to make a Keystore but this contains only the public key of this Server encryption certificate ( this is in case of the wss11, for the wss10 you also need to generate a client certificate besides the public key of server, see the x509_token_with_message_protection policies how to do this. ).

To add your Server keystore to FMW, you need to go to the Enterprise Manager and select your Weblogic Domain. In the menu go to the Security / Security Provider Configuration page. And on this page you can import your Java keystore. Before you start you need to copy your keystore to your domain folder and put this in the config/fmwconfig folder.

In this example I used two certificates one for the signature and one for the encryption. For the wss11 Message protection Service policies you only need the encryption certificate.
On the client side you need to load the client keystore and the public key of server encryption certificate. 
execute = new Execute();
SecurityPolicyFeature[] securityFeatures =
    new SecurityPolicyFeature[] { new SecurityPolicyFeature("oracle/wss11_message_protection_client_policy") };
Request_Response_ptt request_Response_ptt = execute.getRequest_Response_pt(securityFeatures);
// Add your code to call the desired methods.
Map<String, Object> reqContext = ((BindingProvider) request_Response_ptt).getRequestContext();

reqContext.put(ClientConstants.WSSEC_KEYSTORE_TYPE, "JKS");
reqContext.put(ClientConstants.WSSEC_KEYSTORE_LOCATION, "C:/client_keystore.jks");
reqContext.put(ClientConstants.WSSEC_KEYSTORE_PASSWORD, "welcome");

reqContext.put(ClientConstants.WSSEC_ENC_KEY_ALIAS, "server_encr");
reqContext.put(ClientConstants.WSSEC_ENC_KEY_PASSWORD, "welcome");
reqContext.put(ClientConstants.WSSEC_RECIPIENT_KEY_ALIAS, "server_encr");

Request req = new Request();
req.setName("edwin");
req.setMessage("hi");
Response resp = request_Response_ptt.requestResponse(req);
For the wss10_message_protection_service_policy you need to do the following.
execute = new Execute();
SecurityPolicyFeature[] securityFeatures =
    new SecurityPolicyFeature[] { new SecurityPolicyFeature("oracle/wss10_message_protection_client_policy") };
Request_Response_ptt request_Response_ptt = execute.getRequest_Response_pt(securityFeatures);
// Add your code to call the desired methods.
Map<String, Object> reqContext = ((BindingProvider) request_Response_ptt).getRequestContext();

reqContext.put(ClientConstants.WSSEC_KEYSTORE_TYPE, "JKS");
reqContext.put(ClientConstants.WSSEC_KEYSTORE_LOCATION, "C:/client_keystore.jks");
reqContext.put(ClientConstants.WSSEC_KEYSTORE_PASSWORD, "welcome");

reqContext.put(ClientConstants.WSSEC_ENC_KEY_ALIAS, "client1");
reqContext.put(ClientConstants.WSSEC_ENC_KEY_PASSWORD, "welcome");
reqContext.put(ClientConstants.WSSEC_RECIPIENT_KEY_ALIAS, "server_encr");

reqContext.put(ClientConstants.WSSEC_SIG_KEY_ALIAS, "client1");  
reqContext.put(ClientConstants.WSSEC_SIG_KEY_PASSWORD, "welcome");

Request req = new Request();
req.setName("edwin");
req.setMessage("hi");
Response resp = request_Response_ptt.requestResponse(req);

The above policies can also be combined. Like in these policies.
oracle/wss10_username_token_with_message_protection_service_policy
oracle/wss11_username_token_with_message_protection_service_policy


For these policies you need to a create user in the WebLogic Console for the username token and generate a server and client keystore for the message protection part.
On the client side you need to the following.
execute = new Execute();
SecurityPolicyFeature[] securityFeatures =
    new SecurityPolicyFeature[] { new SecurityPolicyFeature("oracle/wss11_username_token_with_message_protection_client_policy") };
Request_Response_ptt request_Response_ptt = execute.getRequest_Response_pt(securityFeatures);
// Add your code to call the desired methods.
Map<String, Object> reqContext = ((BindingProvider) request_Response_ptt).getRequestContext();
reqContext.put(BindingProvider.USERNAME_PROPERTY, "test" );
reqContext.put(BindingProvider.PASSWORD_PROPERTY, "weblogic1" );

reqContext.put(ClientConstants.WSSEC_KEYSTORE_TYPE, "JKS");
reqContext.put(ClientConstants.WSSEC_KEYSTORE_LOCATION, "C:/client_keystore.jks");
reqContext.put(ClientConstants.WSSEC_KEYSTORE_PASSWORD, "welcome");

reqContext.put(ClientConstants.WSSEC_ENC_KEY_ALIAS, "server_encr");
reqContext.put(ClientConstants.WSSEC_ENC_KEY_PASSWORD, "welcome");
reqContext.put(ClientConstants.WSSEC_RECIPIENT_KEY_ALIAS, "server_encr");

Request req = new Request();
req.setName("edwin");
req.setMessage("hi");
Response resp = request_Response_ptt.requestResponse(req);
For the wss10_username_token_with_message_protection_service_policy you need to do the following. ( and a need a client certificate and the public key of the server )
execute = new Execute();
SecurityPolicyFeature[] securityFeatures =
    new SecurityPolicyFeature[] { new SecurityPolicyFeature("oracle/wss10_username_token_with_message_protection_client_policy") };
Request_Response_ptt request_Response_ptt = execute.getRequest_Response_pt(securityFeatures);
// Add your code to call the desired methods.
Map<String, Object> reqContext = ((BindingProvider) request_Response_ptt).getRequestContext();

reqContext.put(BindingProvider.USERNAME_PROPERTY, "test" );
reqContext.put(BindingProvider.PASSWORD_PROPERTY, "weblogic1" );

reqContext.put(ClientConstants.WSSEC_KEYSTORE_TYPE, "JKS");
reqContext.put(ClientConstants.WSSEC_KEYSTORE_LOCATION, "C:/client_keystore.jks");
reqContext.put(ClientConstants.WSSEC_KEYSTORE_PASSWORD, "welcome");

reqContext.put(ClientConstants.WSSEC_ENC_KEY_ALIAS, "client1");
reqContext.put(ClientConstants.WSSEC_ENC_KEY_PASSWORD, "welcome");
reqContext.put(ClientConstants.WSSEC_RECIPIENT_KEY_ALIAS, "server_encr");

reqContext.put(ClientConstants.WSSEC_SIG_KEY_ALIAS, "client1");  
reqContext.put(ClientConstants.WSSEC_SIG_KEY_PASSWORD, "welcome");

Request req = new Request();
req.setName("edwin");
req.setMessage("hi");
Response resp = request_Response_ptt.requestResponse(req);

The last part of this blogpost I will explain the following policies
oracle/wss10_x509_token_with_message_protection_service_policy
oracle/wss11_x509_token_with_message_protection_service_policy

These policies will use the client certificate for the signature and the public key of the server encryption certificate for the encryption.
So we start by making some keystores with some certificates. I don't use self signed certificates because then for every new client I need to update the server keystore and reboot the FMW server. Now I only have to import the CA public certificate in the Server keystore. This is how my Server keystore looks like

It got a private certificate for the server signature and for encryption. The CA public key is trusted.

For the client I have this keystore. ( Every customer / application can have its own client keystore )

The CA and Server encryption certificates are public certificates and are trusted.
Because the FMW Server does not know this client certificate ( it only knows the CA ) you need to add a new user in the myrealm Secuirty Realm in the WebLogic Console. The password of this user is not important, the only requirement is that the common name of this client certificate is the same as the WebLogic Username.

And as last the Client code, where we need to provide the client signature certificate details.
execute = new Execute();
SecurityPolicyFeature[] securityFeatures =
    new SecurityPolicyFeature[] { new SecurityPolicyFeature("oracle/wss11_x509_token_with_message_protection_client_policy") };
Request_Response_ptt request_Response_ptt = execute.getRequest_Response_pt(securityFeatures);
// Add your code to call the desired methods.
Map<String, Object> reqContext = ((BindingProvider) request_Response_ptt).getRequestContext();

reqContext.put(ClientConstants.WSSEC_KEYSTORE_TYPE, "JKS");
reqContext.put(ClientConstants.WSSEC_KEYSTORE_LOCATION, "C:/client_keystore.jks");
reqContext.put(ClientConstants.WSSEC_KEYSTORE_PASSWORD, "welcome");

reqContext.put(ClientConstants.WSSEC_SIG_KEY_ALIAS, "client1");
reqContext.put(ClientConstants.WSSEC_SIG_KEY_PASSWORD, "welcome");

reqContext.put(ClientConstants.WSSEC_ENC_KEY_ALIAS, "server_encr");
reqContext.put(ClientConstants.WSSEC_ENC_KEY_PASSWORD, "welcome");
reqContext.put(ClientConstants.WSSEC_RECIPIENT_KEY_ALIAS, "server_encr");

Request req = new Request();
req.setName("edwin");
req.setMessage("hi");
Response resp = request_Response_ptt.requestResponse(req);

For OWSM SAML policies see this blogpost

For OWSM kerberos policies see this blogpost

Wednesday, August 18, 2010

HTTP Basic authentication with SOA Suite 11g

There can be situations where you need to add some security like HTTP basic authentication to your Composite Services or References. Especially when you have some HTTP Binding Services or References. The HTTP Binding Service in SOA Suite 11g also has a SOAP endpoint beside the HTTP endpoint. With the SOAP endpoint you can always use WS-Security instead of the basic authentication, but if that was the case you won't choose for the HTTP Binding.    
For this blogpost I will use my http binding example of this blogpost 
In this example I have a Mediator with a HTTP Binding Reference. This reference has as endpoint the execute url of the Execute HTTP Binding Service, which is connected to the BPEL Component.
Select the execute Service and configure SOA WS Policies, Here you need to select the oracle/wss_http_token_service_policy . This OWSM policy enables HTTP Basic authentication for HTTP  & SOAP or WSS Username Token in SOAP.

For the Composite Reference you need to use the oracle/wss_http_token_client_policy.

Off course you need to provide the username / password for the basic authentication.  To do this you need to go to the Enterprise Manager Application and select your WebLogic Domain. In the Menu, select the Security menu Item and then go to Credentials.

When you don't have the oracle.wsm.security Map then you need to create this. In the Map you need to add the basic credentials Key where you can provide the username / password for the HTTP Binding Service and Reference.
After rebooting the SOA Server you can test this HTTP Binding Service. I use Wfetch of Microsoft. The internal tester client of WebLogic and Enterprise is not so great with HTTP posts and security.

First test is a POST on the HTTP endpoint with a bad username.  This gives a HTTP 403 Forbidden.
Now with a good username / password and for the POST I only have to provide the request in the body and without the SOAP envelop.

The HTTP Binding service also has a SOAP Endpoint. First we test this with a bad username.


Now with a good username / password. For the SOAP post you need to provide the Content-Type and SOAPAction HTTP Headers and the SOAP envelope with the request.

That's all.

Update by Maarten van Luijtelaar
You can have more than one account on the reference level by overriding the oracle/wss_http_token_client_policy properties. By default the value of csf-key is set to basic.credentials, but you can create a new key in EM and use that as an override.
Also, when not using the policy, adding the properties oracle.webservices.auth.username and oracle.webservices.auth.password with corresponding values will do the trick on external references.

Wednesday, August 4, 2010

WLST Scripting with Oracle Enterprise Pack for Eclipse (OEPE)

With the new OEPE 11.1.1.6 you can create and run all your WLST scripts from Eclipse. This blogpost will give you a WLST jumpstart in the Eclipse IDE. The WLST / Phyton support for the Eclipse IDE is one of the many new OEPE features. For more info read the Markus Eisele great blogpost about all the new and cool features of OEPE.

Let's do some WLST scripting. Before you can start you need to download and install WebLogic. Off course you also need to download OEPE 11.1.1.6

Start Eclipse and provide the workspace folder. 

Click on Workbench
You need to create a new Project where WebLogic can be targeted. Choose for example Dynamic Web Project. ( You don't need to create a Web Application for WLST scripting )
Provide the name of the Project and click on New Runtime.

Open the Bea or Oracle Node and select a WebLogic release. The latest WLS release is 11gR1 PatchSet 2
Browse to the WebLogic Home this is the wlserver_10.3 folder in the FMW Home.
Click on Finish.
Select your just created web project and open the project options. Go to the Project Facets and enable the Oracle WebLogic Scripting Tools support.
This enables the WLST scripting for this project.

Select the wlst folder and create a new WLST Script.
Choose for a default template or make a empty wlst file. In this case we will use "Create Basic WebLogic Domain"
This will always create a file called newWlst.py in the wlst folder.
Change the domain folder in /user_project/domains/...
Rename this wlst file else it will be overwritten by a other WLST script creation.
Select your Domain script and in Run As, choose for WLST Run.
This will create the WebLogic Domain.
Next step is to start this WebLogic Domain. Select New and go to the Server node and click on Next.
Choose for Oracle WebLogic Server 11gR1 PatchSet 2 in the Oracle node.
Browse to the new WLS Domain folder.
In the server window you can start this WebLogic server.
After the WebLogic is started, you can open the MBean Browser. Go to the Window Menu , Show View and choose Other.
Select WebLogic MBean Explorer in the WebLogic node.
This will give you an overview of all the MBeans. You can drag and drop a MBean to your WLST script.
To this WLS Domain we can add some JMS messaging by creating a new WLST Script.
Select the "Configure JMS System Resource" Template.
Rename this script.
And when you run this script you will see the output in the console window.
That's all for the jumpstart.