Consuming a cached WSDL in Java EE

Dinsdag 27 oktober 2009  |  Door Bart Matthaei

I ran into an interesting problem while I was working on a prototype for Ziggo, one of our clients. The project involves a Java EE application that consumes a lot of other webservices within the Ziggo network, combining gathered information into a usable set.

Since some webservices are actually running on multiple hosts, the port endpoint in WSDL wasn't always correct in some cases. I found a neat little trick to fix things, and support multiple endpoints for one wsdl file. Thanks google!

In this case we're trying to consume a CoffeeService. We've downloaded the WSDL file for the service, and packaged it in the JAR file. Then we used wsimport to construct proxy classes so we can use the webservice in our session bean.

In our case, the CoffeeService class contained a gibberish WSDL location, so running new CoffeeService() would have given us a nice error about Java not being able to find the WSDL file:


/**
 * This class was generated by the JAXWS SI.
 * JAX-WS RI 2.0_01-b59-fcs
 * Generated source version: 2.0
 * 
 */
@WebServiceClient(name = "CoffeeService", targetNamespace = "http://coffee.nl/i/like/it", wsdlLocation = "wsdl/CoffeeService.wsdl")
public class CoffeeService
    extends Service
{

    private final static URL COFFEESERVICE_WSDL_LOCATION;

    static {
        URL url = null;
        try {
            url = new URL("file:/Users/bart/Java/jaxws-ri/bin/wsdl/CoffeeService.wsdl"); // OH-OH!
        } catch (MalformedURLException e) {
            e.printStackTrace();
        }
        COFFEESERVICE_WSDL_LOCATION = url;
    }

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

    public CoffeeService() {
        super(COFFEESERVICE_WSDL_LOCATION, new QName("http://coffee.nl/i/like/it", "CoffeeService"));
    }


.... other stuff ....
}

The URL points to a local file on my Macbook Pro, and doesn't exist on a production machine. The following implementation shows a nice way to circumvent the problem:


@Stateless
public class CoffeeBean implements CoffeeBeanLocal {

	private static CoffeeServicePort port;
	
	static {

		Class<CoffeeService> c = CoffeeService.class;
		
		// Get the webservice annotations, so we can construct a QName.
		WebServiceClient wsClient = (WebServiceClient)c.getAnnotation(WebServiceClient.class);
		QName name = new QName(wsClient.targetNamespace(), wsClient.name());
		
		// We packaged CoffeeService.wsdl in the jar
		URL url = CoffeeService.class.getResource("/CoffeeService.wsdl");
		
		// Get the port
		port = new CoffeeService(url, name).getCoffeeServicePort();
		
		// Sets the correct endpoint for the coffee service.
		final BindingProvider bp = (BindingProvider) port;
		bp.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, 
				"http://some.host/Coffee/CoffeeService");
	}

	public Coffee getSomeCoffee() {

		return port.getSomeCoffee();
	}
}

And it doesn't stop there. We could also make some logic to balance our requests over multiple endpoints, or call difference endpoints depending on the situation.



0 reactie(s) Geplaatst in: Java SOAP

Je reactie toevoegen

The content of this field is kept private and will not be shown publicly.