Google Answers Logo
View Question
 
Q: Deploying a java web service using Axis (JWS is not sufficient) ( No Answer,   4 Comments )
Question  
Subject: Deploying a java web service using Axis (JWS is not sufficient)
Category: Computers > Programming
Asked by: kattanh3-ga
List Price: $35.00
Posted: 31 Mar 2006 06:53 PST
Expires: 30 Apr 2006 07:53 PDT
Question ID: 713963
Q: How can I deploy my java client class (and its dependant classes
and packages) as a webservice using Apache TomCat and Axis
******************************************************************************
What I have : I am new to webservices but I have managed to make a
class which creates multiple clients for different webservices (Google
using SOAP, and Yahoo using REST) and merge them into a common type.
******************************************************************************
What I want : is to place this code as a webservice using Axis and
Tomcat and provide a WSDL discription for it. I am not familiar with
Ant scripts, the only method which i am familiar with in order to
deploy webservices is by converting the java source code extention
from .java into .jws and then using axis
http://localhost...myClass.jws?wsdl to create the wsdl file and then
use axis again to create the stubs. Aparently this is not suitable for
my class because i have packages and i wish to return a
MetaSearchResults instance rather than basic parameters. It is my
understanding that WAR (Web Application aRchives) are more than what i
need and that WSDD (Web Service Discription Deployment) might be the
solution.

Please give me the steps for getting around this problem and a pseudo
code for how it can be done.
******************************************************************************
Answer  
There is no answer at this time.

Comments  
Subject: Re: Deploying a java web service using Axis (JWS is not sufficient)
From: ltcstyle-ga on 09 Apr 2006 15:58 PDT
 
A:

To answer your custom object input/ouput, I suggest you to design your
class follow the Java bean pattern, which means all the data member in
your class have standard pair of set/get(if you use Eclipse, click
right button on the data member, and select generate get/set
accessor). After this, you may need to map your type in WSDD.
for example:

<deployment xmlns="http://xml.apache.org/axis/wsdd/"
xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">

<beanMapping qname="ns:StartCondition" xmlns:ns="urn:Executor"
    languageSpecificType="java:soGrid.task.StartCondition"/>

</deployment>

use these codes in your WSDD file, change the
java:soGrid.task.StartCondition with your class name (NOTE: include
your package). Here, my class "StartCondition" is under soGrid.task
package.  Save the WSDD file into your axis\WEB-INF folder. Then, you
use AdminClient to deploy your WSDD file.

*How to use AdminClient*
copy these code to notepad, save it as axisAdmin.bat,


set AXIS_HOME=.
set AXIS_LIB=%AXIS_HOME%\lib
set AXISCLASSPATH=%AXIS_LIB%\axis.jar;%AXIS_LIB%\commons-discovery.jar;%AXIS_LIB%\commons-logging.jar;%AXIS_LIB%\jaxrpc.jar;%AXIS_LIB%\saaj.jar;%AXIS_LIB%\xml-apis.jar;%AXIS_LIB%\xercesImpl.jar
java -Djava.ext.dirs=lib org.apache.axis.client.AdminClient
-lhttp://localhost:8080/axis/services/AdminService deploy.wsdd
pause


And copy this axisAdmin.bat file to axis\WEB-INF, use it, then you
have deployed your WSDD.

Copy all your dependent classes and packages to axis\WEB-INF\classes
folder, if you have .jar package, copy them into axis\WEB-INF\lib
folder also works. And that's it.

I guess your problem is that you havn't use package classes in your
languageSpecificType field in WSDD file.

You are able to use JWS to get your WSDL file after you deploy WSDD
file by AdminClient.

Hope this helped. I suppose you know how to program the client to map
the type, if not or any other problems, please let me know, I will
back to you ASAP.

Cheers
Manson
Subject: Re: Deploying a java web service using Axis (JWS is not sufficient)
From: avatarng-ga on 10 Apr 2006 11:45 PDT
 
Yes WSDD is definitely the easiest way to deploy a web service.

refer this "http://ws.apache.org/wss4j/axis.html".

By Avatar Ng (a Java .net member)
http://avatar21.superihost.com/
KLJUG Blog
Subject: Re: Deploying a java web service using Axis (JWS is not sufficient)
From: avatarng-ga on 10 Apr 2006 22:01 PDT
 
This is what I got from some place, a very good article (yes it's long
and complex, but it covers everything).
(Picked from http://weblogs.asp.net/jdanforth/archive/2005/01/16/354060.aspx)

[Java] Simple WSS4J with Axis Tutorial

This is a simple tutorial for getting started with WSS4J. It's based
on a tutorial posted on the WSS4J mailing list by Rami Jaamour, but
I've added a few clarifications and variants of the code samples. Rami
should get all credits for this tutorial; I'm just a newbie trying to
learn how to use this tool!

Updates

2006-03-29 - If you get an exception like this one below, it is
recommended to look at which Axis version your are using and consider
Axis version 1.2:

Exception in thread "main" java.lang.IllegalAccessError: tried to
access method org.apache.axis.SOAPPart.setCurrentMessage(Ljava/lang/Object;I)V
from class org.apache.ws.axis.security.WSDoAllSender
at org.apache.ws.axis.security.WSDoAllSender.invoke(WSDoAllSender.java:365)
at org.apache.axis.strategies.InvocationStrategy.visit(InvocationStrategy.java:71)

2005-01-29 - This "article" has been updated a couple of times now.
Both with information regarding the xalan.jar problems, and how to set
the UserName Token dynamically.

Credits

As I wrote above, all cred should go to Rami Jaamour because most of
the stuff below is written by him. My thanks to the nice guys in the
WSS4J mailing list - Ashok Shah, Werner Dittmann, Yves Langisch and
others.

The Future

I've added a few things myself to this tutorial, and I'll keep adding
things as I learn more. I'll also connect this tutorial with a
Username Token service written in ASP.NET as soon as possible. After
that we'll see what happens. I'd like to encrypt and sign the stuff
too in the future...

Introduction

WSS4J can be used for securing web services deployed in virtually any
application server, but it includes special support for Axis. WSS4J
ships with handlers that can be used in Axis-based web services for an
easy integration. These handlers can be added to the service
deployment descriptor (wsdd file) to add a WS-Security layer to the
web service. This is a step by step tutorial for deploying a simple
service with Username Token.

Prereqs

To run this tutorial, you must install a JDK (of course). I suggest
JDK 1.4.2_04 or 1.5.0. Then you need an application server. I've
personally used version jakarta-tomcat-4.1.31. Then you need to
download and install Axis (version 1.2) and WSS4J. Getting hold of
WSS4J and the other jars you may need can be quite tricky. One way is
to download Maven and checkout and build WSS4J through it. That's what
I did (not without problems though).

If you have problems getting the needed jar files let me know and I'll
try to add them to this space for download. I've compiled the
wss4j.jar package and made it available for download here.

You don't really need a Java code editor, but it helps. Personally I
use Eclipse and Lomboz (a J2EE plug-in for Eclipse).

Installing WSS4J

   1. Download the WSS4J binaries or build it from sources
   2. Copy the contents (the jar files) of the WSS4J lib directory to
your Axis WEB-INF/lib directory. Many jar files will already exist.
Most of them will already exist there but you can just overwrite them
all.
   3. You may need to restart Tomcat unless you have automatic
deployment/class loading turned on. Check the Axis Happiness Page
(typically at http://localhost:8080/axis), make sure that the XML
Security (xmlsec.jar) is listed under the "Optional Components"
section.

Creating the service

   1. This tutorial will secure the StockQuoteService which ships with
the sample code with Axis. If you deploy the sample web apps that
ships with Axis you don't need to do anything more. Look at the Axis
docs on how to install it properly. Unless you have one already,
create a deployment descriptor (deploy.wsdd) file with the following
contents:


<deployment xmlns="http://xml.apache.org/axis/wsdd/"
xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">
 <service name="stock-wss-01" provider="java:RPC" style="document" use="literal">
  <parameter name="className" value="samples.stock.StockQuoteService"/>
  <parameter name="allowedMethods" value="getQuote"/>
  <parameter name="scope" value="application"/>
 </service>
</deployment>

It doesn't matter where you put this file.

   2. deploy the service (using AxisAdmin): 

java org.apache.axis.client.AdminClient
-lhttp://localhost:8080/axis/services/AdminService deploy.wsdd

The AdminClient class depends on a load of jar-files, so to deploy
this I created a bat-file that looked like this:

setlocal

set CLASSPATH=%CLASSPATH%;C:\axis-1_2RC2\lib\axis.jar;C:\axis-1_2RC2\lib\jaxrpc.jar;C:\axis-1_2RC2\lib\commons-logging.jar;C:\axis-1_2RC2\lib\commons-discovery.jar;C:\axis-1_2RC2\lib\saaj.jar;

java org.apache.axis.client.AdminClient
-lhttp://localhost:8080/axis/services/AdminService test-deploy.wsdd

endlocal

You have to change the bat-file to reflect where you've put your axis
jar files naturally.

Creating the Client

   1. Use WSDL2Java to generate the client service bindings (a number
of soap client classes):

      java org.apache.axis.wsdl.WSDL2Java -o .
-Nhttp://fox:8080/axis/services/stock-wss-01 samples.stock.client
http://fox:8080/axis/services/stock-wss-01?wsdl

      Again, the wsdl2java needs a number of jar files to work
properly, so I created a new bat-file to help out with that. The
bat-file looks like this:

      setlocal

      set CLASSPATH=%CLASSPATH%;C:\axis-1_2RC2\lib\axis.jar;C:\axis-1_2RC2\lib\jaxrpc.jar;C:\axis-1_2RC2\lib\commons-logging.jar;C:\axis-1_2RC2\lib\commons-discovery.jar;C:\axis-1_2RC2\lib\saaj.jar;C:\axis-1_2RC2\lib\wsdl4j.jar;

      java org.apache.axis.wsdl.WSDL2Java -o .
-Nhttp://localhost:8080/axis/services/stock-wss-01
samples.stock.client
http://localhost:8080/axis/services/stock-wss-01?wsdl

      endlocal

      A bunch of java classes will be created under
samples/stock/client, including the StockQuoteServiceServiceLocator.
   2. Write a simple java console application that uses the generated
service locator. For example:

      package samples.stock.client;

      import java.rmi.RemoteException;
      import javax.xml.rpc.ServiceException;

      public class StockServiceClient {
          public StockServiceClient() {
          }
          public static void main(String[] args) throws
ServiceException, RemoteException {
              if (args.length == 0) {
                  System.out.println("Usage:\njava StockServiceClient [symbol]");
                  return;
              }
              StockQuoteServiceService locator = new
StockQuoteServiceServiceLocator();
              StockQuoteService service = locator.getStockWss01();
              float quote = service.getQuote(args[0]);
              System.out.println("stock quote service returned " +
args[0] + ": " + quote);
          }
      }
   3. run the client:

      java samples.stock.client.StockServiceClient XXX

      If all went well, you should get the result:

      stock quote service returned IBM: 55.25

When using "XXX" as parameter, the service won't try to go out on the
Internet to get the real quotes, but just returns a float with the
value of 55.25.

What you've created so far is a very simple web service with a simple
client that calls it. WSS4J has not been used yet, so this web service
call is unprotected. Now it's time to add a Username Token to the soap
call.

Configuring the Service for Username Token

   1. Modify the deployment descriptor you created above to look like this:

      <deployment xmlns="http://xml.apache.org/axis/wsdd/"
xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">
       <service name="stock-wss-01" provider="java:RPC"
style="document" use="literal">
        <requestFlow>
         <handler type="java:org.apache.ws.axis.security.WSDoAllReceiver">
          <parameter name="passwordCallbackClass" value="PWCallback"/>
          <parameter name="action" value="UsernameToken"/>
         </handler>
        </requestFlow>
        <parameter name="className" value="samples.stock.StockQuoteService"/>
        <parameter name="allowedMethods" value="getQuote"/>
        <parameter name="scope" value="application"/>
       </service>
      </deployment>

      WSDoAllReceiver is an Axis handler located in wss4j.jar package.
This is the standard way to deploy an Axis handler. For more details
please refer to the Axis handler for WSS4J documentation.
   2. Create a class named PWCallback.java and compile it and put the
resulting PWCallback.class file into your Axis WEB-INF/classes
directory. In this example I used the default package for simplicity,
but you might need to use the fully qualified class name (be
consistent with the deployment descriptor).

      The following code snippet shows a simple password callback class:

      import java.io.IOException;
      import javax.security.auth.callback.Callback;
      import javax.security.auth.callback.CallbackHandler;
      import javax.security.auth.callback.UnsupportedCallbackException;
      import org.apache.ws.security.WSPasswordCallback;

      public class PWCallback implements CallbackHandler {
          public void handle(Callback[] callbacks) throws IOException,
UnsupportedCallbackException {
              for (int i = 0; i < callbacks.length; i++) {
                  if (callbacks[i] instanceof WSPasswordCallback) {
                      WSPasswordCallback pc = (WSPasswordCallback)callbacks[i];
                      // set the password given a username
                      if ("wss4j".equals(pc.getIdentifer())) {
                          pc.setPassword("security");
                      }
                  } else {
                      throw new
UnsupportedCallbackException(callbacks[i], "Unrecognized Callback");
                  }
              }
          }
      }

   3. Redeploy the service using the bat file you created earlier.
Your service should now be expecting a WSS Username Token in the
incoming soap request, and clients should send the username "wss4j"
and password "security" to get through.

Configuring the Client for Username Token

   1. run the client we created again:

      java samples.stock.client.StockServiceClient IBM

      You should now get an error:

      Exception in thread "main" AxisFault
       faultCode: {http://schemas.xmlsoap.org/soap/envelope/}Server.generalException
       faultSubcode:
       faultString: WSDoAllReceiver: Request does not contain required
Security header

      This is because your client is not configured to send a Username
Token yet, so the service is rejecting the request. To fix this, you
need to create a callback class in the client, which adds the Username
Token to the outgoing soap request.
   2. Create a deployment descriptor file (client_deploy.wsdd) for the client:

      <deployment xmlns="http://xml.apache.org/axis/wsdd/"
xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">
       <transport name="http"
pivot="java:org.apache.axis.transport.http.HTTPSender"/>
        <globalConfiguration >
         <requestFlow >
          <handler type="java:org.apache.ws.axis.security.WSDoAllSender" >
           <parameter name="action" value="UsernameToken"/>
           <parameter name="user" value="wss4j"/>
           <parameter name="passwordCallbackClass"
value="samples.stock.client.PWCallback"/>
           <parameter name="passwordType" value="PasswordDigest"/>
          </handler>
         </requestFlow >
        </globalConfiguration >
      </deployment>
   3. Create the samples.stock.client.PWCallback class:

      package samples.stock.client;

      import java.io.IOException;
      import javax.security.auth.callback.Callback;
      import javax.security.auth.callback.CallbackHandler;
      import javax.security.auth.callback.UnsupportedCallbackException;
      import org.apache.ws.security.WSPasswordCallback;

      /**
       * PWCallback for the Client
       */
      public class PWCallback implements CallbackHandler {

          /**
           * @see javax.security.auth.callback.CallbackHandler#handle(javax.security.auth.callback.Callback[])
           */
          public void handle(Callback[] callbacks) throws IOException,
                          UnsupportedCallbackException {
              for (int i = 0; i < callbacks.length; i++) {
                  if (callbacks[i] instanceof WSPasswordCallback) {
                      WSPasswordCallback pc = (WSPasswordCallback)callbacks[i];
                      // set the password given a username
                      if ("wss4j".equals(pc.getIdentifer())) {
                          pc.setPassword("security");
                      }
                  } else {
                      throw new
UnsupportedCallbackException(callbacks[i], "Unrecognized Callback");
                  }
              }
          }
      }
   4. Define the system property axis.ClientConfigFile for your client:

      java -Daxis.ClientConfigFile=client_deploy.wsdd -classpath
$AXISCLASSPATH samples.stock.client.StockServiceClient

      Make sure that your CLASSPATH includes the jar files under WEB-INF/lib.

      Another way to do this is to specify the wsdd file in your
StockServiceClient to the service locator programmatically:

      ...
      import org.apache.axis.EngineConfiguration;
      import org.apache.axis.configuration.FileProvider;
      ...

      EngineConfiguration config = new FileProvider("client_deploy.wsdd");
      StockQuoteServiceService locator = new
StockQuoteServiceServiceLocator(config);
      ...
   5. Run the client, you should get no errors:

      stock quote service returned XXX: 55.25

      Your client is now sending a Username Token in the wsse request
header with the username "wss4j" (see client_deploy.wsdd) and password
"security" (see the PWCallback implementation).

      Another way to do this is to have the client application set the
username and CallbackHandler implementation programmatically instead
of using the client_deploy.wsdd file:

      ...
      import org.apache.axis.client.Stub;
      ...

      Remote remote = locator.getPort(StockQuoteService.class);
      Stub axisPort = (Stub)remote;
      axisPort._setProperty(UsernameToken.PASSWORD_TYPE,
WSConstants.PASSWORD_DIGEST);
      axisPort._setProperty(WSHandlerConstants.USER, "wss4j");
      axisPort._setProperty(WSHandlerConstants.PW_CALLBACK_REF, pwCallback);

      where "pwCallback" is a reference to a PWCallback
implementation. See the Axis handler for WSS4J documentation for more
details on this.

      UPDATE: I've tried to set the callback using the techinque
above, but without much success. I'll continue trying, and when I get
it working I'll update this section again :)

      UPDATE 2: After some testing and teaking and good ideas from
people, I got the thing above working. It's all explained in another
blog post.
   6. Try modifying your client's PWCallback to return the wrong
password, or send the wrong username. The service should reject your
requests.

Known problems

When I first ran this tutorial myself, I got a stacktrace error that
didn't interrupt the program, but printed out a warning about the
xalan.jar package. It looks something like this:

- Unable to patch xalan function table.
       java.lang.NoSuchFieldException: m_functions
              at java.lang.Class.getField(Unknown Source)
              at org.apache.xml.security.Init.registerHereFunction(Init.java:429)
              at org.apache.xml.security.Init.init(Init.java:124)? (and so on)

This may have to do with how the xalan.jar package is deployed on your
system and what version of xalan you use and the version of JDK. I got
the tip from Ashok Shah to make sure I use Java version 1.4.2_04
instead of 1.4.2_06 that I used. I've not tried this yet, but I will
do.

UPDATE: I tried to put the xalan.jar in the JAVA_HOME/lib/endorsed/
directory, but it didn't work much better. So I updated to JDK 5.0 and
made sure that the xalan.jar package from the WSS4J distribution was
available to tomcat and to my client, and behold - it works :)

UPDATE 2: I got a tip from Martin Stemplinger that the xalan.jar
should probably go into the JAVA_HOME/jre/lib/endorsed/ directory.
I've not tested it myself, but it sounds right.

(Picked from http://weblogs.asp.net/jdanforth/archive/2005/01/16/354060.aspx)
Subject: Re: Deploying a java web service using Axis (JWS is not sufficient)
From: avatarng-ga on 10 Apr 2006 22:07 PDT
 
This is the simplest+summarize version I can get, in this way you
follow an example of deploying existing example. This is a generic way
which is so flexible, even you can deploy a servlet or bean to serve
as WSDL.

So much I post, hopes it helps!

required libraries:
-------------------
axis.jar, 
commons-discovery.jar, 
commons-logging.jar, 
jaxrpc.jar, 
saaj.jar, 
log4j-1.2.8.jar, 
xerces.jar, 
xml-apis.jar, 
xercesImpl.jar


setting environment variables:
------------------------------
on Windows
----------
set AXIS_HOME=c:\axis
set AXIS_LIB=%AXIS_HOME%\lib
set AXISCLASSPATH=%AXIS_LIB%\axis.jar;%AXIS_LIB%\commons-discovery.jar;
  %AXIS_LIB%\commons-logging.jar;%AXIS_LIB%\jaxrpc.jar;%AXIS_LIB%\saaj.jar;
  %AXIS_LIB%\log4j-1.2.8.jar;%AXIS_LIB%\xml-apis.jar;%AXIS_LIB%\xercesImpl.jar

ON UNUX
-------
set AXIS_HOME=/usr/axis
set AXIS_LIB=$AXIS_HOME/lib
set AXISCLASSPATH=$AXIS_LIB/axis.jar:$AXIS_LIB/commons-discovery.jar:
  $AXIS_LIB/commons-logging.jar:$AXIS_LIB/jaxrpc.jar:$AXIS_LIB/saaj.jar:
  $AXIS_LIB/log4j-1.2.8.jar:$AXIS_LIB/xml-apis.jar:$AXIS_LIB/xercesImpl.jar
export AXIS_HOME; export AXIS_LIB; export AXISCLASSPATH


Run the admin client:
---------------------
On Windows
----------
java -cp %AXISCLASSPATH% org.apache.axis.client.AdminClient
     -lhttp://localhost:8080/axis/services/AdminService deploy.wsdd

On UNIX
-------
java -cp $AXISCLASSPATH org.apache.axis.client.AdminClient
     -lhttp://localhost:8080/axis/services/AdminService deploy.wsdd


testing:
--------
On Windows
----------
java -cp .;%AXISCLASSPATH% samples.stock.GetQuote
     -lhttp://localhost:8080/axis/servlet/AxisServlet
     -uuser1 -wpass1 XXX

On UNIX
-------
java -cp $AXISCLASSPATH samples.stock.GetQuote
     -lhttp://localhost:8080/axis/servlet/AxisServlet
     -uuser1 -wpass1 XXX


adding Axis to your own Webapp:
-------------------------------
1. Add axis.jar, wsdl.jar, saaj.jar, jaxrpc.jar and the other
dependent libraries to your WAR file.
2. Copy all the Axis Servlet declarations and mappings from
axis/WEB-INF/web.xml and add them to your own web.xml
3. Build and deploy your webapp.
4. Run the Axis AdminClient against your own webapp, instead of Axis,
by changing the URL you invoke it with.


testing url:
------------
http://localhost:8080/axis/servlet/AxisServlet (list all web services)
http://localhost:8080/axis/SOAPMonitor (web service monitoring client)
http://localhost:8080/axis/happyaxis.jsp (dianogstic page)

Important Disclaimer: Answers and comments provided on Google Answers are general information, and are not intended to substitute for informed professional medical, psychiatric, psychological, tax, legal, investment, accounting, or other professional advice. Google does not endorse, and expressly disclaims liability for any product, manufacturer, distributor, service or service provider mentioned or any opinion expressed in answers or comments. Please read carefully the Google Answers Terms of Service.

If you feel that you have found inappropriate content, please let us know by emailing us at answers-support@google.com with the question ID listed above. Thank you.
Search Google Answers for
Google Answers  


Google Home - Answers FAQ - Terms of Service - Privacy Policy