blob: 8ae67188aa18a78a7c0e11737772d6066ae20f9d [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2009 Composent, Inc. and others. 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
*
* Contributors:
* Composent, Inc. - initial API and implementation
******************************************************************************/
package org.eclipse.ecf.remoteservice.client;
import java.io.NotSerializableException;
import java.lang.reflect.Method;
import java.util.Map;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.ecf.core.util.ECFException;
import org.eclipse.ecf.remoteservice.*;
import org.eclipse.ecf.remoteservice.events.IRemoteCallCompleteEvent;
import org.eclipse.ecf.remoteservice.events.IRemoteCallStartEvent;
import org.eclipse.equinox.concurrent.future.*;
/**
* Remote service client service. Implements {@link IRemoteService}.
*
* @since 4.0
*/
public abstract class AbstractClientService extends AbstractRemoteService {
private long nextID = 0;
protected RemoteServiceClientRegistration registration;
protected AbstractClientContainer container;
public AbstractClientService(AbstractClientContainer container, RemoteServiceClientRegistration registration) {
this.container = container;
Assert.isNotNull(container);
this.registration = registration;
Assert.isNotNull(this.registration);
}
public Object callSync(IRemoteCall call) throws ECFException {
IRemoteCallable callable = getRegistration().lookupCallable(call);
if (callable == null)
throw new ECFException("Callable not found for call=" + call); //$NON-NLS-1$
return invokeRemoteCall(call, callable);
}
public IFuture callAsync(final IRemoteCall call) {
return callAsync(call, getRegistration().lookupCallable(call));
}
public void callAsync(IRemoteCall call, IRemoteCallListener listener) {
callAsync(call, getRegistration().lookupCallable(call), listener);
}
public void fireAsync(IRemoteCall call) throws ECFException {
IRemoteCallable callable = getRegistration().lookupCallable(call);
if (callable == null)
throw new ECFException("Remote callable not found"); //$NON-NLS-1$
callAsync(call, callable);
}
protected Object invokeSync(IRemoteCall remoteCall) throws ECFException {
// Now lookup callable
IRemoteCallable callable = getRegistration().lookupCallable(remoteCall);
// If not found...we're finished
if (callable == null)
throw new ECFException("Callable not found for call=" + remoteCall); //$NON-NLS-1$
return invokeRemoteCall(remoteCall, callable);
}
protected Object[] getCallParametersForProxyInvoke(String callMethod, Method proxyMethod, Object[] args) {
return args;
}
protected String getCallMethodNameForProxyInvoke(Method method, Object[] args) {
return RemoteServiceClientRegistration.getFQMethod(method.getDeclaringClass().getName(), method.getName());
}
protected long getNextRequestID() {
return nextID++;
}
protected void callAsync(IRemoteCall call, IRemoteCallable restClientCallable, IRemoteCallListener listener) {
final AbstractExecutor executor = new ThreadsExecutor();
executor.execute(new AsyncResult(call, restClientCallable, listener), null);
}
protected IFuture callAsync(final IRemoteCall call, final IRemoteCallable callable) {
final AbstractExecutor executor = new ThreadsExecutor();
return executor.execute(new IProgressRunnable() {
public Object run(IProgressMonitor monitor) throws Exception {
if (callable == null)
throw new ECFException("Callable not found"); //$NON-NLS-1$
return invokeRemoteCall(call, callable);
}
}, null);
}
/**
* inner class implementing the asynchronous result object. This
* implementation also provides the calling infrastructure.
*/
protected class AsyncResult implements IProgressRunnable {
IRemoteCall call;
// the remote call object.
IRemoteCallable callable;
// the callback listener, if provided.
IRemoteCallListener listener;
// the result of the call.
Object result;
// the exception, if any happened during the call.
Throwable exception;
// constructor
public AsyncResult(final IRemoteCall call, final IRemoteCallable callable, final IRemoteCallListener listener) {
this.call = call;
this.callable = callable;
this.listener = listener;
}
public Object run(IProgressMonitor monitor) throws Exception {
Object r = null;
Throwable e = null;
final long reqID = getNextRequestID();
if (listener != null) {
listener.handleEvent(new IRemoteCallStartEvent() {
public IRemoteCall getCall() {
return call;
}
public IRemoteServiceReference getReference() {
return getRegistration().getReference();
}
public long getRequestId() {
return reqID;
}
});
}
try {
if (callable == null)
throw new ECFException("Restcall not found for method=" + call.getMethod()); //$NON-NLS-1$
r = invokeRemoteCall(call, callable);
} catch (Throwable t) {
e = t;
}
synchronized (AsyncResult.this) {
result = r;
exception = e;
AsyncResult.this.notify();
}
if (listener != null) {
listener.handleEvent(new IRemoteCallCompleteEvent() {
public Throwable getException() {
return exception;
}
public Object getResponse() {
return result;
}
public boolean hadException() {
return exception != null;
}
public long getRequestId() {
return reqID;
}
});
}
return null;
}
}
protected void handleInvokeException(String message, Throwable e) throws ECFException {
throw new ECFException(message, e);
}
protected AbstractClientContainer getClientContainer() {
return container;
}
protected RemoteServiceClientRegistration getRegistration() {
return registration;
}
protected String prepareEndpointAddress(IRemoteCall call, IRemoteCallable callable) {
return getClientContainer().prepareEndpointAddress(call, callable);
}
protected IRemoteCallParameter[] prepareParameters(String uri, IRemoteCall call, IRemoteCallable callable) throws NotSerializableException {
return getClientContainer().prepareParameters(uri, call, callable);
}
/**
* @since 8.0
*/
protected Object processResponse(String uri, IRemoteCall call, IRemoteCallable callable, Map responseHeaders, byte[] responseBody) throws NotSerializableException {
return getClientContainer().processResponse(uri, call, callable, responseHeaders, responseBody);
}
protected IRemoteServiceID getRemoteServiceID() {
return registration.getID();
}
protected IRemoteServiceReference getRemoteServiceReference() {
return registration.getReference();
}
protected String[] getInterfaceClassNames() {
return registration.getClazzes();
}
/**
* @since 8.5
*/
public static class UriRequest {
private final String uri;
private final IRemoteCall call;
private final IRemoteCallable callable;
public UriRequest(String uri, IRemoteCall call, IRemoteCallable callable) {
this.uri = uri;
this.call = call;
this.callable = callable;
}
public String getUri() {
return uri;
}
public IRemoteCall getRemoteCall() {
return call;
}
public IRemoteCallable getRemoteCallable() {
return callable;
}
}
/**
* @since 8.5
*/
protected UriRequest createUriRequest(String endpoint, IRemoteCall call, IRemoteCallable callable) {
return getClientContainer().createUriRequest(endpoint, call, callable);
}
/**
* Invoke remote call. The implementation of this method should actually
* make the remote call for the given call and associated callable.
*
* @param call the call for the remote call. Will not be <code>null</code>.
* @param callable the callable associated with the remote call. Will not be <code>null</code>.
* @return Object the result of the remote call. May be <code>null</code>.
* @throws ECFException thrown if the call fails.
*/
protected abstract Object invokeRemoteCall(final IRemoteCall call, final IRemoteCallable callable) throws ECFException;
}