I've followed the tutorial for spring remoting, in particular HttpInvokerServiceExporter and have no problems setting up both the client and the server (factorybean).
Question is, I've noticed using Spring MVC, each interface is mapped to a particular URL
<bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="hello.htm">test_service</prop>
</props>
</property>
</bean>
<!-- *********************exposed web services*************************-->
<bean name="test_service" class="org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter">
<property name="serviceInterface" value="foo.webservices.HelloServiceInterface" />
<property name="service">
<ref bean="helloService"></ref>
</property>
Question is, if I have more than 1 method in my service interface, is it possible to map each of these interface methods to a URL themselves?
The idea behind HTTPInvokerServiceExporter is to provide an endpoint to receive remove method invocation.
On the server side it would be easy as configure a RemoteExporter, declaring the interface you want to expose and associating it to the real bean that will handle the invocations.
On the client it would be necessary configure the RemoteAcessor that basically needs the interface that is going be access on the server side.
The implementation over HTTP can be done using HttpInvokerServiceExporter on the server side like the following example:
Service Interface:
package foo.bar.services;
public interface MyService {
public int sum(int num1, int num2);
}
For this service you would have an implementation (let's say foo.bar.services.DefaultMyService).
The exposition and configuration on spring context would look like:
<bean name="myService" class="foo.bar.DefaultMyService" />
<bean name="/myService" class="org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter">
<property name="service" ref="myService"/>
<property name="serviceInterface" value="foo.bar.MyService"/>
</bean>
With this configuration I just intended to have a instance of my implementation of MyService being exposed under foo.bar.MyService interface over the URL mapped by /myService (bean name) in the simpliest case using BeanNameUrlHandlerMapping that does nothing else than map a URL to a bean with the URL value (this case /myService).
On the client side (consumer), you will have a bean configured just declaring the interface you expect the remote side is exposing. For our service would be something like:
<bean id="httpInvokerProxy" class="org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean">
<property name="serviceUrl" value="http://foo.bar.org/springSample/myService"/>
<property name="serviceInterface" value="foo.bar.MyService"/>
</bean>
At the moment spring instantiate the beans on client side, a proxy is instantiated and every method invocation would then be serialized and sent over HTTP to the endpoint (in this case http://foo.bar.org/springSample/myService. At the server side this request is deserialized and interpreted i.e. invoking the method on the real service being exposed (on our case DefaultMyService). The service will return something that will be serialized an gave as result to the HTTP request performed by the client. The client will receive it and deserialize it and return it to the original method invocator.
As you can see (and got from Spring documentation):
The server side will
Deserializes remote invocation objects and serializes remote
invocation result objects. Uses Java serialization just like RMI, but
provides the same ease of setup as Caucho's HTTP-based Hessian and
Burlap protocols.
The client side will
Serializes remote invocation objects and deserializes remote
invocation result objects. Uses Java serialization just like RMI, but
provides the same ease of setup as Caucho's HTTP-based Hessian and
Burlap protocols.
The serialization used with Spring Remoting on this case is Java serialization, meaning the HTTP request holds an entity body containing the serialized object (is good to keep in mind that in this case JVM version and class versions needs to be compatible).
The exposition is done as a whole, you could not separate it having one URL for each method of that interface. Therefore would be easier the use of Spring MVC and create a controller (#Controller) implement a method for each method you have on your interface annotating it as #RequestMapping (with the desired URL) and invoke the method on the service as follows the example:
Controller Sample
package foo.bar;
import foo.bar.service.MyService;
#Controller
public class MyService {
#Autowired
private MyService myService;
#RequestMapping("/sum/{num1}/{num2}")
public int sum(#PathVariable("num1") int num1, #PathVariable("num2") int num2) {
return myService.sum(num1, num2);
}
}
Using the context configuration
<context:component-scan base-package="foo.bar"/>
it would map the classes found on foo.bar and under packages automatically, meaning the Service implementation (DefaultMyService) could be mapped with #Service and #Autowired to the controller as done in the sample, without any bean configuration on the context xml.
But this will expose your service over REST interface, meaning it will handle HTTP plain requests that could be done by other consumers like a PHP consumer (this couldn't be done with Spring Remoting because it uses pure Java serialization).
If your client is Java you could definitively use Remoting and expose your service as a whole, if not the REST implementation using Spring MVC is a good solution.
Spring Documentation can be found here
I really recommend defining your controllers with the #Controller annotation. From the Spring documentation, start with adding a component scan to your Spring config.
<context:component-scan base-package="your.package.path"/>
Then, in a class, say, your.package.path.WhateverController, annotate the class:
#Controller
WhateverController
And annotate your methods with #RequestMapping:
#RequestMapping(value = "/helloWorld")
public ModelAndView helloWorld() {
...
}
#RequestMapping(value = "/project/{projectId}")
public ModelAndView helloWorld(#PathVariable String projectId) {
...
}
That's about it, multiple mappings per controller.
I think you need to tell us what you are trying to do first. If you are exposing your services to a universal web client, REST or SOAP would be a better option; if you are exposing your services to another Spring bean in another application, then Spring Remoting might suffice.
The comment "exposed web services" in your spring configuration file seems unclear of your purpose.
When you expose a service to remote clients, you always need to provide a contract to let the remote clients know what's possible. REST exposes that contract using URL's; SOAP exposes that contract using WSDL's; and Spring Remoting just directly gives the client that contract in a java interface, so the client can inject that interface into its own beans and use it like a locally defined bean.
In your question you mentioned mapping a method to an URL, Spring Remoting can't do that because it exposes intefaces; what you want to do sound very REST to me. And I agree with #stevebrown, exposing your services using a mapped controller is a good approach.
Related
So I have spring mvc up and running with hibernate.
I'm reading how I can add Restful endpoints using the #ResponseBody: http://blog.springsource.com/2010/01/25/ajax-simplifications-in-spring-3-0/
So if I have an endpoint like:
http://localhost:8080/services/user/get/1
I will fetch a user with userId=1, how will I return and how will it convert my user object to an XML representation?
Do I have to do something special in my User.java class for this to work?
The way I've done this in the past is as follows:
Annotate your User class with JAXB annotations (for example #XmlRootElement)
Hook up a suitable Spring HttpMessageConverter as in this documentation
When sending a request, make sure to include an Accept header: Accept: application/xml
By doing this, you'll have total control of how your User gets "flattened" to XML, but you're leaving all the hard work (determining the correct endpoint, data conversion) to Spring.
The conversion of method return types annotated with #ResponseBody into actual HTTP Responses is accomplished by implementations of the HttpMessageConverter interface. Spring comes with an implementation for JAXB. So if you can annotate your User class with JAXB annotations, that may work for you. If User is a Hibernate annotated Entity, adding JAXB to it also can get hairy. You may want to create an intermediate object for the JAXB.
Alternately you can use any arbitrary Marshaller by using the Marshalling Message Converter. There are quite a few implementations of Marshaller built in to choose from, or you can always write your own.
You turn on converters by registering them on the AnnotationMethodHandlerAdapter (in the dispatcher servlet xml:
<bean id="xmlMessageConverter" class="org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter">
<property name="supportedMediaTypes" value="text/xml" />
</bean>
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<list>
<ref bean="xmlMessageConverter"/>
</list>
</property>
</bean>
Spring MVC have integration with XStream (convert objects to XML)
This is an interesting approach: http://www.stupidjavatricks.com/?p=54
You have to set the XStreamAlias annotation in your class and configure Spring to use XStream.
I also indicate Spring that the output is xml. In your url example that should be:
http://localhost:8080/services/user/get/1.xml
I'm using spring and in my client, a web app, I need to interact with a Jax-WS webservice. I currently have it working via annotating the service interface with the #WebServiceRef annotation. However, I need the wsdlLocation property to be injected because, obviously Sun Microsystems or Oracle, the web service wsdl location in production will be different to what's being used during development.
How can I inject the wsdlLocation?
Here's an extremely simplified version of the code:
//This client service lives in the web app. wsimport used to generate artifacts.
#Component
public class MyClientServiceImpl implements MyClientService {
#WebServiceRef(wsdlLocation = "http://localhost:8080/ws/MyOtherService/the.wsdl", value = MyOtherServiceService.class)
//Interface generated by wsimport
private MyOtherService otherService;
#Override
public List<SomeSearchData> search(String searchString) {
return otherService.search(searchString);
}
}
This is semi outlined in the JAX-WS FAQ. You need to inject the endpoint string as a standard member variable and then use...
((BindingProvider)proxy).getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, this.injectedEnpointURL);
You can use LocalJaxWsPortProxyFactoryBean. You can configure WSDL URL (among other things) via this factory bean. Here is a configuration snippet from the official documentation:
<bean id="accountWebService" class="org.springframework.remoting.jaxws.JaxWsPortProxyFactoryBean">
<property name="serviceInterface" value="example.AccountService"/>
<property name="wsdlDocumentUrl" value="http://localhost:8888/AccountServiceEndpoint?WSDL"/>
<property name="namespaceUri" value="http://example/"/>
<property name="serviceName" value="AccountService"/>
<property name="portName" value="AccountServiceEndpointPort"/>
</bean>
Then you can let Spring autowire this dependency into your target bean (e.g. MyClientServiceImpl).
Anyone knows why apparently it is not possible to use AOP with annotated MVC Controllers? (see Post).
I have a #Controller that stops working as soon as I add a pointcut to it.
The problem is not that the interceptor is not being called, but rather the #Controller simply stops working (in the log you can see that instead of "Mapped URL path [/xx] onto handler 'Yyy'" you get a "no URL paths identified").
I know there is a mechanism for adding interceptors to controllers via the handlerMapping but my question is specific to AOP interceptors. Aren't annotated controllers just pojos in the Spring container as any other pojo? What is the difference? Why?
#Controller
#RequestMapping("/user")
public class RestTestImpl implements RestTest {
#RequestMapping(value="/", method={RequestMethod.GET})
public #ResponseBody String deleteUsers(String arg) {
return "Xxxxx";
}
}
In my servlet-Context I have:
<context:component-scan base-package="org.xxx.yyy"></context:component-scan>
<mvc:annotation-driven />
<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
. . .
</bean>
And everything works just great.
But when I add:
<aop:config>
<aop:pointcut expression="execution(* org.xxx.*(..))" id="pc1"/>
<aop:advisor advice-ref="hibernateInterceptor" pointcut-ref="pc1" order="2" />
</aop:config>
The controller stops being a controller (no errors, simply it stops binding to the specified URL)!
From the Spring MVC Reference:
Note
When using controller interfaces (e.g. for AOP proxying),
make sure to consistently put all your
mapping annotations - such as
#RequestMapping and #SessionAttributes
- on the controller interface rather than on the implementation class.
Granted, this note is well hidden :-)
I ran into the same issue and found out the solution.
Indeed your controller (annotated by #Controller) and your aspects (annotated by #Aspect) should be in the same Spring context.
Usually people define their controllers in the dispatch-servlet.xml or xxx-servlet.xml and their service beans (including the aspects) in the main applicationContext.xml. It will not work.
When Spring initializes the MVC context, it will create a proxy for your controller but if your aspects are not in the same context, Spring will not create interceptors for them.
The above ssertion does not depend
on the way your declare your controllers/aspects (by manual XML declaration or annotation style)
on the proxying style you choose (JDK proxy or CGLIB)
I've tested all the combinations and they all work as long as the controller & aspects are in the same Spring context
My best guess without doing some serious digging is because Spring's AOP mechanism that you are using is wrapping the target classes in proxy classes which end up loosing their annotation or the original annotation gets dropped after weaving.
I am sure there is a better answer and I'll expand on mine as I think of a better more clear way to present it.
I have a static method I have no control over: MyUtils.getServiceURL() which returns a URL. I need to extract just the port from this URL to set a property on a bean:
<bean id="myBean>
<property name="defaultPort" value="?????"/>
</bean>
I can get the string value of the URL as a bean like this:
<bean id="serviceURL" class="MyUtils" factory-method="getServiceURL" />
I'm probably just going to write a method to parse the URL in myBean and extract the port. I was wondering if there was a way to avoid having to do this, and configure this directly in the spring context?
No need for custom classes, or parsers. Remember, a bean is just a class with get/is/set methods. A java.net.URL class qualifies as such.
Solution: Use a java.net.URL as a Spring-configurable bean and call it's getPort method.
Remember, in Spring, you can wire anything as a bean very easily so long as it sports methods using the get/is/set Bean convention. The java.net.URL class does such a thing.
** warning ** I'm just typing this out of my a$$, you'll have to check for any syntax shenanigans that I might be introducing in this Spring-config pseudo-code. One thing that is certain is that the concept will work with Spring 2.5 and that it relies on the util schema.
If you are using an older version of Spring, you'll have to use a PropertyPathFactoryBean. If you are using Spring 3.0, you'll want to use Spring expression language (EL), but I can't comment on the later since I'm not familiar with Spring 3.0.
In java:
int port = (new URL(MyUtils.getServiceURL()).getPort()
In Spring:
<bean id="serviceURL" class="MyUtils" factory-method="getServiceURL" />
<bean id="myURL" class="java.net.URL">
<constructor-arg>
<ref-bean="serviceURL"/>
</constructor-arg>
</bean>
<util:property-path id="defaultPort" path="myURL.port"/>
<bean id="myBean>
<property name="defaultPort" ref="defaultPort"/>
</bean>
There might be a way to consolidate all these four expressions into three or less, don't know if that will improve readability, though. The concept remains the same, though. Treat a java.net.URL instance as a bean, set its URL via its constructor, and get a hold (via Spring) of its getPort() method.
** edit **:
If you are using Spring 2.5 you can create an inline groovy bean that does all that for you. I've seen people doing that as integration glue to get rid of multitude of temp Spring bean place holders. That's the best choice IMO when you need to define a class (when it's simpler than just using Spring tags) and when you know such a class won't be used outside of Spring wiring of things.
Not I can think of. Either way, you probably have to write something to parse the port out. Since you have no control of that static method, perhaps you may want to utilize the adapter pattern to hide that static method. Doing so also makes your code easier to test because you can easily mock that external API out. For example:-
public interface URLServiceAdapter {
int getServiceURLPort();
}
public class URLServiceAdapterImpl implements URLServiceAdapter {
public int getServiceURLPort() {
return MyUtils.getServiceURL().getPort();
}
}
Your beans will then rely on your adapter class instead of MyUtils.getServiceURL() directly:-
<bean id="urlServiceAdapter" class="project.URLServiceAdapterImpl" />
That way, you can do something like this:-
#Autowired
private UrlServiceAdapter urlServiceAdapter;
...
bean.setDefaultPort(urlServiceAdapter.getServiceURLPort());
SpEL is your friend.
<bean id="myBean>
<property name="defaultPort"
value='#{ T(com.foo.MyUtils).getServiceURL().split(":")[2].split("/")[0] }'/>
</bean>
Enjoy,
I am using the Spring MVC for a project, and I am using the Spring DispatcherServlet to map the request's coming into the application to the controllers written elsewhere. I am looking for a way to have a default handler ( a catch all handler) if the request doesn't map to any of the exisiting controller-view maps. This currently shows a Resource not found exception, but I want to know if a catch all unmatched requests function is available in the Spring.
Every HandlerMapping strategy in Spring MVC has a defaultHandler property for just this purpose.
This is easy if your Spring config is already specifying a HandlerMapping object explicitly (e.g. a SimpleUrlHandlerMapping), but it's less obvious if you're relying on the defaults to supply a HandlerMapping for you.
For example, if you're using annotated controllers, then you're probably relaying on the default declaration of DefaultAnnotationHandlerMapping which Spring supplies automatically. However, you can provide your own bean to override the default:
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
<property name="defaultHandler" ref="myDefaultHandler"/>
</bean>
This same pattern will work with any Handlermapping type, just substitute the class name.