Another option is what I've implemented in a project recently...

First, every single Web Service request is directed to a single Action mapping, quit originally called /WebServices.app :)

Then, in the action I first check for the SOAPAction header, making the assumption that only a valid Web Service request will contain it (that's not a requirement of the SOAP spec as far as I know, but generally people and products to adhere to that rule, and certainly you can tell your clients they must to use your services). If it's not found I forward to an error page, presumably someone would see it, if not, too bad :)

From then on, it's really just a question of parsing the SOAP envelope...
all my services at this point I've dictated must be "flat", i.e., no nested XML nodes, in other words, all elements are a child of the root node (that to me is relatively flat, at least relative to the root node). This is actually sufficient for the vast majority of our services. The only reason I did it this way was that it made dealing with the SOAP message very easy: just read the body of the request, which is the SOAP message, and parse it with normal XML parsing classes. I didn't need to get any special SOAP parsing classes for this. Obviously a more robust solution would, but this was done with simplicity in mind.

Part of the WSDL spec for all my services is a RequestedService element. This, unbeknownst to the caller, is actually a class name (for instance, ChangePassword is one, FindAccount is another). I have a package com.company.app.webservices where all these classes live. So, I instantiate the class, which extends from a custom abstract class I wrote called WSHandler, and passed control to it to do whatever it is that it does (which in all cases here is a call to the business logic classes of the larger app).

Before I forget, there is also a UserID and Password element requried for all requests, and I do the same validation on the WS requests as I would any other non-service request through this system.

The WSHandler class basically contains three methods: startResponse, endResponse and process. The first two, as the name implies, writes out the common portions of the SOAP envelope. For example,. here's the actual startResponse method:

 // Must be called first in the process method.
 void startResponse(HttpServletResponse wsResponse) throws Exception {

wsOutBuffer = new StringBuffer();
wsOutBuffer.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
wsOutBuffer.append("<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"; xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"; xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\";>\n");
wsOutBuffer.append(" <soap:Body>\n");


 } // End startResponse()

Very straight-forward. The process() method is what the Action calls, and as the comment above says, it must start by calling startResponse(). Then, it does it's work and constructs the payload of the SOAP message. Here's an example from the ChangePassword service:

public void process(HashMap wsParameters, String logonMessage) throws Exception{
// Get the parameters we need for the call
String userID = (String)wsParameters.get("userID");
String currentPassword = (String)wsParameters.get("currentPassword");
String newPassword = (String)wsParameters.get("newPassword");
if (userID == null) { userID = ""; }
if (currentPassword == null) { currentPassword = ""; }
if (newPassword == null) { newPassword = ""; }
// Instantiate needed function beans
Connection conn = DBConnectionManager.createConnection();
UsersFB usFB = new UsersFB(conn);
// Call the function bean to do our work
boolean cpResult = usFB.changePassword(userID, currentPassword, newPassword);
// Finalize the function bean
usFB.cleanup();
// Generate our output and return it
startResponse(workContext);
writeResponse(" <ChangePasswordResponse xmlns=\"TOAWebServices\">");
writeResponse(" <result>");
if (cpResult) {
writeResponse(" Password Changed");
} else {
writeResponse(" Password NOT Changed");
}
writeResponse(" </result>");
writeResponse(" </ChangePasswordResponse>");
finishResponse();
} // End process()


Again, really fairly simple.

Now, the downside to this of course is that in order to expose existing code as a service, you have to implement a class for it extended from WSHandler, so it's not as straight-forward as some of the real Web Service packages out there (Axis and others). But, it is really very simple, and has the benefit of not requiring anything special outside the JDK (1.4.2 anyway if I remember correctly, 1.3.1 you'd have to add the XML parsing stuff as I recall). I personally like not having extra dependencies where I can avoid them, and this does that.

Naturally, this won't do for all cases, but for simpler services it should do the trick nicely, and has for me. It's not perfect, but depending on your needs might be a good fit.

Let me know if anyone has questions if they are interested in doing something like this, I'll try and answer any I can.

From: <[EMAIL PROTECTED]>
Reply-To: "Struts Users Mailing List" <[EMAIL PROTECTED]>
To: <[EMAIL PROTECTED]>
Subject: RE: Controller for web services
Date: Fri, 21 May 2004 11:35:05 +0100 (WEST)


Thank you (sorry for the direct reply... bad webmail :( ).

  I'll do just that.

Pedro Salgado

> I believe Axis has stuff for doing this kind of thing, but Im only just
> starting to learn it myself so still dont know all the details. What Ive
> seen is pretty cool though!
>
> They have a rather active user list so Im sure if you ask there someone
> will be able to help :-)
>
> regards
> Andrew
>
> -----Original Message-----
> From: [EMAIL PROTECTED] [mailto:[EMAIL PROTECTED]
> Sent: Friday, 21 May 2004 18:17
> To: [EMAIL PROTECTED]
> Subject: RE: Controller for web services
>
>
>
>   Yes, Axis is what I need. (thank you Andrew)
>   But is there any "Controller" for web services?
>   Do I need to have a different class for each web service and then do
> the
> security, authorization refactoring by myself?
>
>
>   Now:
>   WS1 -> 1 class W1 -> calls methods in a predefined and obliged order
> WS2 -> 1 class W2 -> calls methods in a predefined and obliged order
>
>  What I have in mind
>   WS1 ... WSn -> controller -> check authentication/authorization ->
> dispatch to a class that consumes the web service and sends a response.
>
>   Struts isn't the answer because I am not processing HTTP requests...
> so :(
>
> Pedro Salgado
>
>> Have a look at Axis (also an Apache project). It will probably do what
>> you need.
>>
>> -----Original Message-----
>> From: Pedro Salgado [mailto:[EMAIL PROTECTED]
>> Sent: Friday, 21 May 2004 13:20
>> To: Struts Users List
>> Subject: Controller for web services
>>
>>
>>
>>   Is there any MVC implementation for web services (I am not seeing
>> any
>> wasy
>> way to do that with Struts)?
>>
>>   Thank you,
>>
>> Pedro Salgado
>>
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: [EMAIL PROTECTED]
>> For additional commands, e-mail: [EMAIL PROTECTED]
>>
>>
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: [EMAIL PROTECTED]
>> For additional commands, e-mail: [EMAIL PROTECTED]




--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]


_________________________________________________________________
Best Restaurant Giveaway Ever! Vote for your favorites for a chance to win $1 million! http://local.msn.com/special/giveaway.asp



--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]



Reply via email to