Pages

Monday, April 27, 2009

Using the WebLogic deployment plan to change your ear / war for production

With Weblogic you can use a deployment plan to change your environment settings so it works in your production environment. For example if you put your WSDL url of your web service proxy clients as a context parameter in the web.xml then you can change this by using a deployment plan. This plan is a xml file and can be easily changed. You can apply this plan even after deployment.
First let's take a look at the wsdl url parameter in the web.xml, The deployment plan will change this context parameter

<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5" xmlns="http://java.sun.com/xml/ns/javaee">
<description>Empty web.xml file for Web Application</description>
<context-param>
<param-name>wsdlUrl</param-name>
<param-value>http://localhost:7001/ws_helloworld/HelloWorldServicePort?WSDL</param-value>
</context-param>


To make this work, we need to generate a deployment plan. We will use your application ear or war file as input for this plan. This is the bat file I used for this.

set BEA_HOME=C:\oracle\MiddlewareJdev11g
call %BEA_HOME%\wlserver_10.3\server\bin\setWLSEnv.cmd
set PATH=%BEA_HOME%\jdk160_05\bin
set planname=HelloWorld.xml
set earfile=C:\projecten\workspace\11g_prod\ws_helloworld\webapp\deploy\helloworld.ear
java weblogic.PlanGenerator -all -plan %planname% %earfile%

This will generate a xml file. Change the deployment xml and add a new variable with the right url

<deployment-plan xmlns="http://www.bea.com/ns/weblogic/deployment-plan" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.bea.com/ns/weblogic/deployment-plan http://www.bea.com/ns/weblogic/deployment-plan/1.0/deployment-plan.xsd" global-variables="false">
<application-name>helloworld.ear</application-name>
<variable-definition>
<!-- add the wsdl var -->
<variable>
<name>wsdlUrl</name>
<value>http://localhost:7101/ws_helloworld/HelloWorldServicePort?WSDL</value>
</variable>

Now we can change the web.xml part where we use xpath to find the context parameter and replace the value with the just created variable

<module-descriptor external="false">
<root-element>web-app</root-element>
<uri>WEB-INF/web.xml</uri>

<!-- replace the wsdl url with the deployment url -->
<variable-assignment>
<name>wsdlUrl</name>
<xpath>/web-app/context-param/[param-name="wsdlUrl"]/param-value</xpath>
<operation>replace</operation>
</variable-assignment>
</module-descriptor>
</module-override>
<config-root>C:\DOCUME~1\ebiemond\LOCALS~1\Temp\ebiemond\.\config\deployments\ear.ear\plan</config-root>
</deployment-plan>

The plan is finished and we can use this plan with the deployment. You can apply this plan on an ear in the WLS console or you can use this bat file.

set BEA_HOME=C:\oracle\MiddlewareJdev11g
call %BEA_HOME%\wlserver_10.3\server\bin\setWLSEnv.cmd
set PATH=%BEA_HOME%\jdk160_05\bin
set planname=HelloWorld.xml
set earfile=C:\projecten\workspace\11g_prod\ws_helloworld\webapp\deploy\helloworld.ear
java weblogic.Deployer -adminurl http://localhost:7101 -user weblogic -password weblogic -deploy -name HelloWorld -source %earfile% -targets DefaultServer -stage -plan %planname%

Thursday, April 23, 2009

JAX-WS web service proxy client and HTTP authentication

In a project I need to set the HTTP authentication on a JAX-WS proxy client. So let's do it. We only have to set the username and password on the bindingprovider.

@WebServiceRef()
private static TEST_ORDER_INTERACTION tEST_ORDER_INTERACTION;

public static void main(String [] args) throws MalformedURLException {
tEST_ORDER_INTERACTION = new TEST_ORDER_INTERACTION();

Test_order_interactionPortType port = tEST_ORDER_INTERACTION.getTest_order_interactionPort();
((BindingProvider) test_order_interactionPortType).getRequestContext().put(BindingProvider.USERNAME_PROPERTY,"ac-erpweb01\\oracle");
((BindingProvider) test_order_interactionPortType).getRequestContext().put(BindingProvider.PASSWORD_PROPERTY,"test");


Too bad this was not working for me. The Web Service, I called uses NTLM authentication ( Microsoft ). So we need to use our own Authenticator. Just create an Authenticator case.

package test.client;

import java.net.Authenticator;
import java.net.PasswordAuthentication;

public class MyAuthenticator extends Authenticator {

private String user;
private String password;

public MyAuthenticator(String user,String password) {
this.user = user;
this.password = password;
}


@Override
protected PasswordAuthentication getPasswordAuthentication() {
PasswordAuthentication auth = new PasswordAuthentication(user,password.toCharArray());
return auth;
}
}

Use this authenticator

@WebServiceRef()
private static TEST_ORDER_INTERACTION tEST_ORDER_INTERACTION;

public static void main(String [] args) throws MalformedURLException {
tEST_ORDER_INTERACTION = new TEST_ORDER_INTERACTION();

Test_order_interactionPortType port = tEST_ORDER_INTERACTION.getTest_order_interactionPort();

MyAuthenticator myAuth = new MyAuthenticator("ac-erpweb01\\oracle","test");
Authenticator.setDefault(myAuth);

Now we have set the HTTP authentication, we can not use the HTTP analyzer of JDeveloper anymore to see the soap messages. To see the soap request and response we can set a JAX-WS parameter. -Dcom.sun.xml.ws.transport.http.client.HttpTransportPipe.dump=true ,this will dump the data in your console output.

Tuesday, April 21, 2009

Weblogic / JDeveloper Ant Tasks

Here is an example of the Ant script I use in a project. This Ant script can make a new Weblogic Domain, creates an Oracle and MySQL JDBC datasource and creates a JMS server with a Connection Factory and some Queues
This Ant can also make jar files of your projects and deploy this to a WebLogic server. The only thing to do is to make an war of the viewcontroller project

the first part of ant build xml, this part configures the weblogic server
<?xml version="1.0" encoding="windows-1252" ?>
<project name="ant" default="connect-wls" basedir=".">

<property file="build.properties"/>
<property environment="env"/>


<taskdef name="wlserver" classname="weblogic.ant.taskdefs.management.WLServer"/>
<taskdef name="wlconfig" classname="weblogic.ant.taskdefs.management.WLConfig"/>
<taskdef name="wldeploy" classname="weblogic.ant.taskdefs.management.WLDeploy"/>
<taskdef resource="net/sf/antcontrib/antlib.xml">
<classpath>
<pathelement location="${ant.lib.folder}/lib/ant-contrib.jar"/>
</classpath>
</taskdef>


<target name="new-domain">
<mkdir dir="${bea.home}/${project.folder}"/>
<mkdir dir="${bea.home}/${project.folder}/${domain.folder}"/>
<delete dir="${domain.home}/${domain.name}"/>
<mkdir dir="${domain.home}/${domain.name}"/>
<wlserver dir="${domain.home}/${domain.name}" host="${host}" port="${port}"
domainname="${domain.name}" servername="${admin.server}"
generateconfig="true" username="${username}" password="${password}"
action="start"  beahome="${bea.home}"  weblogichome="${weblogic.home}" verbose="true" noexit="false">
<jvmarg value="-XX:MaxPermSize=192m"/>
</wlserver>
</target>

<target name="start-wls" >
<wlserver dir="${domain.home}/${domain.name}" host="${host}" port="${port}" 
domainname="${domain.name}" servername="${admin.server}"
action="start" username="${username}" password="${password}"  beahome="${bea.home}" weblogichome="${weblogic.home}" noexit="true"/>
</target>

<target name="stop-wls">
<wlserver dir="${domain.home}/${domain.name}" host="${host}" port="${port}" servername="${admin.server}"
username="${username}" password="${password}" action="shutdown" beahome="${bea.home}" weblogichome="${weblogic.home}" forceshutdown="true"/>
</target>



<target name="initDomain" depends="initJDBC,initJMS"/>


<target name="initJDBC" depends="deleteJDBC">
<wlconfig url="t3://${host}:${port}" username="${username}" password="${password}">
<query domain="${domain.name}" type="Server" name="${target.server}" property="adminServerProp"/>
<create type="JDBCConnectionPool" name="jdbc/scottDS" property="scottPoolProp">
<set attribute="DriverName" value="oracle.jdbc.OracleDriver"/>
<set attribute="Password" value="tiger"/>
<set attribute="Properties" value="user=scott"/>
<set attribute="URL" value="jdbc:oracle:thin:@localhost:1521:orcl"/>
<set attribute="TestTableName" value="SQL SELECT 1 FROM DUAL"/> 
<set attribute="TestConnectionsOnRelease" value="true"/>
<set attribute="TestConnectionsOnReserve" value="true"/>
<set attribute="Targets" value="${adminServerProp}"/>
</create>
<create type="JDBCConnectionPool" name="jdbc/mhsDS" property="mhsPoolProp">
<set attribute="DriverName" value="com.mysql.jdbc.Driver"/>
<set attribute="Password" value="mhs"/>
<set attribute="Properties" value="user=mhs"/>
<set attribute="URL" value="jdbc:mysql://localhost:3306/mhs"/>
<set attribute="TestTableName" value="SQL SHOW TABLES"/> 
<set attribute="TestConnectionsOnRelease" value="true"/>
<set attribute="TestConnectionsOnReserve" value="true"/>
<set attribute="Targets" value="${adminServerProp}"/>
</create>

</wlconfig>
</target>

<target name="deleteJDBC">
<wlconfig url="t3://${host}:${port}" username="${username}" password="${password}">
<query domain="${domain.name}" type="JDBCConnectionPool" name="jdbc/mhsDS" property="jdbcMhsDSServerProp"/>
<delete mbean="${jdbcMhsDSServerProp}"/>
<query domain="${domain.name}" type="JDBCConnectionPool" name="jdbc/scottDS" property="jdbcscottDSServerProp"/>
<delete mbean="${jdbcscottDSServerProp}"/>
</wlconfig>
</target>

<target name="initJMS" depends="deleteJMS">
<wlconfig url="t3://${host}:${port}" username="${username}" password="${password}">
<query domain="${domain.name}" type="Server" name="${target.server}" property="adminServerProp"/>
<create type="JMSFileStore" name="JmsFileStore" property="fileStore">
</create>
<create type="JMSServer" name="mhsJmsServer">
<set attribute="Store" value="${fileStore}"/>
<set attribute="Targets" value="${adminServerProp}"/>
<create type="JMSQueue" name="esb">
<set attribute="JNDIName" value="jms/esb"/>
</create>
<create type="JMSQueue" name="pop3">
<set attribute="JNDIName" value="jms/pop3"/>
</create>
<create type="JMSQueue" name="smtp">
<set attribute="JNDIName" value="jms/smtp"/>
</create>
<create type="JMSQueue" name="edine">
<set attribute="JNDIName" value="jms/edine"/>
</create>

</create>
<create type="JMSModule" name="mhsJmsModule">
</create>

<query domain="${domain.name}" type="JMSServer" name="mhsJmsServer" property="jmsServerProp"/>
<create type="JMSConnectionFactory" name="mhsCF">
<set attribute="Targets" value="${jmsServerProp}"/>
<set attribute="JNDIName" value="jms/mhsCF"/>
</create>

</wlconfig>
</target>

<target name="deleteJMS">
<wlconfig url="t3://${host}:${port}" username="${username}" password="${password}"  failonerror="false">
<query domain="${domain.name}" type="JMSConnectionFactory" name="mhsCF" property="jmsCFServerProp"/>
<delete mbean="${jmsCFServerProp}"/>

<query domain="${domain.name}" type="JMSQueue" name="esb" property="jmsESBQueueServerProp"/>
<delete mbean="${jmsESBQueueServerProp}"/>
<query domain="${domain.name}" type="JMSQueue" name="pop3" property="jmsESBQueueServerProp"/>
<delete mbean="${jmsESBQueueServerProp}"/>
<query domain="${domain.name}" type="JMSQueue" name="smtp" property="jmsESBQueueServerProp"/>
<delete mbean="${jmsESBQueueServerProp}"/>
<query domain="${domain.name}" type="JMSQueue" name="edine" property="jmsESBQueueServerProp"/>
<delete mbean="${jmsESBQueueServerProp}"/>

<query domain="${domain.name}" type="JMSServer" name="mhsJmsServer" property="jmsServerProp"/>
<delete mbean="${jmsServerProp}"/>
<query domain="${domain.name}" type="JMSFileStore" name="JmsFileStore" property="jmsFileStoreServerProp"/>
<delete mbean="${jmsFileStoreServerProp}"/>
</wlconfig>
</target>


The second part of the Ant script contains the deployment task
<target name="all"> 
<foreach list="${deploy.projects}" param="project" target="deploy" inheritall="true" inheritrefs="true"/>
</target> 

<target name="deployAll"> 
<foreach list="${deploy.projects}" param="project" target="deploy2" inheritall="true" inheritrefs="true"/>
</target>

<target name="deploy2">
<property file="${project}.properties"/>
<property file="project.properties"/>
<echo message="${project.home}"/>
<echo message="Start undeploying application..."/>

<if> 
<equals arg1="${project.ear}" arg2="true"/>
<then>
<wldeploy action="undeploy" verbose="true" debug="true" name="${project}"  adminurl="t3://${host}:${port}" 
user="${username}" password="${password}" targets="${target.server}" failonerror="false"/> 

<echo message="Start deploying application..."/>

<wldeploy action="deploy" verbose="true" debug="true" name="${project}"  adminurl="t3://${host}:${port}" 
user="${username}" password="${password}" targets="${target.server}" failonerror="false" 
source="${project.home}/${general.project.deploy.dir}/${deploy.file}" remote="true" upload="true"/> 

</then>
</if>

</target> 

<target name="deploy" depends="clean,compile,copy,packageJar,packageInterfaceJar,packageEar"> 
<property file="${project}.properties"/>
<property file="project.properties"/>
<echo message="${project.home}"/>
<if> 
<equals arg1="${project.ear}" arg2="true"/>
<then>
<echo message="Start undeploying application..."/>

<wldeploy action="undeploy" verbose="true" debug="true" name="${project}"  adminurl="t3://${host}:${port}" 
user="${username}" password="${password}" targets="${target.server}" failonerror="false"/> 

<echo message="Start deploying application..."/>

<wldeploy action="deploy" verbose="true" debug="true" name="${project}"  adminurl="t3://${host}:${port}" 
user="${username}" password="${password}" targets="${target.server}" failonerror="false" 
source="${project.home}/${general.project.deploy.dir}/${deploy.file}" remote="true" upload="true"/> 

</then>
</if>

</target> 

<target name="clean">
<property file="${project}.properties"/>
<property file="project.properties"/>

<echo message="${project.home} ${project.bin.dir}"/>
<property file="${project}.properties"/>
<delete includeemptydirs="true" quiet="true">
<fileset dir="${project.bin.dir}" includes="**/*"/>
</delete>
<delete includeemptydirs="true" quiet="true">
<fileset dir="${project.home.deploy}" includes="**/*"/>
</delete>
</target>


<target name="compile">
<property file="${project}.properties"/>
<property file="project.properties"/>

<echo message="java home ${env.JAVA_HOME}"/>
<echo message="${project.home} ${project.src.dir} ${project.bin.dir}"/>
<echo message="classpath ${project.classpath}"/>
<mkdir dir="${project.bin.dir}"/>
<javac destdir="${project.bin.dir}" classpath="${project.classpath}" deprecation="off" encoding="Cp1252" source="1.6" target="1.6" fork="yes">
<src path="${project.src.dir}"/>
</javac>
</target>

<target name="copy">
<property file="${project}.properties"/>
<property file="project.properties"/>

<patternset id="copy.patterns">
<include name="**/*.gif"/>
<include name="**/*.jpg"/>
<include name="**/*.jpeg"/>
<include name="**/*.png"/>
<include name="**/*.properties"/>
<include name="**/*.xml"/>
<include name="**/*-apf.xml"/>
<include name="**/*.ejx"/>
<include name="**/*.xcfg"/>
<include name="**/*.cpx"/>
<include name="**/*.dcx"/>
<include name="**/*.wsdl"/>
<include name="**/*.ini"/>
<include name="**/*.tld"/>
<include name="**/*.tag"/>
<include name="**/*.template"/>
<include name="**/*.xlf"/>
<include name="**/*.xsl"/>
<include name="**/*.xsd"/>
<exclude name="**/application.xml"/>
<exclude name="**/weblogic-application.xml"/>
<exclude name="**/weblogic-ejb.xml"/>
<exclude name="**/weblogic-web.xml"/>
</patternset>

<copy todir="${project.bin.dir}">
<fileset dir="${project.src.dir}">
<patternset refid="copy.patterns"/>
</fileset>
</copy>

</target>

<target name="packageJar">
<jar destfile="${project.home.deploy}/${project}.jar" basedir="${project.bin.dir}" compress="false"/>
</target>


<target name="packageInterfaceJar">
<if> 
<equals arg1="${project.interfacejar}" arg2="true"/>
<then>
<jar destfile="${project.home.deploy}/${project}_Interface.jar" compress="true"> 
<fileset dir="${project.bin.dir}" excludes="**/*Bean.class,**/weblogic-application.xml,**/persistence.xml,**/ejb-jar.xml"/>
</jar>
</then>
</if>



</target>

<target name="packageEar">

<if> 
<equals arg1="${project.ear}" arg2="true"/>
<then>
<copy todir="${project.home.deploy}/META-INF">
<fileset dir="${project.src.dir}/META-INF" excludes="**/.svn"/>
</copy> 
<ear  destfile="${project.home.deploy}/${deploy.file}" appxml="${project.build.dir}/META-INF/application.xml" compress="false">
<fileset dir="${project.home.deploy}"  includes="*.jar, *.war, META-INF/weblogic-application.xml" excludes="*_Interface.jar"/>
</ear> 
<delete dir="${project.home.deploy}/META-INF"/>
</then>
</if>
</target>
</project>


Here is the build.properties

# connection info to the wls admin server
host=127.0.0.1
port=7001
username=weblogic
password=weblogic

# jdev home for the needed libraries to compile projects
jdeveloper.home=C:/oracle/MiddlewareJdev11g/jdeveloper/

# wls 10.3 instance installation
bea.home=C:/oracle/bea
weblogic.home=${bea.home}/wlserver_10.3/server
ant.lib.folder=${bea.home}/modules/net.sf.antcontrib_1.0.0.0_1-0b2
wls.lib.folder=${weblogic.home}/lib
jdev.lib.modules=${bea.home}/jdeveloper/modules
wls.lib.modules=${bea.home}/modules

# project folder in wls
project.folder=user_projects
# domain folder in wls under wls project folder
domain.folder=domains
# wls admin server name
admin.server=admin
# total domain path
domain.home=${bea.home}/${project.folder}/${domain.folder}
# wls domain name
domain.name=development

# wls deploy server name
target.server=admin

deploy.projects=General,Model,RunServices,CacheServices,ServerServices,Server

general.project.src.dir=src
general.project.src.adf.dir=adfmsrc
general.project.deploy.dir=deploy
general.project.bin.dir=classes
general.project.build.dir=build

project.base=C:/projecten/mhs11g/trunk
project.lib=${project.base}/Libraries

The general project.properties file.

project.home=${project.base}/${project}
project.home.deploy=${project.home}/${general.project.deploy.dir}
project.src.dir=${project.home}/${general.project.src.dir}
project.build.dir=${project.home}/${general.project.build.dir}
project.build.home=C:/projecten/mhs11g/derived/${project}
project.bin.dir=${project.build.home}/${general.project.bin.dir}

For every project in the deploy.projects variable in the build.properties we need to create a project specific property file.
Here is a example of a EJB model project

project=RunServices
project.ear=true
project.interfacejar=true
deploy.file=mhs_runServices.ear
project.classpath=${jdev.lib.modules}/oracle.toplink_11.1.1/*.jar

Now we only have to start ant in a cmd box and do your thing

set BEA_HOME=C:\oracle\bea
call %BEA_HOME%\wlserver_10.3\server\bin\setWLSEnv.cmd
set PATH=%BEA_HOME%\modules\org.apache.ant_1.6.5\bin

ant xxxx

Here you can download the scripts

Here is total new version
<?xml version="1.0" encoding="iso-8859-1"?>
<project name="datasource" default="JDBC">

  <target name="JDBC">
    <wlCreateDatasource datasource="scottDS" 
                        jdbcurl="jdbc:oracle:thin:@localhost:1521:orcl" 
                        user="scott" 
                        password="tiger" 
                        target="AdminServer"
                        adminUser="weblogic"
                        adminPassword="weblogic1"
                        adminUrl="t3://localhost:7001"/>

    <wlRemoveDatasource datasource="scottDS" 
                        adminUser="weblogic"
                        adminPassword="weblogic1"
                        adminUrl="t3://localhost:7001"/>
  </target>

 <macrodef name="wlRemoveDatasource">
  <attribute name="datasource"/>
  <attribute name="adminUser"/>
  <attribute name="adminPassword"/>
  <attribute name="adminUrl"/>
  <sequential>
    <wlst failonerror="true" debug="false" arguments="@{datasource} @{adminUser} @{adminPassword} @{adminUrl}">
      <script>
     datasource=sys.argv[0]
     adminUser=sys.argv[1]
     adminPassword=sys.argv[2]
     adminUrl=sys.argv[3]
     
     connect(adminUser,adminPassword,adminUrl)
   
     edit()
     startEdit()
     
     cd('/')
     cmo.destroyJDBCSystemResource(getMBean('/SystemResources/'+datasource))

     save()
     activate()
     cd('/')
      </script>
    </wlst>
  </sequential>
 </macrodef>

 <macrodef name="wlCreateDatasource">
  <attribute name="datasource"/>
  <attribute name="jdbcurl"/>
  <attribute name="user"/>
  <attribute name="password"/>
  <attribute name="target"/>
  <attribute name="adminUser"/>
  <attribute name="adminPassword"/>
  <attribute name="adminUrl"/>
  <sequential>
    <wlst failonerror="true" debug="false" arguments="@{datasource} @{jdbcurl} @{user} @{password} @{target} @{adminUser} @{adminPassword} @{adminUrl}">
      <script>
     datasource=sys.argv[0]
     jdbcurl=sys.argv[1]
     user=sys.argv[2] 
     password=sys.argv[3]
     target=sys.argv[4]
     
     adminUser=sys.argv[5]
     adminPassword=sys.argv[6]
     adminUrl=sys.argv[7]
     
     connect(adminUser,adminPassword,adminUrl)
     
     edit()
     startEdit()
     
     cd('/')
     cmo.createJDBCSystemResource(datasource)
     
     cd('/JDBCSystemResources/'+datasource+'/JDBCResource/'+datasource)
     cmo.setName(datasource)
     
     cd('/JDBCSystemResources/'+datasource+'/JDBCResource/'+datasource+'/JDBCDataSourceParams/'+datasource)
     set('JNDINames',jarray.array([String('jdbc/'+datasource)], String))
     
     cd('/JDBCSystemResources/'+datasource+'/JDBCResource/'+datasource+'/JDBCDriverParams/'+datasource)
     cmo.setUrl(jdbcurl)
     cmo.setDriverName('oracle.jdbc.xa.client.OracleXADataSource')
     cmo.setPassword(password)
     
     cd('/JDBCSystemResources/'+datasource+'/JDBCResource/'+datasource+'/JDBCConnectionPoolParams/'+datasource)
     cmo.setTestTableName('SQL SELECT 1 FROM DUAL\r\n\r\n\r\n\r\n')
     
     cd('/JDBCSystemResources/'+datasource+'/JDBCResource/'+datasource+'/JDBCDriverParams/'+datasource+'/Properties/'+datasource)
     cmo.createProperty('user')
     cd('/JDBCSystemResources/'+datasource+'/JDBCResource/'+datasource+'/JDBCDriverParams/'+datasource+'/Properties/'+datasource+'/Properties/user')
     cmo.setValue(user)
     
     cd('/JDBCSystemResources/'+datasource+'/JDBCResource/'+datasource+'/JDBCDataSourceParams/'+datasource)
     cmo.setGlobalTransactionsProtocol('TwoPhaseCommit')
     
     cd('/SystemResources/'+datasource)
     set('Targets',jarray.array([ObjectName('com.bea:Name='+target+',Type=Server')], ObjectName))     

     save()
     activate()
     cd('/')
      </script>
    </wlst>
  </sequential>
 </macrodef>

</project>

Saturday, April 11, 2009

Changing WSDL url ( endpoint) in JAX-WS client

In JDeveloper 11G you can easily generate a JAX-WS client, just create a new Web Service proxy client and use the WSDL Url. This client works perfectly in your test environment but when you want to deploy this to an other environment then you will get IO errors. This is because JDeveloper generates JAX-WS client code with a WSDL Url.Off course you can change this file with the new WSDL Url but you can also change the endpoint url. IMPORTANT this only works when the original WSDL Url is still accessible. So don't use this.

@WebServiceRef
private static HelloWorldService helloWorldService;

public static void main(String [] args)
{
String newAddress = System.getProperty("wsdlurl");
helloWorldService = new HelloWorldService();
HelloWorld helloWorld = helloWorldService.getHelloWorldPort();
System.out.println("old address "+((BindingProvider)helloWorld).getRequestContext().get(BindingProvider.ENDPOINT_ADDRESS_PROPERTY));
((BindingProvider)helloWorld).getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY , newAddress);

System.out.println(helloWorld.sayHello());


The other and better way is to use the other proxy client constructor and provide the new WDSL url.

@WebServiceRef
private static HelloWorldService helloWorldService;

public static void main(String [] args)
{
String newAddress = System.getProperty("wsdlurl");
try {
helloWorldService = new HelloWorldService( new URL(newAddress)
, new QName("http://ws.whitehorses.nl/", "HelloWorldService"));
} catch (MalformedURLException e) {
e.printStackTrace();
}
HelloWorld helloWorld = helloWorldService.getHelloWorldPort();
System.out.println(helloWorld.sayHello());
}

The last way ( if you use the jax-ws-client in a web application) is to add a jax-ws-catalog.xml file to the ear deployment of your web application, this will replace the WSDL url at runtime.
the file looks like this. See Gerard Devision blog for more information.

<?xml version="1.0" encoding="ISO-8859-1" ?>
<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog" prefer="system">
<system systemId="http://localhost:7101/ws_helloworld-Project1-context-root/HelloWorldServicePort?wsdl"
uri="http://localhost:7001/ws_helloworld/HelloWorldServicePort?WSDL"/>
</catalog>

Monday, April 6, 2009

Create a 11G EJB Project with EclipseLink

In JDeveloper 11G you can off course create an ADF BC model project for your ADF Webapp but why don't you use an EJB model project with EclipseLink, it is not so difficult. For this blog entry I made a document with the screenshots of the step you need to do to make an EJB model project. After this you can read this blog how to use this in ADF.

Here are the steps I did for this model project based on the HR demo schema.
The first step is to create the EJB project and generate the entity classes.
Change the database and datasource settings in the persistence xml.

Add the relations manually between the department and employee entities.

Add the Oracle sequences definitions to the primary keys
Add a new named query to the entity

Create an session bean

And make an EJB client to test the session.
Here is the example workspace and the document with all the steps and here is the code of my test client where I create a department with two employees.

package nl.whitehorses.eclipselink.model.client;

import java.sql.Timestamp;

import java.util.Date;
import java.util.Hashtable;
import java.util.List;

import javax.naming.Context;
import javax.naming.InitialContext;

import javax.naming.NamingException;

import nl.whitehorses.eclipselink.model.entities.Departments;
import nl.whitehorses.eclipselink.model.entities.Employees;
import nl.whitehorses.eclipselink.model.services.HrSession;

public class HrSessionClient {
public static void main(String [] args) {
try {
final Context context = getInitialContext();
HrSession hrSession = (HrSession)context.lookup("Eclipselink-HrSession#nl.whitehorses.eclipselink.model.services.HrSession");


// insert new department
Departments department = new Departments();
department.setDepartmentName("Sales");
department.setLocationId(1700L);
department.setManagerId(200L);
department = (Departments)hrSession.mergeEntity(department);
System.out.println("new department id: "+department.getDepartmentId());

// add a new employee
Employees employee1 = new Employees();
employee1.setEmail("Test1@test.nl");
employee1.setLastName("Test1");
employee1.setJobId("ST_MAN");
employee1.setHireDate(new Timestamp(new Date().getTime()));

department.addEmployees(employee1);
department = (Departments)hrSession.mergeEntity(department);

// add a other new employee
Employees employee2 = new Employees();
employee2.setEmail("Test2@test.nl");
employee2.setLastName("Test2");
employee2.setJobId("ST_MAN");
employee2.setHireDate(new Timestamp(new Date().getTime()));
employee2.setDepartment(department);

department.getEmployees().add(employee2);
department = (Departments)hrSession.mergeEntity(department);

// retrieving the new department with its employees
for (Departments departments : (List<Departments>)hrSession.queryDepartmentsFindOne( department.getDepartmentId())) {
System.out.println( "departmentId = " + departments.getDepartmentId() );
System.out.println( "departmentName = " + departments.getDepartmentName() );
System.out.println( "locationId = " + departments.getLocationId() );
System.out.println( "managerId = " + departments.getManagerId() );
for (Employees employees : departments.getEmployees()) {
System.out.println( "employeeId = " + employees.getEmployeeId() );
System.out.println( "commissionPct = " + employees.getCommissionPct() );
System.out.println( "email = " + employees.getEmail() );
System.out.println( "firstName = " + employees.getFirstName() );
System.out.println( "hireDate = " + employees.getHireDate() );
}

}



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

private static Context getInitialContext() throws NamingException {
Hashtable env = new Hashtable();
// WebLogic Server 10.x connection details
env.put( Context.INITIAL_CONTEXT_FACTORY, "weblogic.jndi.WLInitialContextFactory" );
env.put(Context.PROVIDER_URL, "t3://127.0.0.1:7101");
return new InitialContext( env );
}
}

Thursday, April 2, 2009

XSD validation and exception handling in OSB

In OSB ( Oracle Service Bus , aqualogic service bus ) it is relative easy to add schema validation to your proxy service and to make a custom exception handling for this validation. Just follow the next steps. First in this example I use these xml schema's for the request and response operation.
The request xsd

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns="http://whitehorses.nl/request"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://whitehorses.nl/request"
elementFormDefault="qualified"
attributeFormDefault="unqualified">
<xs:element name="request">
<xs:complexType>
<xs:sequence>
<xs:element name="runid" type="xs:short"/>
<xs:element name="message" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>

And the response xsd

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns="http://whitehorses.nl/response"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://whitehorses.nl/response"
elementFormDefault="qualified"
attributeFormDefault="unqualified">
<xs:element name="response">
<xs:complexType>
<xs:sequence>
<xs:element name="runid" type="xs:short"/>
<xs:element name="message" type="xs:string" minOccurs="0"/>
<xs:element name="errorid" type="xs:string" minOccurs="0"/>
<xs:element name="error" type="xs:anyType" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>

When everything goes well I will only return the runid element else we get the full message with the errorcode. With these xsd's I made a simple WSDL which I can use in the proxy service.

First part of this blog entry is to make the happy flow when this works we can add the xsd validation.
Make a new proxy service and use this WSDL.
The next step is to make a simple business service with file transport

In my case I put the request xml in the c drive temp folder.

Go back to your proxy service where we create a new message flow.


Add a route-node to the flow with inside a new routing. This routing will call the file business service.

Add an assign component to request action flow so I can retrieve the runid from the request and add this to the runid variable. This variable I can use for the response.
To make a return message I add an assign to the response action. Now I add the response template xml to the body variable.

Add an insert to the response action after the assign. In this insert we will add the runid of the request to the runid of the response message.


The first part is finished, you service should work now. In the second part we will add the XSD validation.
To make a custom exception handling for the xsd we need to add a Pipeline Pair node.
In the request pipeline I will add a new stage.

In this stage I use the validation component. Now we have to select an element in the body variable which OSB will validate against the XSD. Provide the XSD and use the raise error option.

Add an error handler to this stage.

Add a new stage in the error handler

First we add an assign to the stage to retrieve the runid of the request message so I can use this for the response.

Add a second assign to the stage. In this assign I will add the response template xml to the body variable.

Add the runid to the response xml

Add the error details to the response xml

And the error code



With the reply we can give back the response xml back to the client. Very important report no error because this is a handled exception.

The second part is also finished, we only have to test this proxy service by adding a unknow element to the request and look at the response. Here is a picture of the result.