/*******************************************************************************
* Copyright (c) 2009 MATERNA Information & Communications. All rights reserved.
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html. For further
* project-related information visit http://www.ws4d.org. The most recent
* version of the JMEDS framework can be obtained from
* http://sourceforge.net/projects/ws4d-javame.
******************************************************************************/
package org.ws4d.java.client;
import org.ws4d.java.communication.CommunicationManagerRegistry;
import org.ws4d.java.communication.DefaultResponseCallback;
import org.ws4d.java.communication.ProtocolData;
import org.ws4d.java.communication.TimeoutException;
import org.ws4d.java.configuration.DispatchingProperties;
import org.ws4d.java.dispatch.OutDispatcher;
import org.ws4d.java.message.FaultMessage;
import org.ws4d.java.message.InvokeMessage;
import org.ws4d.java.message.Message;
import org.ws4d.java.service.InvocationException;
import org.ws4d.java.service.parameter.ParameterValue;
import org.ws4d.java.service.reference.DeviceReference;
import org.ws4d.java.service.reference.ServiceReference;
import org.ws4d.java.types.QName;
import org.ws4d.java.types.QNameSet;
import org.ws4d.java.types.URI;
import org.ws4d.java.types.XAddressInfo;
import org.ws4d.java.util.Log;
import org.ws4d.java.util.TimedEntry;
import org.ws4d.java.util.WatchDog;
/**
* This utility class allows the invocation of a Web Service action without WSDL
* parsing or discovery.
*/
public class InvokeUtil {
/**
* Invokes the one-way operation of a Web Service with given input action
* URI.
* <p>
* This method tries to <strong>discover</strong> the Web Service. The first
* service which matches the port type is used. The port type is to be
* extracted from the input action URI.
* </p>
*
* @param actionUri the input action URI of the operation
* @param value the request value for the operation
*/
public static void invokeAnyOneWay(String actionUri, ParameterValue value) {
invokeOneWay(discover(actionUri), actionUri, value);
}
/**
* Invokes the operation of a Web Service with given input action URI.
* <p>
* This method tries to <strong>discover</strong> the Web Service. The first
* service which matches the port type is to be used. The port type is to be
* extracted from the input action URI.
* </p>
*
* @param actionUri the input action URI of the operation
* @param value the request value for the operation
* @return the value of the response
* @throws InvocationException
* @throws TimeoutException
*/
public static ParameterValue invokeAny(String actionUri, ParameterValue value) throws InvocationException, TimeoutException {
return invoke(discover(actionUri), actionUri, value, true);
}
/**
* Invokes the one-way operation of a Web Service with given address and
* input action URI.
*
* @param actionUri the input action URI of the operation
* @param value the request value for the operation
* @throws InvocationException
* @throws TimeoutException
*/
public static void invokeOneWay(URI address, String actionUri, ParameterValue value) {
try {
invoke(address, actionUri, value, false);
} catch (Exception e) {
// void
}
}
/**
* Invokes the operation of a Web Service with given address and input
* action URI.
*
* @param actionUri the input action URI of the operation
* @param value the request value for the operation
* @return the value of the response
* @throws InvocationException
* @throws TimeoutException
*/
public static ParameterValue invoke(URI address, String actionUri, ParameterValue value) throws InvocationException, TimeoutException {
return invoke(address, actionUri, value, true);
}
private static ParameterValue invoke(URI address, String actionUri, ParameterValue value, boolean awaitResponse) throws InvocationException, TimeoutException {
InvokeMessage message = new InvokeMessage(actionUri, CommunicationManagerRegistry.getDefault());
XAddressInfo targetXAddressInfo = new XAddressInfo(address, CommunicationManagerRegistry.getDefault());
message.setTargetXAddressInfo(targetXAddressInfo);
message.setContent(value);
MyResponseCallBack callback = new MyResponseCallBack(targetXAddressInfo);
OutDispatcher.getInstance().send(message, targetXAddressInfo, callback);
if (awaitResponse) {
return callback.waitForMe();
}
return null;
}
private static URI discover(String actionUri) {
int i = actionUri.lastIndexOf('/');
String portType = actionUri.substring(0, i);
i = portType.lastIndexOf('/');
String namespace = portType.substring(0, i);
String localPart = portType.substring(i + 1, portType.length());
QName pt = new QName(localPart, namespace);
SearchParameter parameter = new SearchParameter();
parameter.setServiceTypes(new QNameSet(pt));
MySearchCallback callback = new MySearchCallback();
SearchManager.searchService(parameter, callback);
return callback.waitForMe();
}
private static class MySearchCallback extends TimedEntry implements SearchCallback {
private volatile boolean pending = true;
private URI address = null;
/*
* (non-Javadoc)
* @see
* org.ws4d.java.client.SearchCallback#deviceFound(org.ws4d.java.service
* .reference.DeviceReference, org.ws4d.java.client.SearchParameter)
*/
public void deviceFound(DeviceReference devRef, SearchParameter search) {
// void
}
/*
* (non-Javadoc)
* @see
* org.ws4d.java.client.SearchCallback#serviceFound(org.ws4d.java.service
* .reference.ServiceReference, org.ws4d.java.client.SearchParameter)
*/
public synchronized void serviceFound(ServiceReference servRef, SearchParameter search) {
try {
address = servRef.getPreferredXAddress();
unsync();
} catch (TimeoutException e) {
Log.error("Unable to obtain transport addres of service: " + e);
}
}
/*
* (non-Javadoc)
* @see org.ws4d.java.util.TimedEntry#timedOut()
*/
protected synchronized void timedOut() {
Log.error("Service discovery timeout.");
unsync();
}
synchronized URI waitForMe() {
WatchDog.getInstance().register(this, DispatchingProperties.getInstance().getMatchWaitTime());
while (pending) {
try {
wait();
} catch (InterruptedException e) {
Log.printStackTrace(e);
}
}
WatchDog.getInstance().unregister(this);
return address;
}
private void unsync() {
pending = false;
notify();
}
}
private static class MyResponseCallBack extends DefaultResponseCallback {
private volatile boolean pending = true;
private ParameterValue response = null;
private InvocationException invocationException = null;
private TimeoutException timeoutException = null;
MyResponseCallBack(XAddressInfo targetXAddressInfo) {
super(targetXAddressInfo);
}
/*
* (non-Javadoc)
* @see
* org.ws4d.java.communication.DefaultResponseCallback#handle(org.ws4d
* .java.message.Message, org.ws4d.java.message.InvokeMessage,
* org.ws4d.java.communication.ProtocolData)
*/
public synchronized void handle(Message request, InvokeMessage invokeResponse, ProtocolData protocolData) {
response = invokeResponse.getContent();
unsync();
}
/*
* (non-Javadoc)
* @see
* org.ws4d.java.communication.DefaultResponseCallback#handle(org.ws4d
* .java.message.Message, org.ws4d.java.message.FaultMessage,
* org.ws4d.java.communication.ProtocolData)
*/
public synchronized void handle(Message request, FaultMessage fault, ProtocolData protocolData) {
invocationException = new InvocationException(fault);
unsync();
}
/*
* (non-Javadoc)
* @see org.ws4d.java.communication.DefaultResponseCallback#
* handleTransmissionException(org.ws4d.java.message.Message,
* java.lang.Exception, org.ws4d.java.communication.ProtocolData)
*/
public synchronized void handleTransmissionException(Message request, Exception exception, ProtocolData protocolData) {
Log.error("Transmission error: " + exception);
// TODO
unsync();
}
/*
* (non-Javadoc)
* @see org.ws4d.java.communication.DefaultResponseCallback#
* handleMalformedResponseException(org.ws4d.java.message.Message,
* java.lang.Exception, org.ws4d.java.communication.ProtocolData)
*/
public synchronized void handleMalformedResponseException(Message request, Exception exception, ProtocolData protocolData) {
Log.error("Malformed response: " + exception);
// TODO
unsync();
}
/*
* (non-Javadoc)
* @see
* org.ws4d.java.communication.DefaultResponseCallback#handleTimeout
* (org.ws4d.java.message.Message)
*/
public synchronized void handleTimeout(Message request) {
Log.error("Request timeout: " + request);
timeoutException = new TimeoutException("Invocation timeout");
unsync();
}
synchronized ParameterValue waitForMe() throws InvocationException, TimeoutException {
while (pending) {
try {
// FIXME this won't work for one-way operations!!!
wait();
} catch (InterruptedException e) {
Log.printStackTrace(e);
}
}
if (timeoutException != null) {
throw timeoutException;
}
if (invocationException != null) {
throw invocationException;
}
return response;
}
private void unsync() {
pending = false;
notify();
}
}
}