HttpInvokerServiceExporter + HttpInvokerProxyFactoryBean - Could not access HTTP invoker remote service

15.3k Views Asked by At

I'm trying to use HttpInvokerServiceExporter + HttpInvokerProxyFactoryBean, but whatever I do I get an exception:

org.springframework.remoting.RemoteAccessException: Could not access HTTP invoker remote service at [http://localhost:9999/testcaseapp/testcaseservice]; nested exception is java.io.IOException: Did not receive successful HTTP response: status code = 404, status message = [Not Found]

For the simplicity, I've created a test case.

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class RemoteTest {

    private static final Logger logger = LoggerFactory.getLogger("TestsLogger");

    static interface TestCaseService {
        public Integer add(Integer arg1, Integer arg2);
    }
    static class TestCaseServiceImpl implements TestCaseService {
        public Integer add(Integer arg1, Integer arg2) {
            return (arg1 != null ? arg1.intValue() : 0) + (arg2 != null ? arg2.intValue() : 0);
        }
    }

    @Configuration
    static class Config {
        @Bean
        public HttpInvokerServiceExporter httpInvokerServiceExporter() {
            HttpInvokerServiceExporter httpInvokerServiceExporter = new HttpInvokerServiceExporter();
            httpInvokerServiceExporter.setService(new TestCaseServiceImpl());
            httpInvokerServiceExporter.setServiceInterface(TestCaseService.class);
            return httpInvokerServiceExporter;
        }
        @Bean
        public HttpInvokerProxyFactoryBean httpInvokerProxyFactoryBean() {
            HttpInvokerProxyFactoryBean httpInvokerProxyFactoryBean = new HttpInvokerProxyFactoryBean();
            httpInvokerProxyFactoryBean.setServiceInterface(TestCaseService.class);
            httpInvokerProxyFactoryBean.setServiceUrl("http://localhost:9999/testcaseapp/testcaseservice");
            httpInvokerProxyFactoryBean.afterPropertiesSet();
            return httpInvokerProxyFactoryBean;
        }
    }

    @Autowired
    private TestCaseService[] testCaseServices;
    private static Server server;

    @BeforeClass
    public static void setUp() {
        try {
            server = new Server();
            SelectChannelConnector connector = new SelectChannelConnector();
            connector.setPort(9999);
            server.addConnector(connector);
            //
            WebAppContext webAppContext = new WebAppContext();
            webAppContext.setContextPath("/testcaseapp");
            webAppContext.setWar("src/test/java/" + RemotingTest.class.getPackage().getName().replace('.', '/'));
            server.setHandler(webAppContext);
            //
            server.start();
        } catch (Exception ex) {
            logger.info("Could not permorm the set up: {}", ex.toString());
        }
    }

    @AfterClass
    public static void destroy() {
        try {
            server.stop();
        } catch (Exception e) {
        }
    }

    @Test
    public void addTest() {
        for (TestCaseService testCaseService : testCaseServices) {
            Integer sum = testCaseService.add(10, 5);
            Assert.assertNotNull(sum);
            Assert.assertEquals(15, sum.intValue());
        }
    }

}

I've also tried to create a TestCaseService bean

@Bean public TestCaseService testCaseService() ...

and provide it as a httpInvokerServiceExporter argument

@Bean public HttpInvokerServiceExporter httpInvokerServiceExporter(TestCaseService testCaseService)
...
httpInvokerServiceExporter.setService(testCaseService);

but the result is still the same.

What am I doing wrong? Thanks!

2

There are 2 best solutions below

0
On

I think the problem is that the Servlet is not accesible.

SERVER SIDE

Make sure you have in your WEB-INF/web.xml (on the app that is exposing the methods -SERVER-) this code:

<web-app>
...
<servlet>
    <servlet-name>remoting</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
    <servlet-name>remoting</servlet-name>
    <url-pattern>/services/*</url-pattern>
</servlet-mapping>
...
</web-app>

Here, the remote methods are served under "services", that is, for calling the method, the URL should be:

http://localhost:8080/sample/services/list

And you have to define this Servlet as accesible, by creating a bean (in my case under WEB-INF/remoting-servlet.xml):

<bean name="/list" class="org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter">
    <property name="service" ref="myObjectQueryService" />
    <property name="serviceInterface" value="com.kategor.myapp.sample.service.ObjectQueryService" />
</bean>

CLIENT SIDE

If your using Spring under the client (not as in your example), you must define a bean for accessing the remote resources, defining some beans (one for each public resource):

In this case, it would be:

<bean id="listService" class="org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean">
    <property name="serviceUrl" value="http://localhost:8080/sample/services/list" />
    <property name="serviceInterface" value="com.kategor.myapp.sample.service.ObjectQueryService" />
</bean>

In your example is right.

This way, calling the Service "listService", you would have all the methods available in the class com.kategor.myapp.sample.service.ObjectQueryService

@Controller
public class HomeController {

    // This is the remote service definition
    @Autowired
    private ObjectQueryService<MyObject, Long> objectQueryService;

    /* .... */

    /**
     * List all Objects retrieved through Web Service from a remote Server
     */
    @RequestMapping(value = "listRemoteWS", method = RequestMethod.GET)
    public String listRemoteWS(Locale locale, Model model) {

        StringBuilder result = new StringBuilder();
        try {

            // The Remote Service is called
            List objs = objectQueryService.findAll(0, 10);
            result.append(objs.size() + " objs found");

        for (MyObject o : objs) {
            result.append("<br>* ").append(o.getId()).append(" = ").append(o.getName());
        }


        } catch (Exception e) {

            result.append("No objs have been found");
            e.printStackTrace();

        }

        model.addAttribute("result", result);

        return "index";
    }

}

So I think the problem comes from the URL: maybe the service is not visible or this is not the correct path to it.

For more information, check this links (the first is really useful):

https://github.com/JamesEarlDouglas/barebones-spring-mvc/tree/master/reference/spring-remoting

http://www.ibm.com/developerworks/web/library/wa-spring3webserv/index.html

0
On

For me the problem was tomcat picked up two versions of the same applications. This raised the above error on running the client from STS in debug mode. So solution is to clean up all the expanded webapp folders in tomcat for the application. Then redeploy the application.