Pages

Saturday, April 11, 2009

Changing WSDL url ( endpoint) in JAX-WS client

In JDeveloper 11G you can easily generate a JAX-WS client, just create a new Web Service proxy client and use the WSDL Url. This client works perfectly in your test environment but when you want to deploy this to an other environment then you will get IO errors. This is because JDeveloper generates JAX-WS client code with a WSDL Url.Off course you can change this file with the new WSDL Url but you can also change the endpoint url. IMPORTANT this only works when the original WSDL Url is still accessible. So don't use this.

@WebServiceRef
private static HelloWorldService helloWorldService;

public static void main(String [] args)
{
String newAddress = System.getProperty("wsdlurl");
helloWorldService = new HelloWorldService();
HelloWorld helloWorld = helloWorldService.getHelloWorldPort();
System.out.println("old address "+((BindingProvider)helloWorld).getRequestContext().get(BindingProvider.ENDPOINT_ADDRESS_PROPERTY));
((BindingProvider)helloWorld).getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY , newAddress);

System.out.println(helloWorld.sayHello());


The other and better way is to use the other proxy client constructor and provide the new WDSL url.

@WebServiceRef
private static HelloWorldService helloWorldService;

public static void main(String [] args)
{
String newAddress = System.getProperty("wsdlurl");
try {
helloWorldService = new HelloWorldService( new URL(newAddress)
, new QName("http://ws.whitehorses.nl/", "HelloWorldService"));
} catch (MalformedURLException e) {
e.printStackTrace();
}
HelloWorld helloWorld = helloWorldService.getHelloWorldPort();
System.out.println(helloWorld.sayHello());
}

The last way ( if you use the jax-ws-client in a web application) is to add a jax-ws-catalog.xml file to the ear deployment of your web application, this will replace the WSDL url at runtime.
the file looks like this. See Gerard Devision blog for more information.

<?xml version="1.0" encoding="ISO-8859-1" ?>
<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog" prefer="system">
<system systemId="http://localhost:7101/ws_helloworld-Project1-context-root/HelloWorldServicePort?wsdl"
uri="http://localhost:7001/ws_helloworld/HelloWorldServicePort?WSDL"/>
</catalog>

Monday, April 6, 2009

Create a 11G EJB Project with EclipseLink

In JDeveloper 11G you can off course create an ADF BC model project for your ADF Webapp but why don't you use an EJB model project with EclipseLink, it is not so difficult. For this blog entry I made a document with the screenshots of the step you need to do to make an EJB model project. After this you can read this blog how to use this in ADF.

Here are the steps I did for this model project based on the HR demo schema.
The first step is to create the EJB project and generate the entity classes.
Change the database and datasource settings in the persistence xml.

Add the relations manually between the department and employee entities.

Add the Oracle sequences definitions to the primary keys
Add a new named query to the entity

Create an session bean

And make an EJB client to test the session.
Here is the example workspace and the document with all the steps and here is the code of my test client where I create a department with two employees.

package nl.whitehorses.eclipselink.model.client;

import java.sql.Timestamp;

import java.util.Date;
import java.util.Hashtable;
import java.util.List;

import javax.naming.Context;
import javax.naming.InitialContext;

import javax.naming.NamingException;

import nl.whitehorses.eclipselink.model.entities.Departments;
import nl.whitehorses.eclipselink.model.entities.Employees;
import nl.whitehorses.eclipselink.model.services.HrSession;

public class HrSessionClient {
public static void main(String [] args) {
try {
final Context context = getInitialContext();
HrSession hrSession = (HrSession)context.lookup("Eclipselink-HrSession#nl.whitehorses.eclipselink.model.services.HrSession");


// insert new department
Departments department = new Departments();
department.setDepartmentName("Sales");
department.setLocationId(1700L);
department.setManagerId(200L);
department = (Departments)hrSession.mergeEntity(department);
System.out.println("new department id: "+department.getDepartmentId());

// add a new employee
Employees employee1 = new Employees();
employee1.setEmail("Test1@test.nl");
employee1.setLastName("Test1");
employee1.setJobId("ST_MAN");
employee1.setHireDate(new Timestamp(new Date().getTime()));

department.addEmployees(employee1);
department = (Departments)hrSession.mergeEntity(department);

// add a other new employee
Employees employee2 = new Employees();
employee2.setEmail("Test2@test.nl");
employee2.setLastName("Test2");
employee2.setJobId("ST_MAN");
employee2.setHireDate(new Timestamp(new Date().getTime()));
employee2.setDepartment(department);

department.getEmployees().add(employee2);
department = (Departments)hrSession.mergeEntity(department);

// retrieving the new department with its employees
for (Departments departments : (List<Departments>)hrSession.queryDepartmentsFindOne( department.getDepartmentId())) {
System.out.println( "departmentId = " + departments.getDepartmentId() );
System.out.println( "departmentName = " + departments.getDepartmentName() );
System.out.println( "locationId = " + departments.getLocationId() );
System.out.println( "managerId = " + departments.getManagerId() );
for (Employees employees : departments.getEmployees()) {
System.out.println( "employeeId = " + employees.getEmployeeId() );
System.out.println( "commissionPct = " + employees.getCommissionPct() );
System.out.println( "email = " + employees.getEmail() );
System.out.println( "firstName = " + employees.getFirstName() );
System.out.println( "hireDate = " + employees.getHireDate() );
}

}



} catch (Exception ex) {
ex.printStackTrace();
}
}

private static Context getInitialContext() throws NamingException {
Hashtable env = new Hashtable();
// WebLogic Server 10.x connection details
env.put( Context.INITIAL_CONTEXT_FACTORY, "weblogic.jndi.WLInitialContextFactory" );
env.put(Context.PROVIDER_URL, "t3://127.0.0.1:7101");
return new InitialContext( env );
}
}

Thursday, April 2, 2009

XSD validation and exception handling in OSB

In OSB ( Oracle Service Bus , aqualogic service bus ) it is relative easy to add schema validation to your proxy service and to make a custom exception handling for this validation. Just follow the next steps. First in this example I use these xml schema's for the request and response operation.
The request xsd

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns="http://whitehorses.nl/request"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://whitehorses.nl/request"
elementFormDefault="qualified"
attributeFormDefault="unqualified">
<xs:element name="request">
<xs:complexType>
<xs:sequence>
<xs:element name="runid" type="xs:short"/>
<xs:element name="message" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>

And the response xsd

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns="http://whitehorses.nl/response"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://whitehorses.nl/response"
elementFormDefault="qualified"
attributeFormDefault="unqualified">
<xs:element name="response">
<xs:complexType>
<xs:sequence>
<xs:element name="runid" type="xs:short"/>
<xs:element name="message" type="xs:string" minOccurs="0"/>
<xs:element name="errorid" type="xs:string" minOccurs="0"/>
<xs:element name="error" type="xs:anyType" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>

When everything goes well I will only return the runid element else we get the full message with the errorcode. With these xsd's I made a simple WSDL which I can use in the proxy service.

First part of this blog entry is to make the happy flow when this works we can add the xsd validation.
Make a new proxy service and use this WSDL.
The next step is to make a simple business service with file transport

In my case I put the request xml in the c drive temp folder.

Go back to your proxy service where we create a new message flow.


Add a route-node to the flow with inside a new routing. This routing will call the file business service.

Add an assign component to request action flow so I can retrieve the runid from the request and add this to the runid variable. This variable I can use for the response.
To make a return message I add an assign to the response action. Now I add the response template xml to the body variable.

Add an insert to the response action after the assign. In this insert we will add the runid of the request to the runid of the response message.


The first part is finished, you service should work now. In the second part we will add the XSD validation.
To make a custom exception handling for the xsd we need to add a Pipeline Pair node.
In the request pipeline I will add a new stage.

In this stage I use the validation component. Now we have to select an element in the body variable which OSB will validate against the XSD. Provide the XSD and use the raise error option.

Add an error handler to this stage.

Add a new stage in the error handler

First we add an assign to the stage to retrieve the runid of the request message so I can use this for the response.

Add a second assign to the stage. In this assign I will add the response template xml to the body variable.

Add the runid to the response xml

Add the error details to the response xml

And the error code



With the reply we can give back the response xml back to the client. Very important report no error because this is a handled exception.

The second part is also finished, we only have to test this proxy service by adding a unknow element to the request and look at the response. Here is a picture of the result.