Showing posts with label Web Services. Show all posts
Showing posts with label Web Services. Show all posts

Sunday, February 28, 2010

Create and Deploy a JAX-RS REST service on Google App Engine

In this article you will learn how to create a REST service using JAX-RS reference implementation (Jersey) and deploy it on Google AppEngine.

Prerequisites

For this tutorial you will need:
  • a Google AppEngine account : http://code.google.com/appengine/
  • Eclipse Galileo (3.5.x)
  • Google App Engine SDK for Java

    • Install the Google Plugin for Eclipse as documented here (Check that you are using the release 1.3.1 of the GAE Java SDK, if not download it and configure the plugin to use it)
    • it is also useful to have the AppEngine documentation locally, you can download it from here.
  • JAX-RS Reference Implementation, be sure you take the Jersey 1.1.5 release. You can download it from here.

    • Unzip the file in a directory that we will call $JERSEY_HOME
  • JAXB 2.2 Implementation to simplify the marshalling/unmarshalling of the XML, and also facilitate the JSON support. Download it from here 


    • Install it using thejava -jar JAXB2_20091104.jar command.  The installation directory of JAXB will be called $JAXB_HOME

Creating new application

To create a new App Engine project in Eclipse:
  1. Click on the "New Web Application Project" button in the toolbar . It is also possible to do it using the menu File > Web Application Project

  2. The "Create a Web Application Project" wizard opens:
  • Project Name: EmployeeService
  • Package : com.grallandco.employee.service
  • Uncheck "Use Google Web Toolkit"
  • Check that the SDK version your are using is "App Engine 1.3.0"; if not configure the project to use it.
  • The screen should look like the following screen :


  • Click Finish

  • The project should look like the following screen :



Running the application

The App Egine SDK, installed with the Eclipse plugin contains a Web server (based on Jetty), that could be used for testing and debugging. To test that your application has been created correctly select the menu Run > Run As > Web Application. I personnaly most of the time run my server using the debug command Run > DebugAs > Web Application. In debug mode you can change source code and test is without restarting the server.

The web server is starting automatically, you should see the following message in the Eclipse console

The server is running at http://localhost:8080/

You can access the application, and the sample servlet that has been created using the URL: http://localhost:8080/employeeservice

To stop the server, click on the terminate button in the Eclipse console.

Configuring the REST support in the application

To be able to create and run REST services in your application you need to:
  • Add the JAX-RS, JAXB Jars in your project and application
  • Configure the web application (web.xml) to handle REST requests
Add JAX-RS, JAXB to your project
  1. Right click on the project and select menu entry Build Path > Configure Build Path...
  2. Click on the Add External JARs button

  3. Select all the JARs located in $JERSEY_HOME/lib  and $JAXB_HOME/lib folders. You can for better visibility and reuse create a user library with all these JARs
  4. You also need to copy the JARs in the web-inf/lib directory of your application, this step is mandatory to be sure that the JARs are included in the application when deployed to App Engine.
    Note: I do not like this step. I would prefer to do that by configuration of the build path, to automatically add the JARs to the WEB-INF/lib directory when executing/deploying the application. Unfortunately I did not find the way to do it, so if you know it, feel free to post a comment and I will update the article.

Configure the web application

In this step you will register a new URI to handle REST requests. To do that you need to register a new servlet that is using the Jersey API and configure it to a specific URI (eg: /ressources  and/or /rest) and configure what are the Java packages that contain the REST implementation classes. So you need to modify the web.xml of your application with the following entries:

  <servlet>
    <servlet-name>Jersey Web Application</servlet-name>
     <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
     <init-param>
     <param-name>com.sun.jersey.config.property.packages</param-name>
     <param-value>com.grallandco.employee.service.rest.impl</param-value>
     </init-param>
     <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>Jersey Web Application</servlet-name>
    <url-pattern>/resources/*</url-pattern>
  </servlet-mapping>
   <servlet-mapping>
    <servlet-name>Jersey Web Application</servlet-name>
    <url-pattern>/rest/*</url-pattern>
  </servlet-mapping>


This servlet that will answer to the /resources/ and /rest/ URL. The configuration parameter com.sun.jersey.config.property.packages is used by Jersey to list the packages where REST services implementation are located.Note that you can put as many package as you need to, you just need to separate the package names by a ; .


Creating a simple REST Service to test the environment

The project is now ready to contain REST service. It is time to create one.Create for example the class com.grallandco.employee.service.rest.impl.HelloWorldResource, be sure to use the package name that you have configured in the web.xml for the Jersey servlet, based on the configuration we have made in previous step the package is com.grallandco.employee.service.rest.impl

Here a sample class with the JAX-RS annotations:
package com.grallandco.employee.service.rest.impl;
import javax.ws.rs.Path;
import javax.ws.rs.GET;
import javax.ws.rs.Produces;
@Path("/hr/")
public class EmployeeResource {
 
 @GET
 @Produces("text/plain")
 @Path("/employee") 
 public String getEmployee() {
        return "Hello World!";
    }
}
You should be able to test it, stop the server and run it again, enter the following URL in your browser:
http://localhost:8080/resources/hr/employee
or
http://localhost:8080/rest/hr/employee


Deploying the application to Google App Engine

Before deploying the application you need to register a new application in Google App Engine using the Administartion Console, see the documentation here. In my example I have used "tugdual" as Application ID.
You can easily now deploy the application to Google App Engine by clicking on the  "Deploy App Engine Project" button Deploy App Engine Project Button available in the Eclipse toolbar.
To be able to deploy your application to Google App Engine, you need to check that your application can be registered, the application ID is stored in the WEB-INF/lib/appengine-web.xml.
<?xml version="1.0" encoding="utf-8"?>
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
 <application>[your-application-id]</application>   
 <version>1</version>    
 <!-- Configure java.util.logging -->
  <system-properties>
   <property name="java.util.logging.config.file" value="WEB-INF/logging.properties"/>
 </system-properties>    
</appengine-web-app>

The App Engine deploy button prompts you for multiple informations: username (your Google account) and password.

When the deployment is complete you can access your application using the following URL:
http://[your-application-id].appspot.com/resources/hr/employee
or
http://[your-application-id].appspot.com/rest/hr/employee

Ading XML and JSON support to the service

Let's now add new method to manipulate an "Employee" object using the service, and the data format should be based on JSON and XML. This is where JAXB is useful, since it allows easily to transform marshall/unmarshall Java objects in XML -obviously- and JSON (cool isn't!)

Creating an Employee Class

Start with the creation of a new class to manipulate Employee data, this is a very simple Java class that could look like the following code:

package com.grallandco.employee.service.model;
import java.util.Date;

public class Employee {
    private String firstName;
    private String lastName;
    private Date hireDate;
    private String email;   
    public Employee(String firstName, String lastName, Date hireDate, String email) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.hireDate = hireDate;
        this.email = email;
    }
    public Employee() {}
    public String getFirstName() {
 return firstName;
 }
    public void setFirstName(String firstName) {
 this.firstName = firstName;
 }
    public String getLastName() {
 return lastName;
 }
    public void setLastName(String lastName) {
     this.lastName = lastName;
 }
    public Date getHireDate() {
 return hireDate;
 }
    public void setHireDate(Date hireDate) {
 this.hireDate = hireDate;
 }
    public String getEmail() {
        return email;
 }
    public void setEmail(String email) {
        this.email = email;
   }
    public String toString() {
        StringBuffer sb = new StringBuffer();
        sb.append("First: ").append(getFirstName());
        sb.append(" - Last: ").append(getLastName());
        sb.append(" - Date: ").append(getHireDate());
        sb.append(" - Email: ").append(getEmail());
        return sb.toString();
    }
}
When implementing your "real" application with some persistence layer this POJO is the one as JDO/JPA entity.

Create a Converter class for your entity

I usually encapsulate all the transformation in some converter class, like that I do not directly couple my business class to the serialisation mechanism. (So I do that for classes and lists of classes). So instead of adding the JAXB annotations to the Employee class itself, let's create an EmployeeConverter class that will be responsible of the transformation and used by your REST service.

package com.grallandco.employee.service.converter;

import java.util.Date;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import com.grallandco.employee.service.model.Employee;

@XmlRootElement(name = "employee")
public class EmployeeConverter {
 private Employee entity = null;
 public EmployeeConverter() {
 entity = new Employee();
 }

 public EmployeeConverter(Employee entity) {
 this.entity = entity;
 }

 @XmlElement
 public String getFirstName() {
 return entity.getFirstName();
 }

 @XmlElement
 public String getLastName() {
 return entity.getLastName();
 }

 @XmlElement
 public Date getHireDate() {
 return entity.getHireDate();
 }

 @XmlElement
 public String getEmail() {
 return entity.getEmail();
 }

 public Employee getEmployee() {
 return entity;
 }

 public void setFirstName(String firstName) {
 entity.setFirstName(firstName);
 }

 public void setHireDate(Date hireDate) {
 entity.setHireDate(hireDate);
 }

 public void setLastName(String email) {
 entity.setEmail(email);
 }

 public void setEmail(String lastName) {
 entity.setLastName(lastName);
 }
}
You can now update your service to use this utility/converter class to return XML or JSON ojbect based on the content type of the request.

Add support to JSON and XML to your REST service

You need to change the EmployeeRessource class, to change the signature and add new annotations of the getEmployee() method.
The annotation you are adding:
  • @Produces({"application/xml", "application/json"}) : indicates which type of content will be produced by the service. Based on the type of the request.
  • @Path("/employee/{employeeEmail}/") :    change the Path to indicate a Path parameter, here for example the URL can accept an email in the URI - not the best example, but you get the point...
  • public EmployeeConverter getEmployee( @PathParam ("employeeEmail") String email)  : change the type returned by the method and take a parameter as String that match the Path param defined in the @Path annotation
Here the complete class code:
package com.grallandco.employee.service.rest.impl;

import javax.ws.rs.Path;
import javax.ws.rs.GET;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import com.grallandco.employee.service.converter.EmployeeConverter;
import com.grallandco.employee.service.model.Employee;

@Path("/hr/")
public class EmployeeRessource {

 
 @GET
 @Produces({"application/xml", "application/json"})
 @Path("/employee/{employeeEmail}/") 
 public EmployeeConverter getEmployee( @PathParam ("employeeEmail") String email) {
 //dummy code
 Employee emp = new Employee();
 emp.setEmail(email);
 emp.setFirstName("John");
 emp.setLastName("Doe");
 EmployeeConverter converter = new EmployeeConverter(emp);
 return converter;
 } 
}


Test the service

You can now run the server locally and test the service
http://localhost:8080/resources/hr/employee/tug@grallandco.com
This will return an XML document.
If you want to test the JSON call you have multiple choice:
  • Using following command
tgrall$ curl -H "Accept: application/json" http://localhost:8080/resources/hr/employee/tug@grallandco.com
{"email":"tug@grallandco.com","firstName":"John","lastName":"Doe"}
  • Using an HTTP client that allows your to configure/set the HTTP request completely, I am using the Poster Firefox Plugin
  • Using some Javascript code in an application
You can repeat the test on your deployed application on Google App Engine.

Conclusion

In this article you have learned how to create and deploy a new REST Service on Google App Engine. This service has been created with the JAX-RS Reference Implementation the Jersey project. In the next article you will learn how to add persistence and create a CRUD Rest service on Google App Engine.

Tuesday, February 17, 2009

JAX-WS: How to configure the service end point at runtime?


When deploying your Web Service client you often need to change the endpoint of the service that  has been set during the code generation. This short post explains how you can set change it at runtime in the client code.

You have two approaches to do that:

  • set the endpoint in the Port using the BindingProvider
  • get the endpoint URL from the WSDL itself at runtime

Use the Binding Provider to set the endpoint URL

The first approach is to change the BindingProvider.ENDPOINT_ADDRESS_PROPERTY property value of the BindingProvider (Port) using the following code:
        try { 
           
EmployeeServiceService service = new EmployeeServiceService();
           
EmployeeService port = service.getEmployeeServicePort();

           
BindingProvider bp = (BindingProvider)port;
           
bp.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, "http://server1.grallandco.com:8282/HumanRessources/EmployeeServiceService");

           
Employee emp = port.getEmployee(123);



           
System.out.println("Result = "+ emp);
       
} catch (Exception ex) {...

          

Use the WSDL to get the endpoint URL

Another part is to set the WSDL when you are creating the Service. The service will be using the value that is located in the WSDL port -SOAP Endpoint-. This is simply done using the following code:
        try { 
          
EmployeeServiceService service =
          
new org.demo.service.EmployeeServiceService
               
(new URL("http://server1.grallandco.com:8282/HumanRessources/EmployeeServiceService?wsdl"),
               
new QName("http://service.demo.org/","EmployeeServiceService"));

           
EmployeeService port = service.getEmployeeServicePort();

           
Employee emp = port.getEmployee(123);

         System.out.println("Result = "+ emp);
       
} catch (Exception ex) {
          

Note that, in Glassfish, like lot of Web Service environments the WSDL can generate dynamically the Endpoint URL based on the URL used  to get the WSDL. With this approach you can also dynamically change the Soap endpoint. (If compatible with the network configuration of the production environment.)

Tuesday, March 25, 2008

Exposing a Database as a Web Service... with OracleAS and DB

I am just cross posting this entry to react to this very interesting article:
- Exposing a Database as a Web Service a developer.com article...

Oracle Application Server Web Services

If you are an Oracle Application Server user, you may know that it is possible to expose database resources as Web Services using the OracleAS Web Services stack. You can for example using JAX-RPC based Web Service create service on a PL/SQL stored procedure, a SQL statement and even poste message on a queue (AQ). This is available in the Web Service Assembler (wsa) tool and also JDeveloper.
At the end when you have executed the wizard, you have a complete JavaEE application ready to be deloyed. All the JDBC calls and PL type mapping are done automatically by the wizard... very neat Take a look to the Assembling Database Web Services documentation.

Here the archtecture schema of OracleAS Database Web Services:
It is important to mention that such service can leverage the WS-* support of OracleAS and any JAX-RPC handler you want to add to the service.

BPEL PM and Database Resources

In addition to a pure Java developer approach it is also possible to expose database resource as Web Service using Oracle BPEL PM, yeah... it could be overloaded, but still it is possible and very easy to do. See the chapter BPEL: Communicating with a Database

Oracle RDBMS 11 NDWS

Orale RDBMS introduced a new feature that is called: Native Oracle XML DB Web Services, that allows developer to directly expose Web Services from the DB. Take a look to the chapter Using Native Oracle XML DB Web Services.
Note that in this case you do not have any WS-* support without another technical solution that could be Oracle Web Service Manager or any other solutions (such as a SOA appliance like for example IBM dataPower)
hmm I have not used that much this feature since I have left Oracle... I wonder when Oracle will provide a OS X release that will allow me to use my computer without any VM...

Thursday, December 20, 2007

Web Services and Files Exchange

SOAP based Web Services are now very common in the enterprise architecture, and quite often, applications that consume or publish services would need to send binary content such as images, PDF or Word documents (or anything you have in mind...). The SOAP and XML provide different way to achieve this. So what are the challenges around binary data exchange using SOAP based Web Services:
  • The main goal of Web Services is interoperability; so when you are offering a service, you need to be careful about the technical choice you are making. SOAP has been one great success in term of interoperability. I am aware that REST is also a very good fit for that but since I talk about SOAP and later WS-* standards, I do not want to talk about REST more in this post, the only thing that you can put in your mind is before choosing to implement SOAP based Web Services, ask the following question to yourself: "do I really need SOAP services or REST would be enough?"... That said let's continue on SOAP and binary content exchange. When talking about binary content, the interoperability comes with some trade off around for example performance/message sized or impact on developer. This will be discussed later, but always keep in mind that interoperability is the key point of Web Services. If this is not the case on your project, that means you probably do not need to use SOAP that has an important overhead in general.
  • Performance and Scalability is also quite important when you are building a service based application. Especially that often you cannot predict exactly how much a service will be used. We have to keep in mind that often services are build to be reusable, it is one of the basic best practices of development, so if the service is really "reused" it is important to keep it running with acceptable performances. This is why when talking about binary content, with SOAP it is important to talk about the impact of it on the size of the message and the processing cost.
  • When using SOAP Composability is also quite important. In the context of binary content exchange with XML/SOAP it is important to support composability of the WS-* standard, and this in a performant manner. An example would be that a services that is sing WS-Security to sign part of the messages should be able to sign the PDF document using the same standard.
  • Impact on development: it is interesting also when choosing the way binary content should be exchanged with SOAP, to see how much impact it has on the development itself. Does a developer must import specific API to be sure that the binary content is properly sent/consumed by the server or client. Note: I will talk about Java here, and particularly about JAX-WS/JAX-RPC since it is the stacks that I know the much, but the remarks would be the same on all technologies.
Let's now dive into the different options that are offered to a developer/architect to exchange document using SOAP:
  • XML Base64 encoding
  • SOAP With Attachment (SwA) using MIME (Multipurpose Internet Mail Extensions)
  • SOAP With Attachment using DIME (Direct Internet Message Encapsulation)
  • Message Transmission Optimization Mechanism (MTOM)
First of all, I will not talk in detail about the 3rd point around SOAP with Attachment with DIME, for a simple reason: this approach has been pushed by Microsoft around 2003/2004 and it is now deprecated in favor of MTOM.

Base64 Encoding
Base64 is part of the core XML capabilities, and when using it to exchange binary content in a SOAP message it has some very good advantages:
  • Since it is part of XML itself, it has a great interoperability, I can say that all stacks will be able to consume or send messaged that contains Base64 data.
  • For the same reason it does not have any impact on development, most of the Java stacks will automatically use base64 encoding when byte[] paramters will be present.
  • Always because of the fact that is it 100% XML based, the composability with other XML/WS-* standard is very good.
  • So far eveything looks great for this approach, but the trade off is the following: Base64 encoding is not efficient, since "lot of" CPU will be used to encode and decode the binary content. In addition the size of the encoded data would be around 30% bigger than the binary content itself. (It can still be used for small dataset)
SOAP with Attachment (SwA)
The SOAP with Attachment specification is the first effort of the Web Services industry to solve the problem of binary content with SOAP. The idea is to In addition to the W3C Note, the WS-Interoperability organization, has extend this recommendation to create a basic attachment profile to enforce the interoperability of it, using the SOAP with Attachment Reference (swaRef).
  • The good part of SwA and is the fact that it has been noted by the W3C but also adopted by the WS-I organization. But in fact the interoperability is not that great, mainly because none of the Microsoft Web Services solution support SwA. It is true that most of the Java stacks, starting with the standard JAX-RPC/JAX-WS is supporting SwA and swaRef but it is not enough to call it a good interoperability.
  • The reason why Microsoft refused to implement it, and why it is only a W3C note (and not a recommendation) it is because SOAP with Attachment has poor composability. The reason why it is hard to use WS-* standard with SwA, it is because it breaks some part of the model by ignoring the SOAP/XML processing and just put the document in the MIME header, and a simple reference to it into the SOAP message.
  • SOAP with Attachment is efficient, because of the previous point. The SOAP stack does not really deal with the content and just stream it into the MIME header.
  • When it is used with JAX-RPC and JAX-WS, has an impact on the developer, that must use specific Java API to build it service and put specific data types in the WSDL. The impact on development is not large, but still developper has to think about providing the good method signature or WSDL entry to enforce the use of SwA/swaRef in its service. Where I do believe most developers would expect this to be transparent.
Message Transmission Optimization Mechanism (MTOM)
The last mechanism is also based on MIME on the wire to exchange the binary content, but the way the message (SOAP+MIME) is build is totally different from the previous SwA approach. MTOM has been based on the "experience" of the others mechanisms, to be able to support composability without impacting the performance and the development.
  • Interoperability is virtually great. It is great because it has been pushed by major vendors such as IBM, Microsoft, BEA, Oracle and it is a W3C recommendation, so interoperability should be good. I put a "virtually", because to be interoperable the various Web Services stack must implement it, and it is not the case yet. Today, most of the latest stacks are supporting MTOM so it should not be an issue if you are starting a project.
  • Composability is perfect, since MTOM does use the SOAP envelop but it provides an automatic and transparent optimization to put the binary content on the MIME header. During the serialization of the message, the SOAP engine is working with the content with a temporary base64 representation of the content allowing all the WS-* operation needed, for example an XML signature, but without the overhead of dealing with base64 over the wire.
  • MTOM appears like the most efficient way of dealing with large document and SOAP.
  • Because MTOM is using the same approach than the pure XML base64 process, it does not have any impact on development. In fact this the the Web Service stack that choose to use base64 (embedding the document) or MTOM over the wire. And this could be done in conjunction with a WS-Policy. As you can see in the WS-MTOMPolicy this is not under the control of the developer but more under the control of the administrator and then the applications to choose or not to use MTOM.
But... Which one I should use?
Based on the different points described earlier is looks like MTOM is the way to go; even if this is true it cannot be summarized to this. First of all MTOM is not supported by all the stacks, so if you cannot control the consumers of your services and cannot impose a modern stack, MTOM may not be the best approach. For me, the second on the list is the Base64 approach, because of high interoperability but it is important to remember that has an impact on performance/processing. I personnally would not push SwA because of its non support in the Microsoft world... As you know the world is not yet 100% Java based ;). Let's take a look on which stacks are supporting MTOM today:
  • JAX-WS reference implementation (and Metro)
  • IBM Websphere 6.x with SOA Feature Pack
  • BEA Weblogic 10
  • OracleAS 10gR3 (10.1.3.1) JAX-RPC and FWM 11 preview (JAX-RPC and JAX-WS)
  • Axis2
  • XFire
  • JBossWS
You can find more information on these comparison matrices : Apache WS Stack Comparison and Xfire Comparison Matrix. (these two are probably very interesting to keep... unfortunately they do not contains any MSFT data. I had one in the past, but cannot find it... if you have such matrix feel free to post it in comment.)

Monday, December 10, 2007

Working on a large XML or SOA project: think about "separation of concerns"

With XML and SOA becoming mainstream in the enterprise XML operation such as Schema validations, XSL transformations are now very common. These specific operations are CPU intensive and could become a performance bottleneck when directly applied on the middleware. It could be even worst now when using SOAP based Web Services and their related WS-* standards. For example with WS-Security, XML encryption and signature is now more and more used in SOA based applications.

This is why many enterprise architects are bow looking for solutions to improve performances of XML centric applications.

One of the think we learn when developing application, and that Aspect Oriented Programming has highlighted is the concept of “separation of concerns”. It is key to keep that in mind also in global architecture in our case by separating the XML processing from the business logic. Hopefully it is most of the time done directly by the various Web Services framework you are using, you do not code the SOAP request/response, it is hidden by the Web Services framework.

However, in the current application server, the full XML treatment is made directly in the container, for example the XML Encryption is made in the same container that the place where the pure business logic is executed. So let’s find a solution to extract the most intensive XML processing into another part of the system.

Vendors have now in their catalog appliances that could do the job. The same way that today we are using SSL accelerators to deal with SSL encryption/decryption, we can put XML appliance to deal with the intensive CPU processing operation: XML validations, transformation, Ws-Security enforcing point,...

Architecture Overview
The overall architecture could be represented using the following schema :

The role of the XML/SOA Appliance varies a lot depending of your project:

  • Simple XML firewall to check the validity of the XML/SOAP messages
  • Web Services access control: lookup enterprise directory to check authentication and authorization. This could be based on the WS-Security standards and its various tokens (username, SAML, ...)
  • Content generation and transformation: the appliance can be used to serve various devices for example WAP cell phone or simple HTML Web Client. the XSL transformation is done in a very efficient way in the appliance directly.
  • Services Virtualization : it is possible to route the different messages to various end point depending of simple rules. (business or IT system rules)

As you can see from an architecture point of view, XML appliances are very interesting to distribute the heavy processing of XML to some specific hardware. I have noticed that sometimes developers/architects hesitate to put another piece of hardware/software in their design, but I do think that in this specific case it is probably a good move.

Separating the concern is quite easy and very clean when dealing with XML processing, but also it will allow the overall architecture to be managed in a better way. This kind of appliance will allow administrators to centralize the management of policies, and transformations. But also a side effect of this is the simple fact that when dealing with Web Services, you can easily add WS-* support to many stacks that do not support "them".

XML/SOA Appliances Offering
I have said earlier that vendors are offering such products, here some of the product that I have met or pushed:

What's next?
Some of you would probably raise the fact that the application server, especially when dealing with Web Services, must parse the XML/SOAP request even if this has been done by the appliance. Yes it is true, but I am sure that in a next future the vendors of such solution would optimize it by providing for example support for binary XML, or any other solution that will improve even more the performance of the overall IT in complex enterprise architecture. But for this application server must support binary XML first to avoid proprietary approaches.

Another point of view that I have not talk about is the possible support of such appliance around Web 2.0/Ajax optimization. I have not yet dive into this, but I am sure we can do very interesting things too.

Finally if you have experiences with any XML/SOA appliance feel free to post a comment about it, it will help the readers to see the interest (or not) around this topic.

Sunday, October 7, 2007

Paris "SOA Forum" feedback; and little comments about SOA projects

This week I have attended a SOA conference in Paris the SOA Forum. (I was not there in 2006). This event is not a technical event targeted towards developers but mainly oriented for IT managers and decision makers. This day was well attended, around 200 people. The content and more important the questions and round tables provide a good snapshot of how SOA is adopted.

If last year, based on comments that I can get, the message was "What & Why SOA?" this year I have the feeling that most of the audience was really familiarized with the SOA concepts -as I said earlier it is not a technical conference- and now they are more asking "How and When SOA?". Lot of discussions were about how to I start the projects, since in many case the SOA will impact the whole IT, and even more the full enterprise.

Thoughts about SOA project & approach

It is hard to say if the best way to start with SOA is starting from the Top (C level) or from the IT department on a departmental project. To be honest I think it will depend of each organizations; and depends of "why" SOA is a good fit for the enterprise.

I am tempted to say that if the choice is made for a "Time-To-Market" reason I believe that the project will start from a specific business need and be implemented in a "bottom-up" fashion., meaning the IT will quickly put together some services to give some agility to the business. This is something that I have seen many times in the telco industry.

At the other end, when the key factor is about rationalization of the business processes over the whole enterprise, the project is often manage at the IT management level if not even higher. This because this kind of approach will have impact on many departments/people.

Basically like in any project it is important to have:

  • good communication between actors that could be developers or departments
  • share the same goals
  • have an understanding of the technologies that will be used and their constraints.
If for the point 1 & 2 this is management that deals with this. For the 3rd one, we are closer to the technology where we can probably share the most -saying that because I believe that most of you, reader, are technical people. At the end of the day we do not build system with slideshows, but with products/solutions. So it is part of our job to take time to understand the pros/cons, limitations of the different products that will be involved in the project.

One example, is this week I have visited a customer and this customer wants to put in place an ESB to provide services to the different departments of the enterprise. Discussing at the global level of the architecture we all agreed on the different needs such as: connectivity to heterogeneous systems, transformation, routing, ...

Then the customer talk about "Web Services" again and again, this is where I have to say, I always try to slow down the discussion to set the expectation at the correct level, for example talking about impact on reliability, security of the HTTP/SOAP based Web Services. Don't get me wrong I am not saying that it is not possible to achieve correct QoS (Quality of Services) with Web Services but it could have an impact on the product choice, for example supporting WS-RM, WS-Security or even using proprietary approach for stateful Web Services, ... And the same comments, questions could occur with other part of the stack.

In conclusion, independently of the type of approach you are taking to put in place a Service Oriented Architecture, you will need sometimes to really understand well the product/solution you will be using to implement it. And for each of the options you will be choosing take some time to estimate the pros/cons and limitations of it. The same way you are taking time to list the different services, their granularity, their QoS, you need to take some time to analyze the different solution. For example when you choose to use an ESB, BPEL engine with their connectivity capabilities, what are the best way to connect to a system (SOAP, JMS, JDBC, JCA, Java, ..), how to code the logic (Java, BPEL, business rules, ...) and for each of this question think about the impact of it on your system. For example, how portable will be my code/business process, and is it important for me?

Thursday, February 15, 2007

Oracle Web Services: Sharing Session between client calls

OracleAS Web Services Runtime provides a support for stateful Web Services that is based on HTTP /Servlet session. Some people will probably say that Web Services should not be stateful, or at least not based on the protocol... However, today most of Web Services are using HTTP, and in some specific cases it is very useful to be able to have a state.

In this post, I am not explaining how to enable stateful services and clients, since it is documented in the Java Classes and Stateful Web Services chapter of the developer guide. Here I am show you how you can using client side programming share the same state (session) between different web services calls (even different services running in the same server side application).

The tip used here is about the association of cookies to the client instance (JAX-WS Stub or Call object). Here the code you have to write to do that using DII, will be very similar when using static Stub

1. Enable the state management

...
Service service = sf.createService(qName);
QName port = new QName("CartService");
Call call = service.createCall(port);
call.setProperty(Stub.SESSION_MAINTAIN_PROPERTY, Boolean.valueOf(true));  // this is necessary to be able to manipulate cookie
...

2. Create a Map that contains the Cookies and assign it to the call (or Stub)

... Map cookieMap = new HashMap();
call.setProperty(ClientConstants.COOKIE_MAP, cookieMap);
...

This specific step associates a map that will contains all the cookie with the call/stub instance. You will be able then to manipulate the Map to get or set the cookies.

3. How to get the JSESSION cookie

private Cookie getJSessionCookie(Call call) {
   Map cookies = (Map)call.getProperty(ClientConstants.COOKIE_MAP);

   if (cookies != null && !cookies.isEmpty()) {
       Iterator it =  cookies.values().iterator();
       while (it.hasNext()) {
           Cookie cookie = (Cookie)it.next();
           if (cookie.getName().equals("JSESSIONID")) {
               return cookie;
           }
       }
   }

   return null;
}

Note that the Cookie object is an instance of Oracle HTTPClient.Cookie.

4. Utilizing the Cookie

So now you have all the information to be able to get the Session information when the stateful conversation has started;

In this example each time the call.invoke() is done, a counter is incremented on the server.

Call call = service.createCall(port);
call.setProperty(Stub.SESSION_MAINTAIN_PROPERTY, Boolean.valueOf(true));  // this is necessary to be able to manipulate cookie
 Map cookieMap = new HashMap();
call.setProperty(ClientConstants.COOKIE_MAP, cookieMap);
... // The session will only be created after the first invoke
 call.invoke(...); // counter = 1 call.invoke(...); // counter = 2 since on the same session

... // the session is now created so you can get the cookie
 Cookie mySession = getJSessionCookie(call)
...

You can now use the cookie in another call using the following code:

mySession ..  // was extracted from the call #1
...// now I am creating a new call instance (myNewCall) that could be in another class
Call myNewCall = service.createCall(port);
myNewCall.setProperty(Stub.SESSION_MAINTAIN_PROPERTY, Boolean.valueOf(true));  // this is necessary to be able to manipulate cookie
Map cookieMap = new HashMap();
// add the cookie to the map this will add the cookie to the HTTP request so it will be associated to the same session (/state)
cookieMap.put(mySession,mySession);// associate the cookie Map to the call
myNewCall.setProperty(ClientConstants.COOKIE_MAP, cookieMap);
...
myNewCall.invoke;  // counter = 3 since we share the same session
...
Using this sample you have 2 instances of a client calling a service and reusing the same session -state-. You can also use the same approach to have 2 different clients talking to different services and share the same session. To do that you will have on the server side to use the HTTP Session directly to store your data between calls, and share it between services.

Sunday, January 7, 2007

How to use SOAP Compression using JAX-RPC, on OC4J

HTTP compression has improved a lot the download time of content from servers. In the context of Web Service it could be very interesting to also use HTTP compression to improve the network traffic. Firs, I am explaining how to compress a SOAP response when you have a Web Service running in Oracle Containers for J2EE (OC4J) using a generic servlet filter. I have to give credit to http://www.thomas-bayer.com/ since he has created the Filter and documented how to do such thing using Axis. 

So you can take a look to the following article for more details, you can read the 2 following article, or jump to the next paragraph that explains how to configure your JAX-RPC based service to send compressed HTTP response.

In this sample I am showing how to compress the SOAP response using a servlet filter, it is also possible to use some other Oracle infrastructure element to achieve that such as Oracle HTTP Server/Apache, or Oracle Webcache.

1- Install the compression filter library in your application

    Download the compression filter library 2wayfilter-1.2.jar and copy it into the Web application's WEB-INF/lib folder

2- Configure your application to use the filter

    The configuration of a servlet filter is done using the web.xml where you reference which servlet or URL will be using the filter. As you may knowin JAX-RPC, the HTTP endpoint of a service are exposed as servlet and defined in the web.xml. You can choose to compress all the endpoint/URL or create a new servlet mapping, that will become a new SOAP endpoint and only compress this one. If you take the option of creating a new endpoint keep in mind that it will not be added to the WSDL automatically, so the client application will have to point explicitly to the compressed endpoint URL to take benefits of it.

<web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
     version="2.4">
    <servlet>
        <description>Web Service CustomerServiceSoapHttpPort</description>
        <display-name>Web Service CustomerServiceSoapHttpPort</display-name>
        <servlet-name>CustomerServiceSoapHttpPort</servlet-name>
        <servlet-class>demo.oracle.CustomerServiceImpl</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>CustomerServiceSoapHttpPort</servlet-name>
        <url-pattern>CustomerServiceSoapHttpPort</url-pattern>
    </servlet-mapping>
   
    <!-- New servlet mapping to handle compressed SOAP Messages -->
    <servlet-mapping>
        <servlet-name>CustomerServiceSoapHttpPort</servlet-name>
        <url-pattern>CompressedCustomerServiceSoapHttpPort</url-pattern>
    </servlet-mapping>

   
    <!-- Filter definition with mapping on the compressed endpoint -->
    <filter>
        <filter-name>2WayFilter</filter-name>
        <filter-class>com.osmoticweb.gzipfilter.GZIP2WayFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>2WayFilter</filter-name>
        <url-pattern>CompressedCustomerServiceSoapHttpPort</url-pattern>
    </filter-mapping>   
   
</web-app>

You can now package and deploy your application.

3- Create & Invoke the service

In this basic configuration you have only changed the servlet that is the HTTP endpoint of your service. So the compressed endpoint is not present in the WSDL, but you can use any of the URL to create your proxy.

When you have created your proxy, if you want to access the endpoint that will return the compressed response you must be sure that you are calling the correct endpoint. You can set the endpoint using the setEndpoint method, of your Web Service client.

This is it!
I will in a next post explain how you can using the Oracle Web Service client API send a compressed request that will have to be uncompressed on the server using the same filter.

Tuesday, December 26, 2006

SOAP Client: A simple Web Services testing tools for Mac

I was discussing with a friend about SOAP testing tools. We all know SOAP UI that is a very powerful one, but I am also using a very simple one developed on Mac for Mac (cocoa based application), this application is SOAP Client:

Monday, December 4, 2006

Calling a Web Services Protected using HTTP Basic

WS-Security provides a way to protect Web Services at the message level (SOAP) and it is independent of the protocol used (HTTP, JMS, ...). However, some services are still using HTTP based authentication for protection. JAX-RPC and its Oracle implementation provides a way to set the username and password in the client (Stub) using some properties on the Stub.

             ((Stub)port)._setProperty(Stub.USERNAME_PROPERTY, "username");
             ((Stub)port)._setProperty(Stub.PASSWORD_PROPERTY, "password");           

That's it...

Theses properties are shortcuts to the standard JAX-RPC properties:

                javax.xml.rpc.security.auth.username
                javax.xml.rpc.security.auth.password

This code is the same when you are using the Call interface.

Monday, November 13, 2006

IBM article: JAX-RPC vs JAX-WS

I was discussing with a customer not familiar with the JAX-WS standard. I was writing him a mail explaining the difference when I found this nice article on the IBM DeveloperWorks library: * Web services hints and tips: JAX-RPC vs JAX-WS It is an opportunity for me to remind OracleAS users that the 10.1.3.1 stack in addition to the JAX-RPC support also provides support for: * Attachments with MTOM, Soap with Attachment and DIME * Annotations based development (JSR-181) that is part of JAX-WS * WS-Security and WS-Reliability

Friday, October 13, 2006

Using HTTPS with Web Services

Prerequisites:
In this article you have

  • already a Web Service deployed in OC4J that is running on the default HTTP port. The WSDL and Endpoint are available. In my sample the non secure Web Service endpoint is: http://127.0.0.1:8888/math-service/MathServiceSoapHttpPort

Add HTTPS to OC4J

Creating of the Keystore

The first thing to do to secure OC4J would be to create a new keystore that will contain the different certificates. The easiest way to do that for a Java developer is to use SUN's keytool:
keytool -genkey -alias oracle-server -dname "CN=Tug Grall, OU=Blog O=Grall And Co L=Redwood Shores, S=CA, C=US" -keyalg RSA -keypass welcome -storepass welcome -keystore server.keystore
You can copy the server.keystore into the $ORACLE_HOME/j2ee/home/config to simplify the next steps.


Configuring OC4J

OC4J stand alone is using the notion of Web-Site to expose HTTP resources (Web Applications). The default-web-site is define is he $ORACLE_HOME/j2ee/home/config/default-web-site.xml. To secure an OC4J you can follow the steps describe in the OC4J Security guide that I have summarized in the following section.

What we want to achieve for the purpose of the demonstration is to have OC4J using HTTP and HTTPS, on port 8888 and 4443 for example.

1. Copy default-web-site.xml to  secure-web-site.xml

2. Edit the secure-web-site.xml:
    2.1. Change the web-site tag by changing the port to 4443 and adding the element secure="true"
    2.1. Add the ssl-config element and point this to the new created keystore.
    The file looks like:

<web-site   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:noNamespaceSchemaLocation="http://xmlns.oracle.com/oracleas/schema/web-site-10_0.xsd"
            port="4443"
            secure="true"
            display-name="OC4J 10g (10.1.3) Default Web Site"
            schema-major-version="10"
            schema-minor-version="0" >
        ...
        <ssl-config keystore="server.keystore" keystore-password="welcome" />
        ...
</web-site>

3. Import the new Web site in your OC4J instance by editing the $ORACLE_HOME/j2ee/home/server.xml file. You need to add or replace the web-site tag. In my case I want to add the secure web site to my instance so the configuration looks like:

    ...   
    <web-site default="true" path="./default-web-site.xml" />
    <web-site path="./secure-web-site.xml" />
    ...

Since we have copied the file from the default-web-site, all applications are available using HTTP and HTTPS

Start OC4J and test the HTTPS port

Start OC4J using the standard Java command or shell script, I am adding the Java Network debug flag that would help you to see what is happening at the SSL level.

    java -Djavax.net.debug=ssl -jar oc4j.jar

You should be able to access the service WSDL using the HTTPS port for example in my case:
  •     https://127.0.0.1:4443/math-service/MathServiceSoapHttpPort?WSDL


Consuming the Service using HTTPS

Generate and configure a client Keystore

Event if this is possible to use the same keystore for the server and the client, I will guide you in the steps to create a client certificate and import the certificate from the existing -server- one. Here the command to create a new keystore:
keytool -genkey -alias oracle-client -dname "CN=John Doe, OU=Blog O=MyDummyClient, S=CA, C=US" -keyalg RSA -keypass welcomeClient -storepass welcomeClient -keystore client.keystore

The next step is to export the certificate from the server keystore to be able to import it in the client:
keytool -keystore server.keystore -export -alias oracle-server -file server.cer

You can now import the cerificate in the client keystore:
keytool -keystore client.keystore -import -file server.cer

Generate the proxy

You have now the client certificate so you can use the Oracle Web Service Assembler to generate the proxy. The only specific thing you have to do is to specify which key store to use when running the tool. The command to use when generating the proxy is:

java -Djavax.net.ssl.trustStore=/Users/tgrall/ssl/client.keystore
     -Djavax.net.ssl.keyStore=/Users/tgrall/ssl/client.keystore
     -Djavax.net.ssl.trustStorePassword=welcomeClient
     -Djavax.net.ssl.keyStorePassword=welcomeClient
     -jar $ORACLE_HOME/webservices/lib/wsa.jar
     -genProxy
     -wsdl https://127.0.0.1:4443/math-service/MathServiceSoapHttpPort?WSDL


Calling the Service using secure endpoint

Configure the Java Environment to use the client store is made using the following System properties:
  • javax.net.ssl.trustStore
  • javax.net.ssl.keyStore
  • javax.net.ssl.trustStorePassword
  • javax.net.ssl.keyStorePassword
       
This could be done using different approach, property file, -D command line parameter or programmatically. To simply the example I am using the programmatic approach, the following code is part of the main method of the Client class:
  ...
   System.setProperty("javax.net.ssl.trustStore", "/Users/tgrall/ssl/client.keystore");
   System.setProperty("javax.net.ssl.keyStore", "/Users/tgrall/ssl/client.keystore");
   System.setProperty("javax.net.ssl.trustStorePassword", "welcomeClient");
   System.setProperty("javax.net.ssl.keyStorePassword", "welcomeClient");
   ...
   // Adding Debug information
   
System.setProperty("javax.net.debug", "ssl");
   ...


It is possible to change the Endpoint dynamically in the Proxy using the setEndpoint method.
  ...
  democlient.proxy.MathServiceSoapHttpPortClient myPort = new democlient.proxy.MathServiceSoapHttpPortClient();
  ...
  String ep = "https://127.0.0.1:4443/math-service/MathServiceSoapHttpPort";
  myPort.setEndpoint(ep);
  System.out.println("Result of the operation is "+ myPort.add(2,2));
  ...


You should now be able to run the client and call the service using HTTPS. This would look like:

Wednesday, October 4, 2006

Configuring the SOAP Address in OracleAS Web Services

When a JAX-RPC service is developped using OracleAS 10g R3 stack, the service URL http://server:port/context/serviceName, provide access to a test page and to the WSDL by adding the ?wsdl parameter to the URL. You can then use this URL to create services client with your tools of choice.

If you take a look to the WSDL, the SOAP address of the SOAP HTTP Port is dynamically generated based on the calling URL, for example if you have a service running on your machine:

http://127.0.0.1:8888/math-service/MathServiceSoapHttpPort?WSDL
will generate the following information in the WSDL
<service name="MathService">
    <port name="MathServiceSoapHttpPort" binding="tns:MathServiceSoapHttp">
        <soap:address location="http://127.0.0.1:8888/math-service/MathServiceSoapHttpPort"/>
    </port>
</service>

But if you are using another URL, for example the name of the computer:
http://tgrall-computer:8888/math-service/MathServiceSoapHttpPort?WSDL
will generate:
<service name="MathService">
    <port name="MathServiceSoapHttpPort" binding="tns:MathServiceSoapHttp">
        <soap:address location="http://tgrall-computer:8888/math-service/MathServiceSoapHttpPort"/>
    </port>
</service>

However in some case you may want to hard code this value to a specific location,for example to be sure that user will use the internet visible name, (no IP or intranet name), to do such thing you can use the  oracle-webservice.xml file and th <web-site> tag. This deployment descriptor is used to configure the service at runtime. In the following example I am forcing the service to use a new hostname and port:

<oracle-webservices xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"      .... >
    <web-site host="www.grallandco.com" port="80" />
    <webservice-description name="MathService">
        ...
        ...
    </webservice-description>
</oracle-webservices>...

This element and all other Oracle Web Services configuration elements are documented in the Oracle Web Service Developer Guide.

Thursday, September 21, 2006

Accessing User Principal in a Web Service

WS-Security provides a standard way to secure Web Services. Since based on SOAP it is agnostic of the stack you are using. When using JAX-RPC implementation, you are running in a J2EE container. In this post I am giving a tip to access the Principal object.

I have a service service, and I need to access some user information in its implementation class ( org.tug.ws.sample.SimpleServiceImpl ). This service is secure with WS-Security, with for example simple authentication, the following screenshot, is the configuration of inbound security in OracleAS 10gR3:

em-ws-sec-001


So the service is secured, here the code that you have to add in your service implementation (or handlers) to access the Principal object.

  1. Implement javax.xml.rpc.server.ServiceLifecycle
  2. Implement the init(Object context) method to access the ServletEndpointContext, that you can for example put as a local member of your implementation class.
        public void init(Object context) {
            _servleContext = (ServletEndpointContext)context;
        }
  3. Then you can access the principal object using the getUserPrincipal() method:
            ...
            if (_servleContext.getUserPrincipal() != null ) {
                Principal userPrincipal = _servleContext.getUserPrincipal();
                ...
            }
            ...
     
You can find more information about the Security in J2EE 1.4 Web Services in the Designing Web Services with the J2EE 1.4 Platform tutorial. 
Update on Wednesday october 4th: Frank Nimphius, has use this entry to create a more detail article about End to End Security with Web Services Security.

Thursday, March 2, 2006

Oracle Fusion Middleware and Microsoft Interoperability - Developer's Guide

Download the Beta version of the Oracle Application Server Developer's Guide for Microsoft Office Interoperability along with sample code (and other technical resources) from this new OTN page.

  • Windows Platform: Fusion Middleware is concurrently tested and delivered on Windows.
  • .NET/Windows Server System Integration: Fusion Middleware offers broad integration with Microsoft .NET and Windows Server System at multiple levels.
  • Office Interoperability: Fusion Middleware enables use of Office as the front-end for enterprise applications, as well as many ways to interact with enterprise information that can be read, parsed, and generated in Office-formatted documents.

Thursday, December 22, 2005

SearchWebServices: Oracle's Steve Harris on Java and standing out in SOA, part 1

Interested to know more about the Oracle Application Server 10g and the SOA/Java strategy? Take some time to read the SearchWebServices.com interview with Steve Harris, VP of the Java Platform Group at Oracle.     Oracle's Steve Harris on Java and standing out in SOA, part 1 Addition on 30/12: follow TheServerServide discussion

Tuesday, September 27, 2005

Publishing SQL and DML as Web Service

This morning I have been talking about the Oracle Database and Web Services. If you are Oracle 10g developer (Database or Application Server) you probably already know that you can publish PL/SQL stored procedure as Web Services... One of the new feature of our OracleAS 10.1.3 release is the fact that now you can publish SQL and DML as well. In this post I am quickly explaining the basic steps to publish a query as Web Service.

Oracle Web Service Assembler

If you are not familiar with the Oracle Web Services tools, or if you are using Oracle JDeveloper to generate your services and client, I would like to use the Oracle WS command line utility to do the work here. The Oracle Web Services Assembler, aka WSA, allows you to generate client and server using Oracle JAX-RPC implementation and extensions.

WSA is a Java utility that can be used as command line or with Apache Ant, basically it is a Jar file located in $ORACLE_HOME/webservices/lib/wsa.jar. Type the following command in a terminal to learn more about WSA.

java -jar $ORACLE_HOME/webservices/lib/wsa.jar -help
Usage:
java -jar wsa.jar -<command> -debug -help
where command can be one of:
        analyze
        annotationAssemble
        aqAssemble
        assemble
        corbaAssemble
        dbJavaAssemble
        ejbAssemble
        fetchWsdl
        genApplicationDescriptor
        genConcreteWsdl
        genDDs
        genGatewayService
        genInterface
        genProxy
        genQosWsdl
        genValueType
        genWsdl
        help
        jmsAssemble
        plsqlAssemble
        sqlAssemble
        topDownAssemble
        version
As you can see with the different command options, Oracle WAS allows you to do "everything" Web Services related, for example creating a WS from an EJB using ejbAssemble, from a stored procedure using plsqlAssemble... and I let you guess, we will be using sqlAssemble for this specific demo.

To have the detail of all the parameters of each command you can just enter
java -jar $ORACLE_HOME/webservices/lib/wsa.jar -[command] -help

Generating the Web Service from a SQL

So you can easily generate a Web Service using WSA from multiple SQL statements, to do it, just use the following command:
java -jar wsa.jar -sqlAssemble
                       -appName my-soaql-application
                       -dataSource jdbc/MyDBServices
                       -sqlStatement "getAllEmp=select ename, sal from emp"
                       -sqlStatement "getEmpByDept=select ename, sal from emp where DEPTNO = :{dept NUMBER}"
                       -dbConnection jdbc:oracle:thin:@localhost:1521:orcl
                       -dbUser scott/tiger
So WSA has created the different classes needed by the Web Service but also packaged in a EAR file that you can now deploy to your OracleAS instance. The appName parameter is used to generate the different application name and files (EAR and WAR). The sqlStatement used to specify the different queries you want to publish as operation.


Deploying the application

You can either use Oracle EM Application Server Control to deploy the application or using the command line utility, admin.jar

> java -jar $ORACLE_HOME/j2ee/home/admin.jar ormi://hostName[:ormiPort] oc4jadmin password -deploy -file my-soaql-application -deploymentName my-soaql-application

> java -jar $ORACLE_HOME/j2ee/home/admin.jar ormi://hostName[:ormiPort] oc4jadmin password  -bindWebApp my-soaql-application my-soaql-application-web default-web-site /soaql
Also be sure that you have a datasource defined in your application server that match the parameters set when you ran the WSA command, in my case it will be jdbc/MyDBServices that connection to my local database using the SCOTT schema.

You should now be able to access the service using the following URL:
  • http://youserver:port/soaql/my-soaql-application

What is going on?

When you are running the Web Service that is deployed inside OracleAS the flow is quite simple:
  1. A client is sending a request to the server using SOAP. So it uses the different typed as defined in the payload
  2. The JAX-RPC Servlet processes the request and deserializes the message
  3. The generated classes use the OC4J DataSource to connect to the database and execute the statement using JDBC
  4. The database sends the data to the classes, and servlet that creates a SOAP response

When you access the test page ( http://youserver:port/soaql/my-soaql-application )  or when you are viewing the generated WSDL you probably notice that each query is published with 3 different operations. These operations return the same data but using different formats:
  • <operationName>Bean : returns the data as serialize Javabean
  • <operationName>XML : returns the data in the SOAP body as Rowset/Row structure
  • <operationName>XMLRowSet : returns the data in the SOAP body using the WebRowset format (JSR-114)

Summary

In this small article you have learnt how to pulish a SQL statement as Web Service. It is interesting to take a look closely to the WSA tools that give you several way of building Web Services, starting from SQL, Stored Procedure, Java, EJB, or using a contract based approach starting from the WSDL.

Sunday, May 29, 2005

Good Bye JAX-RPC, weclome to JAX-WS

Finally the Java specification about Web Service will have a name that makes sense... moving away from JAX-RPC to JAX-WS (JAX Web Services)...

The JAX-RPC name, which stands for Java API for XML-based RPC, is misleading because developers assume it is only about RPC, according to Doug Kohlert, a Sun staff engineer, in his blog this week. “By renaming JAX-RPC to JAX-WS, we can eliminate this confusion,” Kohlert wrote. JAX-WS stands for Java API for XML Web Services.
This infoworld article will give you more details.

Thursday, April 28, 2005

Web Services and SOA Web Site

I was yesterday talking to a customer about Web Services and Services Oriented Architecture, and he was looking for more information. So I shared with him one of my bookmark.

http://www.service-architecture.com/ is a Web site dedicated to WS and SOA with lof of articles that defines for example most of the WS-* acronyms.