| /******************************************************************************* |
| * 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; |
| |
| } |