Saturday, May 31, 2008

Webservice endpoint

The Java JAX-RPC implementation used to create simple to use web service clients, where developer can easily change the web service endpoint as shown below-

MyWsImpl stub = new MyWsImplService_Impl().getXXX();
((Stub) stub)._setProperty(Stub.ENDPOINT_ADDRESS_PROPERTY, "http://myHost/myWs/myWs");

See this entry for details about building JAX-RPC web services.

The JAX-WS has changed the way it generates the clients. As a general practice people keep the WSDL along with their code and create the client side stubs at the build time. The JAX-WS hard codes the WSDL path in the client stub. See the one such generated code below-
package cache;

import java.net.MalformedURLException;
import java.net.URL;
import java.util.logging.Logger;

import javax.xml.namespace.QName;
import javax.xml.ws.Service;
import javax.xml.ws.WebServiceClient;

@WebServiceClient(name = "MyServiceImplService", targetNamespace = "http://c.b.a/", wsdlLocation = "file:/D:/Test/temp/wsdl/MyServiceImplService.wsdl")
public class MyServiceImplService extends Service {

private final static URL MYSERVICEIMPLSERVICE_WSDL_LOCATION;
private final static Logger logger = Logger
.getLogger(MyServiceImplService.class.getName());

static {
URL url = null;
try {
URL baseUrl;
baseUrl = MyServiceImplService.class.getResource(".");
url = new URL(baseUrl,
"file:/D:/Test/temp/wsdl/MyServiceImplService.wsdl");
} catch (MalformedURLException e) {
logger.warning("Failed to create URL for the wsdl Location: 'file:/D:/Test/temp/wsdl/MyServiceImplService.wsdl', retrying as a local file");
logger.warning(e.getMessage());
}
MYSERVICEIMPLSERVICE_WSDL_LOCATION = url;
}

public MyServiceImplService(URL wsdlLocation, QName serviceName) {
super(wsdlLocation, serviceName);
}

public MyServiceImplService() {
super(MYSERVICEIMPLSERVICE_WSDL_LOCATION, new QName("http://c.b.a/",
"MyServiceImplService"));
}
}
If one tries to create an instance of client using the default constructor then it looks for the WSDL file at the location hard coded in the class and might fail with FileNotFoundException. The workaround for this problem is to call the another consturcutor, passing the endpoint URL and QName. Creating this QName is quite annoying and also that may change in future changes to WSDL. Then what is the easy wayout?

If you look closely at the web service client, it has an annotation @WebServiceClient, which has all the information to create the QName dynamically.
WebServiceClient ann = MyServiceImplService.class
.getAnnotation(WebServiceClient.class);
MyServiceImplService service = new MyServiceImplService(
new URL("ENDPOINT URL OF MY SERVICE"),
new QName(ann.targetNamespace(), ann.name()));

Now it looks pretty simple, is not it?

Wednesday, May 28, 2008

Proxy authentication in Java

The usual corporate networks provide internet access via proxy servers and at times they require authentication as well. May applications do open the connections to servers which are external to the corporate intranet. So one has to do proxy authentication programmatically. Fortunately Java provides a transparent mechanism to do proxy authentications.

Create a simple class like below-

import java.net.Authenticator;

class ProxyAuthenticator extends Authenticator {

private String user, password;

public ProxyAuthenticator(String user, String password) {
this.user = user;
this.password = password;
}

protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(user, password.toCharArray());
}
}
and put these lines of code before your code opens an URLConnection-
Authenticator.setDefault(new ProxyAuthenticator("user", "password"));
System.setProperty("http.proxyHost", "proxy host");
System.setProperty("http.proxyPort", "port");

Now all calls will successfully pass through the proxy authentication.

Monday, May 05, 2008

@Stateless + @WebService +Weblogic 10 = :-(

On my last project we have to expose some stateless session beans as web service as well. The deployment platform was Weblogic 10 MP1. For the initial few weeks everything (development, deployment and testing) went fine and then all of a sudden Weblogic refused to deploy couple of EJBs without any error messages. The general observation is, if a class has both @Stateless and @WebService on a single java class and number of code lines grow beyond some limit (our classes have around 350 lines) then Weblogic has issues with them. If we reduced the code by commenting out some code or removing some methods then deployment went well.

This is not the only issue with Weblogic, one more equally weird observation is that @EJB annotations does not work when a class has both @Stateless and @WebService.