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>