Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: bf0d835cf32d351f48ff450579fd5987c1a3701b (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
/*******************************************************************************
* Copyright (c) 2016 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.lang.reflect.Method;
import java.util.concurrent.*;
import org.eclipse.ecf.core.util.ECFException;
import org.eclipse.ecf.remoteservice.*;
import org.eclipse.ecf.remoteservice.events.IRemoteCallCompleteEvent;
import org.osgi.framework.ServiceException;

/**
 * Abstract client remote service instance.   This class should be overridden to implement the abstract
 * invokeAsync, and invokeSync methods, which will be called when the proxy created is called by clients.
 * 
 * @since 8.9
 */
public abstract class AbstractRSAClientService extends AbstractClientService {

	public static class RSARemoteCall extends RemoteCall {

		private final Object proxy;
		private final Method reflectMethod;

		public RSARemoteCall(Object proxy, Method method, String methodName, Object[] parameters, long timeout) {
			super(methodName, parameters, timeout);
			this.reflectMethod = method;
			this.proxy = proxy;
		}

		public Method getReflectMethod() {
			return reflectMethod;
		}

		public Object getProxy() {
			return proxy;
		}
	}

	/**
	 * @param call the remote call to invoke
	 * @param callable the remote callable to invoke
	 * @return Object result of remote call
	 * @throws ECFException if invoke fails
	 */
	@Override
	protected Object invokeRemoteCall(IRemoteCall call, IRemoteCallable callable) throws ECFException {
		return null;
	}

	public AbstractRSAClientService(AbstractClientContainer container, RemoteServiceClientRegistration registration) {
		super(container, registration);
	}

	/**
	 * Invoke a remote call asynchronously.  This method should not block and should return either a {@link org.eclipse.equinox.concurrent.future.IFuture}, {@link java.util.concurrent.Future}, or {@link java.util.concurrent.CompletableFuture}
	 * or a
	 * CompletableFuture based upon the return type defined in the asynchronous service interface.
	 * 
	 * @param remoteCall the RSARemoteCall to use to make the asynchronous remote call.  Will not be <code>null</code>.
	 * @return Object.   Should return a non-null instance of {@link org.eclipse.equinox.concurrent.future.IFuture}, {@link java.util.concurrent.Future}, or {@link java.util.concurrent.CompletableFuture}
	 * @throws ECFException if async cannot be invoked
	 */
	protected Object invokeAsync(RSARemoteCall remoteCall) throws ECFException {
		return callFuture(remoteCall, remoteCall.getReflectMethod().getReturnType());
	}

	/**
	 * Invoke a remote call synchronously.  This method should block until a value may be returned, or the remote
	 * call has failed or timed out.
	 * 
	 * @param remoteCall the RSARemoteCall to synchronously invoke.  Will not be <code>null</code>.
	 * @return the result (of appropriate type)
	 * @throws ECFException if some exception occurred during invocation
	 */
	protected Object invokeSync(RSARemoteCall remoteCall) throws ECFException {
		if (remoteCall.getClass().isAssignableFrom(RSARemoteCall.class)) {
			Callable<Object> c = createSyncCallable(remoteCall);
			if (c == null)
				throw new ECFException("invokeSync failed on method=" + remoteCall.getMethod(), new NullPointerException("createSyncCallable() must not return null.  It's necessary for distribution provider to override createSyncCallable.")); //$NON-NLS-1$ //$NON-NLS-2$
			try {
				return callSync(remoteCall, c);
			} catch (InterruptedException e) {
				throw new ECFException("invokeSync interrupted on method=" + remoteCall.getMethod(), e); //$NON-NLS-1$
			} catch (ExecutionException e) {
				throw new ECFException("invokeSync exception on method=" + remoteCall.getMethod(), e.getCause()); //$NON-NLS-1$
			} catch (TimeoutException e) {
				throw new ECFException("invokeSync timeout on method=" + remoteCall.getMethod(), e); //$NON-NLS-1$
			}
		}
		return super.invokeSync(remoteCall);
	}

	protected RSARemoteCall createRemoteCall(Object proxy, Method method, String methodName, Object[] parameters, long timeout) {
		return new RSARemoteCall(proxy, method, methodName, parameters, timeout);
	}

	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		try {
			Object resultObject = invokeObject(proxy, method, args);
			if (resultObject != null)
				return resultObject;
			try {
				// If return is async type (Future, IFuture, CompletableFuture, CompletionStage)
				if (isReturnAsync(proxy, method, args)) {
					if (isInterfaceAsync(method.getDeclaringClass()) && isMethodAsync(method.getName()))
						return invokeAsync(createRemoteCall(proxy, method, getAsyncInvokeMethodName(method), args, getDefaultTimeout()));
					// If OSGI Async then invoke method directly
					if (isOSGIAsync())
						return invokeAsync(createRemoteCall(proxy, method, method.getName(), args, getDefaultTimeout()));
				}
			} catch (Throwable t) {
				handleProxyException("Exception invoking async method on remote service proxy=" + getRemoteServiceID(), t); //$NON-NLS-1$
			}

			final String callMethod = getCallMethodNameForProxyInvoke(method, args);
			final Object[] callParameters = getCallParametersForProxyInvoke(callMethod, method, args);
			final long callTimeout = getCallTimeoutForProxyInvoke(callMethod, method, args);
			return invokeSync(createRemoteCall(proxy, method, callMethod, callParameters, callTimeout));
		} catch (Throwable t) {
			if (t instanceof ServiceException)
				throw t;
			// rethrow as service exception
			throw new ServiceException("Service exception on remote service proxy rsid=" + getRemoteServiceID(), ServiceException.REMOTE, t); //$NON-NLS-1$
		}
	}

	@Override
	protected ExecutorService getFutureExecutorService(IRemoteCall call) {
		return super.getFutureExecutorService(call);
	}

	@Override
	public void callAsync(IRemoteCall call, IRemoteCallListener listener) {
		if (call instanceof RSARemoteCall) 
			callAsyncWithTimeout(call, createAsyncCallable((RSARemoteCall) call), listener);
		else
			super.callAsync(call, listener);
	}

	@Override
	public Object callSync(IRemoteCall call) throws ECFException {
		if (call instanceof RSARemoteCall) {
			Callable<Object> c = createSyncCallable((RSARemoteCall) call);
			try {
				return c.call();
			} catch (Exception e) {
				throw new ECFException("Exception calling callable for method=" + call.getMethod(), e); //$NON-NLS-1$
			}
		}
		return super.callSync(call);
	}

	/**
	 * @since 8.13
	 */
	protected Callable<IRemoteCallCompleteEvent> createAsyncCallable(final RSARemoteCall call) {
		throw new UnsupportedOperationException("distribution provider must override createAsyncCallable for service method=" + call.getMethod() + " class=" + call.getReflectMethod().getDeclaringClass()); //$NON-NLS-1$ //$NON-NLS-2$
	}

	/**
	 * @since 8.13
	 */
	protected Callable<Object> createSyncCallable(final RSARemoteCall call) {
		throw new UnsupportedOperationException("distribution provider must override createAsyncCallable for service method=" + call.getMethod() + " class=" + call.getReflectMethod().getDeclaringClass()); //$NON-NLS-1$ //$NON-NLS-2$
	}

}

Back to the top