You are viewing a plain text version of this content. The canonical link for it is here.
Posted to soap-user@xml.apache.org by gr...@i2image.com on 2001/02/14 18:06:26 UTC

HOW TO: Configure Tomcat/Catalina, SOAP and the addressbook sample

I have posted this in the hopes that it will help others that have run in
to problems setting up Tomcat with SOAP. What I will describe applies to
Tomcat 4.0b1 running under NT 4.0 SP6.1as localhost on port 8080 although
the caveats apply to previous versions and OS's. These notes represent my
current understanding of Tomcat configuration and a number of very
frustating days used in setting up Tomcat 4.0b1. If anything is in error, I
apologize in advance and welcome any and all corrections and
clarifications.

First, the SOAP documentation clearly states that "Apache-SOAP requires
Apache Xerces (Java) version 1.1.2 or higher." Make sure you are using a
current version of the Xerces parser (currently at 1.3.0). Also, note (as
many many individuals have already pointed out) that the xerces jar file
needs to be declared first in you environment classpath. This is because
"these versions support the DOM level 2 candidate recommendation which
provides namespace support. If you have any other XML parsers (or other JAR
files which may have the org.w3c.dom.* interfaces), then it is very
important that you place the JAR file xerces.jar from Xerces at the front
of your classpath. Apache-SOAP will not work otherwise."

Configure Tomcat as described in the SOAP docs for installation (I'm sure
you've done that successfully and that's why your looking at this in quiet
desperation).

Note that Tomcat (alias Catalina in Tomcat 4.x) creates a "work" directory
under the CATALINA_HOME (TOMCAT_HOME for older versions) directory defined
by the environment variable CATALINA_HOME or by the JVM directive
-Dcatalina.home=%CATALINA_HOME% (which appears to override the environment
variable) (see catalina.bat in bin directory). This work directory caches
compiled JSP scripts across runs of the server. If you look inside this
directory (after having run SOAP successfully), you will see that java
source code files are dynamically created from the jsp scripts "list",
"deploy" and "undeploy" and that these source code files are dynamically
compiled into class files that are then dynamically loaded by the server.
(Interestingly the dynamically created SOAP Java source files indicate that
they are in package admin, yet they are stored one directory above the
admin directory and the admin directory remains empty when things are
running "correctly.") Therefore, if you change your setup, especially when
you are having problems getting the server and SOAP to work together, it is
absolutely critical that the server be stopped, the work directory be
thrown away in the trash and the server be restarted. I spent days trying
to fix a configuration problem that I probably had fixed days earlier,
because I failed to discard the work directory.

Tomcat has its own class loader. This appears to cause no end of confusion
for new users. This means that it has its own internal classpath that is
independent of the classpath provided through the shell environment
variable CLASSPATH or as an argument to the JVM using -cp or -classpath.
Because of this Tomcat loads unjar'd classes and jar'd classes from two
possible locations. Tomcat can load unjar'd classes from a directory called
"classes" that must be located directly under the Tomcat home directory and
it can load jar'd classes (i.e. ones in a jar file) from a directory called
"lib" that must also be located directly under the Tomcat home directory.
In addition to these two locations, Tomcat will load unjar'd and jar'd
class files from directories named "classes" and "lib" respectively when
these directories are placed in your webapps application directory under
WEB-INF. For example, using the SOAP application, you would place its
classes and jar files in directories classes and lib as follows:

YOUR_TOMCAT_HOME\webapps\soap\WEB-INF\classes

and/or

YOUR_TOMCAT_HOME\webapps\soap\WEB-INF\lib

Note that when you place your unjar'd classes in either "classes"
directory, you must maintain the package hierarchy of the classes. For
example, if you place a compiled class myclass.class into classes that has
a package of a.b.c, you must create a directory structure of:

YOUR_TOMCAT_HOME\webapps\soap\WEB-INF\classes\a\b\c\myclass.class

It appears that Tomcat loads the classes in "classes" and "lib" under
Tomcat's home first and then those defined under the application
directories, but I have not confirmed this. I have also not confirmed if
Tomcat creates a separate classpath for each application (i.e. different
applications will not see classes from other applications) or if everything
is loaded into one Tomcat classpath. (Any clarification of this issue would
be appreciated).

Make sure the soap.jar file is in your class path just after xerces.jar.
The soap.jar file should also be located in either of the lib directories
described above. I placed it under ...\soap\WEB-INF\lib, since it is
specific to the soap application.

Make sure that you have Sun's Java Mail mailapi.jar (the other mail jars
are unneeded) and the JavaBeans Activation Framework activation.jar files
in your classpath. Both are needed for SOAP.

In order to run the SOAP samples, you should copy the samples directory (as
you received it from the distribution) to:

YOUR_TOMCAT_HOME\webapps\soap\WEB-INF\classes

You must also make sure that this directory is in your environment
classpath. This will allow you to run the address book SOAP remote clients
in testit (described below) or independently as described in the
addressbook README file. If you fail to put this directory in your
classpath, you will see errors of the type:

Getting info for "Mr Good"
Exception in thread "main" java.lang.NoClassDefFoundError: samples/addressbook/GetAddress

In the catalina.bat file in the bin directory under YOUR_TOMCAT_HOME change
the following lines to include your environment's classpath as follows:

FROM:

rem ----- Set Up The Runtime Classpath
----------------------------------------set

CP=%CATALINA_HOME%\bin\bootstrap.jar;%JAVA_HOME%\lib\tools.jar
set CLASSPATH=%CP%
echo Using CLASSPATH: %CLASSPATH%

TO:

rem ----- Set Up The Runtime Classpath
----------------------------------------set

CP=%CATALINA_HOME%\bin\bootstrap.jar;%JAVA_HOME%\lib\tools.jar
set CLASSPATH=%CLASSPATH%;%CP%
echo Using CLASSPATH: %CLASSPATH%

Bring up a DOS command prompt and go to the CATALINA_HOME\bin directory and
startup the server with:

startup

and you should see a command prompt window come up with (for Tomcat 4.0b1
of course):

Starting service Tomcat-Standalone
Apache Tomcat/4.0-b1
Starting service Tomcat-Apache
Apache Tomcat/4.0-b1

In the SOAP 2.1 (but not SOAP 2.0) distribution there is an NT command file
called testit.cmd. Go to the addressbook directory at:

YOUR_TOMCAT_HOME\webapps\soap\WEB-INF\classes\samples\addressbook

and run testit.

The example should walk through all the addressbook SOAP clients and exercise them.

If you get:

org.xml.sax.SAXParseException: The markup in the document preceding the root
element must be well-formed.
        at org.apache.xerces.framework.XMLParser.reportError(XMLParser.java:1016)
        at org.apache.xerces.framework.XMLDocumentScanner.reportFatalXMLError(XMLDocumentScanner.java:625)
        at org.apache.xerces.framework.XMLDocumentScanner$XMLDeclDispatcher.dispatch(XMLDocumentScanner.java:804)
        at org.apache.xerces.framework.XMLDocumentScanner.parseSome(XMLDocumentScanner.java:380)
        at org.apache.xerces.framework.XMLParser.parse(XMLParser.java:908)
        at org.apache.soap.util.xml.XercesParserLiaison.read(XercesParserLiaison.java:85)
        at org.apache.soap.rpc.Call.invoke(Call.java:157)
        at org.apache.soap.server.ServiceManagerClient.invokeMethod(ServiceManagerClient.java:110)
        at org.apache.soap.server.ServiceManagerClient.deploy(ServiceManagerClient.java:123)
        at org.apache.soap.server.ServiceManagerClient.main(ServiceManagerClient.java:188)

Exception in thread "main" [SOAPException: faultCode=SOAP-ENV:Protocol;
msg=java.lang.NoSuchMethodError
        at org.apache.soap.util.xml.QName.<init>(QName.java:80)
        at org.apache.soap.util.xml.QName.matches(QName.java:146)
        at org.apache.soap.Envelope.unmarshall(Envelope.java:210)
        at org.apache.soap.server.http.RPCRouterServlet.doPost(RPCRouterServlet.java:182)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:760)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:853)
        at org.apache.tomcat.core.ServletWrapper.doService(ServletWrapper.java:404)
        at org.apache.tomcat.core.Handler.service(Handler.java:286)
        at org.apache.tomcat.core.ServletWrapper.service(ServletWrapper.java:372)
        at org.apache.tomcat.core.ContextManager.internalService(ContextManager.java:797)
        at org.apache.tomcat.core.ContextManager.service(ContextManager.java:743)
        at org.apache.tomcat.service.http.HttpConnectionHandler.processConnection(HttpConnectionHandler.java:210)
        at org.apache.tomcat.service.TcpWorkerThread.runIt(PoolTcpEndpoint.java:416)
        at org.apache.tomcat.util.ThreadPool$ControlRunnable.run(ThreadPool.java:498)
        at java.lang.Thread.run(Thread.java:484)]
        at org.apache.soap.rpc.Call.invoke(Call.java:167)
        at org.apache.soap.server.ServiceManagerClient.invokeMethod(ServiceManagerClient.java:110)
        at org.apache.soap.server.ServiceManagerClient.deploy(ServiceManagerClient.java:123)
        at org.apache.soap.server.ServiceManagerClient.main(ServiceManagerClient.java:188)

or something related to a SAX parser error, then stop the server, discard
the work directory, restart the server and issue the command (from the SOAP
2.1 addressbook\testit.cmd file):

java org.apache.soap.server.ServiceManagerClient
http://localhost:8080/soap/servlet/rpcrouter deploy
FULL_PATH\DeploymentDescriptor.xml (this is all on one line)

where FULL_PATH is the path to the DeploymentDescriptor.xml file inside the
samples\addressbook directory.

This attempts to deploy the addressbook services using the XML descriptor
file and the deploy.jsp Java server page (in ...\soap\admin). This is far
easier and much less error prone than attempting to deploy the address book
services using the web page that can be obtained at URL:

http://localhost:8080/soap/admin/index.html

Note that the SOAP rpcrouter can be checked for proper functioning by going
to URL:

http://localhost:8080/soap/servlet/rpcrouter

where you will see:

SOAP RPC Router
Sorry, I don't speak via HTTP GET- you have to use HTTP POST to talk to me.

when it is working properly.

Both the SOAP admin clients and visitation of the rpcrouter can be found at:

http://localhost:8080/soap

If you succeed, you should see:

SOAP Service Manager: Unable to read 'DeployedServices.ds': assuming fresh start
>>(Wed Feb 14 09:54:55 EST 2001) Processing SOAP request...

in the DOS command shell window where the server is sending its output.
This creates a DeployedServices.ds file in the bin directory where you
started the server.

You can then see your deployed services by issuing:

java org.apache.soap.server.ServiceManagerClient
http://localhost:8080/soap/servlet/rpcrouter list

which yields:

Deployed Services:
        urn:AddressFetcher

This is exactly the same as clicking on the List button on the SOAP admin
page.

Note that if you see a SAX parse error, then you have at least succeeded in
getting the server to execute the Java Server Page deploy.jsp located in
YOUR_TOMCAT_HOME\webapps\soap\admin. This means that the server has
successfully created the java source code for the JSP, compiled it and run
it (You can see the compiled code in the work directory at this point;
although when things are running correctly, the compiled files disappear).

If you do get the services to depoly then the addressbook example should work and you should be able run testit. Successfully running testit yields:

This test assumes a server URL of http://localhost:8080/soap/server/rpcrouter
Deploying the addressbook service...
.
Verify that its there
Deployed Services:
        urn:AddressFetcher
.
Getting info for "Mr Good"

123 Main Street
Anytown, NY 12345
(123) 456-7890
.
Adding "John Doe"
John Doe has been added.
.
Query "Mr Doe" to make sure it was added

123 Main Street
AnyTown, SS 12345
(800) 555-1212
.
Adding an XML file of listings
Added 2 listings.
.
Get everyone!
<AddressBook>
  <Listing>
    <Name>John Doe</Name>
    <Address>
      <StreetNum>123</StreetNum>
      <StreetName>Main Street</StreetName>
      <City>AnyTown</City>
      <State>SS</State>
      <Zip>12345</Zip>
      <PhoneNumber>
        <AreaCode>800</AreaCode>
        <Exchange>555</Exchange>
        <Number>1212</Number>
      </PhoneNumber>
    </Address>
  </Listing>
  <Listing>
    <Name>Bob Q. Public</Name>
    <Address>
      <StreetNum>456</StreetNum>
      <StreetName>North Whatever</StreetName>
      <City>Notown</City>
      <State>ME</State>
      <Zip>12424</Zip>
      <PhoneNumber>
        <AreaCode>987</AreaCode>
        <Exchange>444</Exchange>
        <Number>5566</Number>
      </PhoneNumber>
    </Address>
  </Listing>
  <Listing>
    <Name>Dave Davis</Name>
    <Address>
      <StreetNum>919</StreetNum>
      <StreetName>Baker Lane</StreetName>
      <City>Sunnytown</City>
      <State>UT</State>
      <Zip>43434</Zip>
      <PhoneNumber>
        <AreaCode>789</AreaCode>
        <Exchange>654</Exchange>
        <Number>3210</Number>
      </PhoneNumber>
    </Address>
  </Listing>
  <Listing>
    <Name>John B. Good</Name>
    <Address>
      <StreetNum>123</StreetNum>
      <StreetName>Main Street</StreetName>
      <City>Anytown</City>
      <State>NY</State>
      <Zip>12345</Zip>
      <PhoneNumber>
        <AreaCode>123</AreaCode>
        <Exchange>456</Exchange>
        <Number>7890</Number>
      </PhoneNumber>
    </Address>
  </Listing>
  <Listing>
    <Name>Mary Smith</Name>
    <Address>
      <StreetNum>888</StreetNum>
      <StreetName>Broadway</StreetName>
      <City>Somewhere</City>
      <State>FL</State>
      <Zip>87654</Zip>
      <PhoneNumber>
        <AreaCode>222</AreaCode>
        <Exchange>333</Exchange>
        <Number>4444</Number>
      </PhoneNumber>
    </Address>
  </Listing>
</AddressBook>
.
Undeploy it now
.
Verify that its gone
Deployed Services:

Interestingly, I had to use the full path to the descriptor file once and
then after throwing away the work directory and changing from Xerces 1.2.3
to 1.3.0, I no longer had to specify the full path. I went back to Xerces
1.2.3 and I still did not have to specify the full path. I'm not quite sure
why this happened, but I have seen messages from other users that have also
had to specify the full path to the descriptor file, although no mention
was made of not specifying the full path after that got the addressbook
example working.

As you can see, almost all problems stem from not setting up the classpaths
properly and not throwing away the work directory.

I have successfully run Tomcat 4.0b1 with SOAP 2.0 and SOAP 2.1 and with
Xerces 1.2.3 and Xerces 1.3.0.

---
Gregg Leichtman, Ph.D.
Senior Software Engineer
Quintiles Intelligent Imaging