|
|
 |
Integrating Apache SOAP with an EJB Server
By Billy Newport, EJB Consultant.
Part 1 |
Part 2 |
Part 3 |
Part 4
This is part one of a 4 part series on how to use SOAP with Visual Age and WebSphere. All lot of this articles just show
how to install and configure the SOAP engine with VAJ/WAS. Part 2 will be useful to anybody using SOAP regardless of which
server you're using as it shows how to write the server adapter code for binding SOAP to session beans.
Part 3 gets SSL working and
Part 4 will get certificate based authentication working.
This first part deals mainly with getting a working VAJ 3.5 SOAP configuration for development. But, even
though a lot of it is related to WebSphere and Visual Age, it covers issues such as security integration between
SOAP and EJB servers that apply equally well to any J2EE server.
Setup the development environment.
First, download SOAP from the Apache SOAP homepage. I downloaded the 2.0 binary
zip and the 2.0 source zip. Unzip both in to a common directory.
Make sure you get the source version. Apache SOAP, by default, uses the servlet 2.2 API. VAJ doesn't support this right now so we get the
source version and modify a couple of lines
to make it work with servlet V2.1. WAS 3.5.2 does support servlet 2.2 but it's not much good when the development tool does not.
Now, get the xerces.jar file from your WebSphere/appserver/lib directory. Import this in the IBM XML Parser project in VAJ. Next,
we import the SOAP sources in to a new project called SOAP. There will be a couple of problems, thats OK. Now, switch to the Problems
pane in VAJ. You will see that your SOAP project has some problems. These are the methods that are using the servlet 2.2 API. There
are two types of changes to make.
Any session.getAttribute calls need to be changed to session.getValue. Change any session.setAttribute
methods to session.putValue. At this point you should have no problems in the SOAP project.
It's important to use the xerces.jar (and xalan.jar) from the WAS appserver/lib directory. If you use a different version for your
server application then you run a good chance of runtime problems as WAS was developed with a different version of xerces/xalan that
your code. So, from now on, you should get used to the fact that you have to use the same version as your WAS runtime. If you play
around with custom class loaders etc, then you could load both the WAS and your version concurrent in the same VM but this is
only for the brave.
Now, we need to add the SOAP rpc router servlet to our VAJ servlet test environment. Find the default_app.webapp file. It should
be in your VAJ/ide/project_resources/IBM WebSphere Test Environment/hosts/default_host/default_app/servlets directory.
Add the following xml fragment to the file before the final </webapp> tag.
<servlet>
<name>rpcrouter</name>
<description>SOAP rpcrouter</description>
<code>org.apache.soap.server.http.RPCRouterServlet</code>
<servlet-path>/rpcrouter</servlet-path>
<init-parameter>
<name>ServicesStore</name>
<value>c:/temp/DeployedServices.ds</value>
</init-parameter>
<autostart>true</autostart>
</servlet>
This declares a new servlet at the /rpcrouter uri. Now, copy from the directory where you unziped the soap binary zip all the files
at this path 'soap-2_0\webapps\soap' to a directory in VAJ/ide/project_resources/IBM WebSphere Test Environment/hosts/default_host/default_app/web.
So, you should have a soap directory in the web directory after this action. This copies the web application
for administering the SOAP services to the WTE directories. At this point, the environment should be ready to go. You'll see that
the servlet has an initial parameter ServicesStore. This should specify where the list of deployed services is persisted.
This is ignored in V2.0 of SOAP as far as I can see. The .ds file is persisted in the C:\ibmvjava\ide\tools\com-ibm-ivj-ui-webcontrolcenter
directory on my machine.
Verifying the test environment
Create a new project called SOAP Samples. Import the java file in the soap/samples directory to this project. You should have no
errors. We will now deploy and launch the address book sample that come with the product to verify the environment is good. Launch the WebSphere test
environment tools and select the servlet engine. Click the 'Edit Class Path' button and select all projects for the
classpath. This adds the SOAP project and XML etc to the path the WTE servlet engine uses. Click OK, and hit the start servlet
engine button. Now, launch a browser and enter the url 'http://localhost:8080/soap'. This should display a welcome to SOAP
page. Click the admin link. You should see the SOAP admin page with List/Deploy and undeploy buttons. Click on LIST and you should
see a message saying that no services are deployed. Now click on DEPLOY. A form appears where we describe the new service. Each
sample SOAP service comes with a DeploymentDescriptor.xml file. This file contains all the information needed for deployment
but you can't deploy automatically using this file for now (as far as I know!). So I just copied the data
from this file to the form manually to deploy the address book sample. Here is the information I entered in the form to deploy the service:
| Column name | Column Value |
| ID | urn:AddressFetcher |
| Scope | Application |
| Methods | getAddressFromName addEntry getAllListings putListings |
| Provider Type | Java |
| Provider Class | samples.addressbook.AddressBook |
| Static | No |
| Number of Mappings | 2 |
Type mappings on this form are as follows:
| Encoding Style | Namespace URI | Local Part | Java Type |
| SOAP | urn:xml-soap-address-demo | address | samples.addressbook.Address |
| SOAP | urn:xml-soap-address-demo | phone | samples.addressbook.Phone |
Set the Java to XML and XML to Java columns for the types to:
org.apache.soap.encoding.soapenc.BeanSerializer
Right, click Deploy and it should say it was successful. You can verify that the DeployedServices.ds file was created after this
step. If you restart the servlet engine then it should read the old deployed services from this file. The file contains some
binary serialized objects so you can't edit it manually or construct it with an editor.
Now, we'll run the addressbook sample client. The package samples.addressbook has the code for this sample. The service is the class
AddressBook. The test client we will use is the class GetAddress. Right click on the class GetAddress and click properties. Click
the Program Tab and enter:
http://localhost:8080/rpcrouter "Bob Q. Public"
for the command line arguments. The first argument is the URL of the servlet we just added to the WTE.
This is the SOAP HTTP dispatcher. It accepts the XML encoded RPC from a HTTP request. It then makes a
call to our service class (samples.addressbook.AddressBook) and invokes the appropriate method. Only the
methods declared when we deployed the service may be called. The dispatcher then encodes the result
of the method call and returns it as the HTTP response. The second argument is the name of the address
we require from the service.
Now switch to class path and click the compute button. Click OK to display the properties dialog. Run
it. You should see the following output in the console:
456 North Whatever
Notown, ME 12424
(987) 444-5566
So, if you get this far then it's working fine in VAJ.
Gotchas with Clustering and Apache SOAP V2.0.
Apache SOAP is completely cluster dumb for the moment. They store the deployed services in a text file and overwrites it when-ever
you deploy a new service to that box. This means that even if you nfs share the file between WebSphere nodes in a cluster you
will trash the file when you deploy a service to box A and then deploy a service to box B. Basically, the first service will
be erased by deploying B. They should really use a database for this store. This is acknowledged in the source so if you can wait
fine. Otherwise, just deploy all services using a single box and then copy/replicate/share the file to the other boxes. If you do
this then you should be fine with regards to clustering. Just make the SOAP web app a model and clone it out to your cluster.
Once you do this then it should be fine in a cluster. Each SOAP dispatcher in each VM is independant from all others in the cluster.
Next, remember it uses the 2.2 servlet API. We had to change it so that it used the V2.1 servlet API to get it to work in VAJ. Lastly,
the ServicesStore attribute for the dispatcher servlet is ignored so it stores the services registry in the current directory your
servlet engine has.
Security Issues
We can put a WebSphere ACL on the rpc dispatcher. Unfortunately this allows us to merely say who can or cannot
make any SOAP calls. We can't stop someone making SOAP calls to specific services using this approach. Our
java service class also has no access to the servlet context so it cannot use J2EE security methods
(getCallerIdentity or isCallerInRole) to implement any security checks.
But, what we can do to workaround this is to put the code for the service in a stateless session bean. This means our service
class is merely a java bean that delegates the call to the session bean. So, the SOAP service simply
wraps the session bean. So, it would get an initial context, find the home interface, create the bean and
make the method call. Now, we make a SOAPROLE method group in WAS.
We only allow people contained in this SOAP role to make calls to the rpcrouter servlet. The SOAP dispatcher
will then forward the RPC to our service. We then get the IC, the home and make the call to the session bean.
We should specify method groups on the methods of the session bean. Clients that need to access to the methods
should be placed in these method groups. Clients that need to make any SOAP calls to any bean should also be
members of the SOAPROLE. This works around the security problem. Now, even though any one in the SOAPROLE
method group can make SOAP RPCs, the WebSphere container will stop the servlet from making calls
to a session bean method unless the client that authenticated to the servlet is authorized to do this. This security
check happens even though this is all taking place in the same thread. So, as long as we use a Session bean
for our business logic and just make the service a wrapper to the bean, then we can leverage WebSphere's
security to limit SOAP RPCs to specific users albeit a little indirectly. You will have a problem limiting access to specific RPCs if
you just put business logic code in a normal java bean.
Conclusion
So, you should have a working VAJ SOAP setup at this stage. You should know how to integrate WebSphere
security with the SOAP runtime. The next installment will show how to write a service that talks
with stateless session beans and how to deploy this to WAS 3.5 although it should be pretty clear how to deploy it now.
|