Thursday, March 18, 2010

Steps to Create a Webservcie Server Using Weblogic

These steps are performed on Weblogic 9.2. The directory workshop\java\WebServices\sampleservice is user created.

1. Open a cmd window. Type C:\bea921\user_projects\domains\mydomain\bin\SetDomainEnv.cmd. This will setup the environment and change current directory to C:\bea921\user_projects\domains\mydomain
2. Change the directory to C:\workshop\java\WebServices\sampleservice, which is the working directory.
3. Make sure that the following URL works: http://localhost:7100/sampleservice/SampleServiceService?WSDL
If it does not work, the application may have been stopped. Go to C:\bea921\user_projects\domains\mydomain\bin and type startWeblogic.cmd to start the application.
4. An eclipse project called sampleservicews is already created. The two files used are SampleServiceImpl and MyDatatype in the package com.mycompany.myapp.webservice.sampleservice. Modify these two classes if needed.
5. type "ant clean". This will clean up the old folders that may be generated before and also undeploy the already deployed webservcie application running at localhost:7100. Verify this by browsing the wsdl url again. It should give error.
6. type "ant build-service".
7. type "ant deploy". This will deploy the newly created webservice.
8. Verify that the new webservice has been deployed successfully by browsing to the wsdl URL. It should show the WSDL file. A page refresh may be needed to see the new WSDL file.
9. Now the new webservice is working, we can use the weblogic tools to generate the client code.

Notes on the build.xml file.

The target <client> and <run> may not work if the related files are not implemented.

Sample build.xml

<project name="webservices-sampleservice" default="all"><!-- set global properties for this build -->
 <property name="wls.username" value="weblogic" />
 <property name="wls.password" value="weblogic" />
 <property name="wls.hostname" value="localhost" />
 <property name="wls.port" value="7100" />
 <property name="wls.server.name" value="PlayServer" />
 <property name="ear.deployed.name" value="sampleserviceServiceEar" />
 <property name="example-output" value="output" />
 <property name="ear-dir"
  value="${example-output}/sampleserviceServiceEar" />
 <property name="clientclass-dir"
  value="${example-output}/clientclass" />
 <path id="client.class.path">
  <pathelement path="${clientclass-dir}" />
  <pathelement path="${java.class.path}" />
 </path>
 <taskdef name="jwsc"
  classname="weblogic.wsee.tools.anttasks.JwscTask" />
 <taskdef name="clientgen"
  classname="weblogic.wsee.tools.anttasks.ClientGenTask" />
 <taskdef name="wldeploy"
  classname="weblogic.ant.taskdefs.management.WLDeploy" />
 <target name="all" depends="clean,build-service,deploy,client" />
 <target name="clean" depends="undeploy">
  <delete dir="${example-output}" />
 </target>
 <target name="build-service">
  <jwsc srcdir="src" destdir="${ear-dir}" keepGenerated="true">
   <jws
    file="com/mycompany/myapp/webservice/sampleservice/SampleServiceImpl.java" />
  </jwsc>
 </target>
 <target name="deploy">
  <wldeploy action="deploy" name="${ear.deployed.name}"
   source="${ear-dir}" user="${wls.username}" password="${wls.password}"
   verbose="true" adminurl="t3://${wls.hostname}:${wls.port}"
   targets="${wls.server.name}" />
 </target>
 <target name="undeploy">
  <wldeploy action="undeploy" failonerror="false"
   name="${ear.deployed.name}" user="${wls.username}"
   password="${wls.password}" verbose="true"
   adminurl="t3://${wls.hostname}:${wls.port}"
   targets="${wls.server.name}" />
 </target>
 <target name="client">
  <clientgen
   wsdl="http://${wls.hostname}:${wls.port}/sampleservice/SampleServiceService?WSDL"
   destDir="${clientclass-dir}"
   packageName="examples.webservice.sampleservice.client" />
  <javac srcdir="${clientclass-dir}" destdir="${clientclass-dir}"
   includes="**/*.java" />
  <javac srcdir="src" destdir="${clientclass-dir}"
   includes="examples/webservices/sampleservice/client/**/*.java" />
 </target>
 <target name="run">
  <java fork="true"
   classname="examples.webservices.sampleservice.client.Main"
   failonerror="true">
   <classpath refid="client.class.path" />
   <arg
    line="http://${wls.hostname}:${wls.port}/sampleservice/SampleServiceService" />
  </java>
 </target>
</project>

Sample JWS file


In this JWS file, there is only one WebMethod. Notice that it returns the user-defined data type. I found that if the method signature does not contain the user-defined data type, then the WSDL file won't define that data type. Also generics are not supported when used as a parameter or return value. For example, the following Java method cannot be exposed as a public operation:
public ArrayList<String> foo(ArrayList<String> in){ return in};
In the following example, we explicitly use the MyDataType array so the WSDL file generated will have binding information for the class MyDataType.
package com.mycompany.myapp.webservice.sampleservice;

import javax.jws.WebMethod;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;

import weblogic.jws.WLHttpTransport;

//the targetNamespace here will be used as the package name for the custom datatype MyDatatype in the weblogic 
//generated webservcie client code. Note that here the targetNamespace matches the package name of the class SampleServiceImpl. 
//But this is not necessary. In fact, if in the targetNamespace, myapp is changed to xyz, then the wsdl and the 
//webservice client code will have com.mycompany.xyz.webservice.sampleservice and the class 
//ArrayOfMyDatatype_Literal will be in that package in stead of com.mycompany.myapp.webservice.sampleservice
@WebService(serviceName = "SampleServiceService", name = "SampleServicePortType", targetNamespace = "http://sampleservice.webservice.myapp.mycompany.com")
// Standard JWS annotation that specifies this is a document-literal-wrapped Web Service
@SOAPBinding(style = SOAPBinding.Style.DOCUMENT, use = SOAPBinding.Use.LITERAL, parameterStyle = SOAPBinding.ParameterStyle.WRAPPED)
// WebLogic-specific JWS annotation that specifies the context path and service URI used to build the URI of the Web Service 
@WLHttpTransport(contextPath = "sampleservice", serviceUri = "SampleServiceService", portName = "SampleServiceServicePort")
/**
 * This JWS file forms the basis of a WebLogic Web Service. The Web Services has
 * one public operations: getMyDatasAtLocation The Web Service is defined as a
 * "document-literal" service, which means that the SOAP messages have a single
 * part referencing an XML Schema element that defines the entire body.
 * 
 * @author Copyright (c) 2005 by BEA Systems. All Rights Reserved.
 */
public class SampleServiceImpl
{
  @WebMethod()
  public MyDatatype[] getMyDatasAtLocation(Long locationSeq)
  {
    System.out.println("getMyDatasAtLocation called with the location seq "
        + locationSeq);
    MyDatatype[] myDatas = new MyDatatype[3];
    for (int i = 0; i < 3; i++)
    {
      MyDatatype myData = new MyDatatype();
      myData.setStatus("ACTIVE");
      myData.setMyDataNbr("" + locationSeq + i);
      myData.setMyDataType("SAMPLE");
      myDatas[i] = myData;
    }
    return myDatas;
  }
}

Sample User-Defined Data Type

package com.mycompany.myapp.webservice.sampleservice;

public class MyDatatype
{
  private String myDataNbr;
  private String myDataType;
  private String status;

  public String getMyDataNbr()
  {
    return myDataNbr;
  }

  public void setMyDataNbr(String myDataNbr)
  {
    this.myDataNbr = myDataNbr;
  }

  public String getMyDataType()
  {
    return myDataType;
  }

  public void setMyDataType(String myDataType)
  {
    this.myDataType = myDataType;
  }

  public String getStatus()
  {
    return status;
  }

  public void setStatus(String status)
  {
    this.status = status;
  }

  public String toString()
  {
    return "type=" + myDataType + " nbr=" + myDataNbr + " status=" + status;
  }
}

Notes

When a client application invokes a WebLogic Web Service operation, the operation invocation takes place outside the context of a transaction, by default. But you can use the @weblogic.jws.Transactional annotation in the JWS file to specify that the operation should be run inside a transaction. See http://download.oracle.com/docs/cd/E12840_01/wls/docs103/webserv_ref/annotations.html#wp1057803. However, I am not sure if this really works. The documentation of the sample MedRec application that comes with weblogic10 says contradictorily that "WebLogic Web Services do not support distributed transaction and its integration with JTA" in the chapter "Delegate Services". Maybe the best way to verify this is to do a real test.

No comments:

Post a Comment