2
2
3
3
import com .fasterxml .jackson .databind .ObjectMapper ;
4
4
import com .googlecode .jsonrpc4j .*;
5
+
6
+ import org .slf4j .Logger ;
7
+ import org .slf4j .LoggerFactory ;
8
+ import org .springframework .aop .framework .ProxyFactory ;
5
9
import org .springframework .beans .factory .BeanFactoryUtils ;
6
10
import org .springframework .beans .factory .InitializingBean ;
7
11
import org .springframework .context .ApplicationContext ;
8
12
import org .springframework .context .ApplicationContextAware ;
9
- import org .springframework .remoting . support . RemoteExporter ;
13
+ import org .springframework .util . ClassUtils ;
10
14
11
15
import java .util .List ;
12
16
import java .util .concurrent .ExecutorService ;
13
17
14
18
/**
15
- * {@link RemoteExporter} that exports services using Json
16
- * according to the JSON-RPC proposal specified at:
17
- * <a href="http://groups.google.com/group/json-rpc">
18
- * http://groups.google.com/group/json-rpc</a>.
19
+ * Exports user defined services using JSON-RPC protocol
19
20
*/
20
21
@ SuppressWarnings ("unused" )
21
- abstract class AbstractJsonServiceExporter extends RemoteExporter implements InitializingBean , ApplicationContextAware {
22
+ abstract class AbstractJsonServiceExporter implements InitializingBean , ApplicationContextAware {
23
+ private static final Logger logger = LoggerFactory .getLogger (AbstractJsonServiceExporter .class );
22
24
23
25
private ObjectMapper objectMapper ;
24
26
private JsonRpcServer jsonRpcServer ;
@@ -36,6 +38,8 @@ abstract class AbstractJsonServiceExporter extends RemoteExporter implements Ini
36
38
private List <JsonRpcInterceptor > interceptorList ;
37
39
private ExecutorService batchExecutorService = null ;
38
40
private long parallelBatchProcessingTimeout ;
41
+ private Object service ;
42
+ private Class <?> serviceInterface ;
39
43
40
44
/**
41
45
* {@inheritDoc}
@@ -49,7 +53,7 @@ public void afterPropertiesSet() throws Exception {
49
53
try {
50
54
objectMapper = BeanFactoryUtils .beanOfTypeIncludingAncestors (applicationContext , ObjectMapper .class );
51
55
} catch (Exception e ) {
52
- logger .debug (e );
56
+ logger .debug ("Failed to obtain objectMapper from application context" , e );
53
57
}
54
58
}
55
59
if (objectMapper == null ) {
@@ -93,7 +97,7 @@ public void afterPropertiesSet() throws Exception {
93
97
*
94
98
* @throws Exception on error
95
99
*/
96
- void exportService ()
100
+ protected void exportService ()
97
101
throws Exception {
98
102
// no-op
99
103
}
@@ -214,4 +218,96 @@ public void setBatchExecutorService(ExecutorService batchExecutorService) {
214
218
public void setParallelBatchProcessingTimeout (long parallelBatchProcessingTimeout ) {
215
219
this .parallelBatchProcessingTimeout = parallelBatchProcessingTimeout ;
216
220
}
221
+
222
+ /**
223
+ * Set the service to export.
224
+ * Typically populated via a bean reference.
225
+ */
226
+ public void setService (Object service ) {
227
+ this .service = service ;
228
+ }
229
+
230
+ /**
231
+ * Return the service to export.
232
+ */
233
+ public Object getService () {
234
+ return this .service ;
235
+ }
236
+
237
+ /**
238
+ * Set the interface of the service to export.
239
+ * The interface must be suitable for the particular service and remoting strategy.
240
+ */
241
+ public void setServiceInterface (Class <?> serviceInterface ) {
242
+ if (serviceInterface == null ) {
243
+ throw new IllegalArgumentException ("'serviceInterface' must not be null" );
244
+ }
245
+ if (!serviceInterface .isInterface ()) {
246
+ throw new IllegalArgumentException ("'serviceInterface' must be an interface" );
247
+ }
248
+ this .serviceInterface = serviceInterface ;
249
+ }
250
+
251
+ /**
252
+ * Return the interface of the service to export.
253
+ */
254
+ public Class <?> getServiceInterface () {
255
+ return this .serviceInterface ;
256
+ }
257
+
258
+
259
+ /**
260
+ * Check whether a service reference has been set,
261
+ * and whether it matches the specified service.
262
+ * @see #setServiceInterface
263
+ * @see #setService
264
+ */
265
+ protected void checkServiceInterface () throws IllegalArgumentException {
266
+ Class <?> serviceInterface = getServiceInterface ();
267
+ if (serviceInterface == null ) {
268
+ throw new IllegalArgumentException ("Property 'serviceInterface' is required" );
269
+ }
270
+
271
+ Object service = getService ();
272
+ if (service instanceof String ) {
273
+ throw new IllegalArgumentException (
274
+ "Service [" + service + "] is a String rather than an actual service reference:"
275
+ + " Have you accidentally specified the service bean name as value "
276
+ + " instead of as reference?"
277
+ );
278
+ }
279
+ if (!serviceInterface .isInstance (service )) {
280
+ throw new IllegalArgumentException (
281
+ "Service interface [" + serviceInterface .getName ()
282
+ + "] needs to be implemented by service [" + service + "] of class ["
283
+ + service .getClass ().getName () + "]"
284
+ );
285
+ }
286
+ }
287
+
288
+
289
+ /**
290
+ * Get a proxy for the given service object, implementing the specified
291
+ * service interface.
292
+ * <p>Used to export a proxy that does not expose any internals but just
293
+ * a specific interface intended for remote access.
294
+ *
295
+ * @return the proxy
296
+ * @see #setServiceInterface
297
+ * @see #setService
298
+ */
299
+ protected Object getProxyForService () {
300
+ Object targetService = getService ();
301
+ if (targetService == null ) {
302
+ throw new IllegalArgumentException ("Property 'service' is required" );
303
+ }
304
+ checkServiceInterface ();
305
+
306
+ ProxyFactory proxyFactory = new ProxyFactory ();
307
+ proxyFactory .addInterface (getServiceInterface ());
308
+ proxyFactory .setTarget (targetService );
309
+ proxyFactory .setOpaque (true );
310
+
311
+ return proxyFactory .getProxy (ClassUtils .getDefaultClassLoader ());
312
+ }
217
313
}
0 commit comments