Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove usage of org.springframework.remoting.support.RemoteExporter #303 #312

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ JSON-RPC).
* HTTP Server (`HttpServletRequest` \ `HttpServletResponse`)
* Portlet Server (`ResourceRequest` \ `ResourceResponse`)
* Socket Server (`StreamServer`)
* Integration with the Spring Framework (`RemoteExporter`)
* Integration with the Spring Framework
* Streaming client
* HTTP client
* Dynamic client proxies
Expand Down Expand Up @@ -66,7 +66,7 @@ that take `InputStream`s and `OutputStream`s. Also in the library is a `JsonRpc
which extends the `JsonRpcClient` to add HTTP support.

## Spring Framework
jsonrpc4j provides a `RemoteExporter` to expose java services as JSON-RPC over HTTP without
jsonrpc4j provides support for exposing java services as JSON-RPC over HTTP without
requiring any additional work on the part of the programmer. The following example explains
how to use the `JsonServiceExporter` within the Spring Framework.

Expand Down Expand Up @@ -113,7 +113,9 @@ public class UserServiceImpl
}
```

Configure your service in spring as you would any other RemoteExporter:
Configure your service in Spring as you would do it for any other Beans,
and then add a reference of your service Bean into `JsonServiceExporter`
by specifying the `service` and `serviceInterface` properties:

```xml
<?xml version="1.0" encoding="UTF-8"?>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ public final void afterPropertiesSet()
*
* @throws Exception on error
*/
void exportService()
protected void exportService()
throws Exception {
// no-op
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,25 @@

import com.fasterxml.jackson.databind.ObjectMapper;
import com.googlecode.jsonrpc4j.*;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.remoting.support.RemoteExporter;
import org.springframework.util.ClassUtils;

import java.util.List;
import java.util.concurrent.ExecutorService;

/**
* {@link RemoteExporter} that exports services using Json
* according to the JSON-RPC proposal specified at:
* <a href="http://groups.google.com/group/json-rpc">
* http://groups.google.com/group/json-rpc</a>.
* Exports user defined services using JSON-RPC protocol
*/
@SuppressWarnings("unused")
abstract class AbstractJsonServiceExporter extends RemoteExporter implements InitializingBean, ApplicationContextAware {
abstract class AbstractJsonServiceExporter implements InitializingBean, ApplicationContextAware {
private static final Logger logger = LoggerFactory.getLogger(AbstractJsonServiceExporter.class);

private ObjectMapper objectMapper;
private JsonRpcServer jsonRpcServer;
Expand All @@ -36,6 +38,8 @@ abstract class AbstractJsonServiceExporter extends RemoteExporter implements Ini
private List<JsonRpcInterceptor> interceptorList;
private ExecutorService batchExecutorService = null;
private long parallelBatchProcessingTimeout;
private Object service;
private Class<?> serviceInterface;

/**
* {@inheritDoc}
Expand All @@ -49,7 +53,7 @@ public void afterPropertiesSet() throws Exception {
try {
objectMapper = BeanFactoryUtils.beanOfTypeIncludingAncestors(applicationContext, ObjectMapper.class);
} catch (Exception e) {
logger.debug(e);
logger.debug("Failed to obtain objectMapper from application context", e);
}
}
if (objectMapper == null) {
Expand Down Expand Up @@ -93,7 +97,7 @@ public void afterPropertiesSet() throws Exception {
*
* @throws Exception on error
*/
void exportService()
protected void exportService()
throws Exception {
// no-op
}
Expand Down Expand Up @@ -214,4 +218,96 @@ public void setBatchExecutorService(ExecutorService batchExecutorService) {
public void setParallelBatchProcessingTimeout(long parallelBatchProcessingTimeout) {
this.parallelBatchProcessingTimeout = parallelBatchProcessingTimeout;
}

/**
* Set the service to export.
* Typically populated via a bean reference.
*/
public void setService(Object service) {
this.service = service;
}

/**
* Return the service to export.
*/
public Object getService() {
return this.service;
}

/**
* Set the interface of the service to export.
* The interface must be suitable for the particular service and remoting strategy.
*/
public void setServiceInterface(Class<?> serviceInterface) {
if (serviceInterface == null) {
throw new IllegalArgumentException("'serviceInterface' must not be null");
}
if (!serviceInterface.isInterface()) {
throw new IllegalArgumentException("'serviceInterface' must be an interface");
}
this.serviceInterface = serviceInterface;
}

/**
* Return the interface of the service to export.
*/
public Class<?> getServiceInterface() {
return this.serviceInterface;
}


/**
* Check whether a service reference has been set,
* and whether it matches the specified service.
* @see #setServiceInterface
* @see #setService
*/
protected void checkServiceInterface() throws IllegalArgumentException {
Class<?> serviceInterface = getServiceInterface();
if (serviceInterface == null) {
throw new IllegalArgumentException("Property 'serviceInterface' is required");
}

Object service = getService();
if (service instanceof String) {
throw new IllegalArgumentException(
"Service [" + service + "] is a String rather than an actual service reference:"
+ " Have you accidentally specified the service bean name as value "
+ " instead of as reference?"
);
}
if (!serviceInterface.isInstance(service)) {
throw new IllegalArgumentException(
"Service interface [" + serviceInterface.getName()
+ "] needs to be implemented by service [" + service + "] of class ["
+ service.getClass().getName() + "]"
);
}
}


/**
* Get a proxy for the given service object, implementing the specified
* service interface.
* <p>Used to export a proxy that does not expose any internals but just
* a specific interface intended for remote access.
*
* @return the proxy
* @see #setServiceInterface
* @see #setService
*/
protected Object getProxyForService() {
Object targetService = getService();
if (targetService == null) {
throw new IllegalArgumentException("Property 'service' is required");
}
checkServiceInterface();

ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.addInterface(getServiceInterface());
proxyFactory.setTarget(targetService);
proxyFactory.setOpaque(true);

return proxyFactory.getProxy(ClassUtils.getDefaultClassLoader());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ public class AutoJsonRpcServiceExporter implements BeanFactoryPostProcessor {

private ObjectMapper objectMapper;
private ErrorResolver errorResolver = null;
private Boolean registerTraceInterceptor;
private boolean backwardsCompatible = true;
private boolean rethrowExceptions = false;
private boolean allowExtraParams = false;
Expand Down Expand Up @@ -141,10 +140,6 @@ private void registerServiceProxy(DefaultListableBeanFactory defaultListableBean
builder.addPropertyValue("invocationListener", invocationListener);
}

if (registerTraceInterceptor != null) {
builder.addPropertyValue("registerTraceInterceptor", registerTraceInterceptor);
}

if (httpStatusCodeProvider != null) {
builder.addPropertyValue("httpStatusCodeProvider", httpStatusCodeProvider);
}
Expand Down Expand Up @@ -225,12 +220,16 @@ public void setAllowLessParams(boolean allowLessParams) {
}

/**
* See {@link org.springframework.remoting.support.RemoteExporter#setRegisterTraceInterceptor(boolean)}
* See {@code org.springframework.remoting.support.RemoteExporter#setRegisterTraceInterceptor(boolean)}
* <p>
* Note: this method is deprecated and marked for removal.
* {@code RemoteExporter} and {@code TraceInterceptor-s} are no longer supported.
*
* @param registerTraceInterceptor the registerTraceInterceptor value to set
*/
@Deprecated
public void setRegisterTraceInterceptor(boolean registerTraceInterceptor) {
this.registerTraceInterceptor = registerTraceInterceptor;
// NOOP
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ public class AutoJsonRpcServiceImplExporter implements BeanFactoryPostProcessor

private ObjectMapper objectMapper;
private ErrorResolver errorResolver = null;
private Boolean registerTraceInterceptor;
private boolean backwardsCompatible = true;
private boolean rethrowExceptions = false;
private boolean allowExtraParams = false;
Expand Down Expand Up @@ -181,11 +180,7 @@ private void registerServiceProxy(DefaultListableBeanFactory defaultListableBean
if (invocationListener != null) {
builder.addPropertyValue("invocationListener", invocationListener);
}

if (registerTraceInterceptor != null) {
builder.addPropertyValue("registerTraceInterceptor", registerTraceInterceptor);
}


if (httpStatusCodeProvider != null) {
builder.addPropertyValue("httpStatusCodeProvider", httpStatusCodeProvider);
}
Expand Down Expand Up @@ -280,14 +275,18 @@ public void setAllowExtraParams(boolean allowExtraParams) {
public void setAllowLessParams(boolean allowLessParams) {
this.allowLessParams = allowLessParams;
}

/**
* See {@link org.springframework.remoting.support.RemoteExporter#setRegisterTraceInterceptor(boolean)}
* See {@code org.springframework.remoting.support.RemoteExporter#setRegisterTraceInterceptor(boolean)}
* <p>
* Note: this method is deprecated and marked for removal.
* {@code RemoteExporter} and {@code TraceInterceptor-s} are no longer supported.
*
* @param registerTraceInterceptor the registerTraceInterceptor value to set
*/
@Deprecated
public void setRegisterTraceInterceptor(boolean registerTraceInterceptor) {
this.registerTraceInterceptor = registerTraceInterceptor;
// NOOP
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,7 @@
import java.io.IOException;

/**
* {@link HttpRequestHandler} that exports services using Json
* according to the JSON-RPC proposal specified at:
* <a href="http://groups.google.com/group/json-rpc">
* http://groups.google.com/group/json-rpc</a>.
* {@link HttpRequestHandler} that exports user services using JSON-RPC over HTTP protocol
*/
public class JsonServiceExporter extends AbstractJsonServiceExporter implements HttpRequestHandler {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,7 @@


/**
* {@link org.springframework.remoting.support.RemoteExporter RemoteExporter}
* that exports services using Json according to the JSON-RPC proposal specified
* at:
* <a href="http://groups.google.com/group/json-rpc">
* http://groups.google.com/group/json-rpc</a>.
* Exports user defined services as streaming server, which provides JSON-RPC over sockets.
*/
@SuppressWarnings("unused")
public class JsonStreamServiceExporter extends AbstractJsonServiceExporter implements DisposableBean {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package com.googlecode.jsonrpc4j.spring;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.googlecode.jsonrpc4j.spring.service.Service;
import com.googlecode.jsonrpc4j.spring.service.ServiceImpl;

import static org.junit.Assert.*;

/**
* This test ensures that {@link com.googlecode.jsonrpc4j.spring.JsonServiceExporter} bean is
* constructed according to Spring Framework configuration.
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:serverApplicationContextC.xml")
public class JsonServiceExporterIntegrationTest {

private static final String BEAN_NAME_AND_URL_PATH = "/UserService.json";

@Autowired
private ApplicationContext applicationContext;

@Test
public void testExportedService() {
assertNotNull(applicationContext);

// check that the bean was only exported on the configured path.
{
Object bean = applicationContext.getBean(BEAN_NAME_AND_URL_PATH);
assertEquals(JsonServiceExporter.class, bean.getClass());

String[] names = applicationContext.getBeanNamesForType(JsonServiceExporter.class);
assertNotNull(names);
assertEquals(1, names.length);
assertEquals(BEAN_NAME_AND_URL_PATH, names[0]);
}

// check that service classes were also successfully configured in the context.

{
Service service = applicationContext.getBean(Service.class);
assertTrue(service instanceof ServiceImpl);

ServiceImpl serviceImpl = applicationContext.getBean(ServiceImpl.class);
assertNotNull(serviceImpl);
}
}
}
14 changes: 14 additions & 0 deletions src/test/resources/serverApplicationContextC.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>

<bean id="userService" class="com.googlecode.jsonrpc4j.spring.service.ServiceImpl">
</bean>

<bean name="/UserService.json" class="com.googlecode.jsonrpc4j.spring.JsonServiceExporter">
<property name="service" ref="userService"/>
<property name="serviceInterface" value="com.googlecode.jsonrpc4j.spring.service.Service"/>
</bean>
</beans>