I want to transform an existing XML-based webservice to a REST webservice. While the services are working already, I'm struggling with implementing the security.
In the former implementation, we used interceptors like this (file ws-server-context.xml):
<jaxws:endpoint id="someService" implementor="..." address="/..." >
<jaxws:inInterceptors>
<bean class="org.apache.cxf.binding.soap.saaj.SAAJInInterceptor" />
<bean class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor">
<constructor-arg>
<map>
<entry key="action" value="UsernameToken" />
<entry key="passwordType" value="PasswordText" />
<entry key="passwordCallbackRef" value-ref="sessionService" />
</map>
</constructor-arg>
</bean>
</jaxws:inInterceptors>
</jaxws:endpoint>
Whenever the address of this endpoint is called, the method handle(Callback[] callbacks) of the bean sessionService is invoked, which checks for proper credentials (username + token). This bean implements the interface CallbackHandler.
How can this approach be implemented in JAX-RS? The endpoints are defined at the webservice classes themself (#Path), so do I need to use any annotations there? How do I register the interceptors?
Thanks for your help!
Instead of the interceptor, you can declare a filter in your web.xml -
<filter>
<display-name>MyFilter</display-name>
<filter-name>MyFilter</filter-name>
<filter-class>com.*.MyFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>MyFilter</filter-name>
<url-pattern></url-pattern> <!-- keep this same as your rest servlet's url pattern -->
</filter-mapping>
This class will be called before your JAX-RS implementation.
You can refer to the callBackHandler from within the filter class.
Related
in process of exposing existing statefull service as a RESTfull service.
I do not want to make any changes to any existing java class.I have been able to configure other annotations such as #path, #GET using spring-config.xml
spring-config.xml
<!-- Inquiry Services -->
<bean id="retrieveContactHistoryBP" class="com.csc.fs.ws.contact.history.impl.RetrieveContactHistoryBPService"/>
<!-- Update Services -->
<bean id="startContactBP" class="com.csc.fs.ws.contact.impl.StartContactBPService"/>
<!-- REST services -->
<bean id="startContactBPRest" class="com.csc.fs.rest.contact.StartContactBP" scope="prototype" />
<bean id="retrieveContactHistoryBPRest" class="com.csc.fs.rest.contact.RetrieveContactHistoryBP" scope="prototype" />
<!-- Exposing beans as rest services -->
<jaxrs:server id="restServer" address="/rest/">
<jaxrs:model id="restModel">
<jaxrs:resource name="com.csc.fs.rest.contact.RetrieveContactHistoryBP" path="retrieveContactHistoryBP">
<jaxrs:operation name="retrieve" path="{partyId}" consumes="application/json" produces="application/json" verb="GET">
<jaxrs:param name="req" type="CONTEXT"/>
<jaxrs:param name="partyId" type="PATH"/>
</jaxrs:operation>
</jaxrs:resource>
<jaxrs:resource name="com.csc.fs.rest.contact.StartContactBP" path="startContactBP">
<jaxrs:operation name="startContact" path="/" consumes="application/json" produces="application/json" verb="PUT">
<jaxrs:param name="req" type="CONTEXT"/>
<jaxrs:param name="startContact" type="REQUEST_BODY"/>
</jaxrs:operation>
</jaxrs:resource>
</jaxrs:model>
<jaxrs:serviceBeans>
<!-- <ref bean="startContactBPRest"/> --> <!-- Instead configure above -->
<!-- <ref bean="retrieveContactHistoryBPRest"/> -->
</jaxrs:serviceBeans>
<jaxrs:extensionMappings>
<entry key="feed" value="application/atom+xml"/>
<entry key="json" value="application/json"/>
<entry key="xml" value="application/xml"/>
<entry key="html" value="text/html"/>
</jaxrs:extensionMappings>
<jaxrs:providers>
<ref bean="jaxbProvider"/>
<ref bean="jsonProvider" />
</jaxrs:providers>
</jaxrs:server>
The thing I am facing problem is with the #XmlRootElement. I have not been successful in configuring it through the xml.
And I get the following error when trying to access the REST service
org.apache.cxf.interceptor.Fault
org.apache.cxf.interceptor.AbstractFaultChainInitiatorObserver.onMessage(AbstractFaultChainInitiatorObserver.java:67)
org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:315)
org.apache.cxf.transport.ChainInitiationObserver.onMessage(ChainInitiationObserver.java:113)
org.apache.cxf.transport.servlet.ServletDestination.invoke(ServletDestination.java:105)
org.apache.cxf.transport.servlet.ServletController.invokeDestination(ServletController.java:461)
org.apache.cxf.transport.servlet.ServletController.invoke(ServletController.java:188)
org.apache.cxf.transport.servlet.AbstractCXFServlet.invoke(AbstractCXFServlet.java:148)
org.apache.cxf.transport.servlet.AbstractHTTPServlet.handleRequest(AbstractHTTPServlet.java:179)
org.apache.cxf.transport.servlet.AbstractHTTPServlet.doGet(AbstractHTTPServlet.java:108)
javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
org.apache.cxf.transport.servlet.AbstractHTTPServlet.service(AbstractHTTPServlet.java:159)
root cause
java.lang.NullPointerException
org.apache.cxf.jaxrs.model.wadl.WadlGenerator.handleOperation(WadlGenerator.java:310)
org.apache.cxf.jaxrs.model.wadl.WadlGenerator.handleResource(WadlGenerator.java:253)
org.apache.cxf.jaxrs.model.wadl.WadlGenerator.handleRequest(WadlGenerator.java:185)
org.apache.cxf.jaxrs.impl.RequestPreprocessor.checkMetadataRequest(RequestPreprocessor.java:189)
org.apache.cxf.jaxrs.impl.RequestPreprocessor.preprocess(RequestPreprocessor.java:82)
org.apache.cxf.jaxrs.interceptor.JAXRSInInterceptor.processRequest(JAXRSInInterceptor.java:112)
org.apache.cxf.jaxrs.interceptor.JAXRSInInterceptor.handleMessage(JAXRSInInterceptor.java:88)
org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:255)
org.apache.cxf.transport.ChainInitiationObserver.onMessage(ChainInitiationObserver.java:113)
org.apache.cxf.transport.servlet.ServletDestination.invoke(ServletDestination.java:105)
org.apache.cxf.transport.servlet.ServletController.invokeDestination(ServletController.java:461)
org.apache.cxf.transport.servlet.ServletController.invoke(ServletController.java:188)
org.apache.cxf.transport.servlet.AbstractCXFServlet.invoke(AbstractCXFServlet.java:148)
org.apache.cxf.transport.servlet.AbstractHTTPServlet.handleRequest(AbstractHTTPServlet.java:179)
org.apache.cxf.transport.servlet.AbstractHTTPServlet.doGet(AbstractHTTPServlet.java:108)
javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
org.apache.cxf.transport.servlet.AbstractHTTPServlet.service(AbstractHTTPServlet.java:159)
So, Is there a way to configure the information in the XmlRoot annotation externally, so we don’t have to add it to Java code?
From the Apache-cxf documentation on jaxrs-data-bindings:
Alternatively to using #XmlRootElement and Collection wrappers, one can
provide an Object factory which will tell JAXB how to marshal a given
type (in case of Collections - its template type). Another option is to
return/accept a JAXBElement directly from/in a given method.
Another option is to register one or more JAX-RS ContextResolver providers
capable of creating JAXBContexts for a number of different types. The
default JAXBElementProvider will check these resolvers first before
attempting to create a JAXBContext on its own.
I'm developing an application in JSP using SimpleFormController with Spring MVC 3.0.2 using Hibernate. Everything is fine. I'm also using Validator to validate forms on the server side. It's also going on well.
Now, I need to use Ajax as an example, when a country is selected from a drop down (<form:select><form:option></form:option></form:select>), the states corresponding to that country should be populated from the database in the state drop down.
I have done such things using Ajax in places but yet not with Spring MVC. I have gone through many tutorials/articles about SimpleFormController on Google but none of them were using Ajax. I couldn't find a single idea about how to use Ajax with SimpleFormController.
With annotated controllers (#Controller), the thing can be made easy because methods can be mapped using the #RequestMapping annotation (nevertheless I haven't yet used it but I think I can).
But with SimpleFormController, I don't have any precise idea about how to handle Ajax requests in the Spring controller (which methods to be mapped and how). With SimpleFormController, I'm usually associated with the onSubmit(), showForm() and referenceData() methods.
Could you please expose some thoughts on how can an Ajax request be made on SimpleFormController, which methods can be mapped and how? (I don't want the full code anymore. A very simple example (if and only if it's possible) or furthermore specific links where the use of Ajax with the SimpleFormController is explained would be quite enough for me to study).
You could always just have a separate #Controller to handle the ajax requests. If you can have custom jsp on the view, there is nothing stopping you from handling an ajax request on the page. Just bind the onchange event of the select box to an ajax call pointing to the other Controller you made.
In terms of keeping it bound to just that SimpleFormController, I don't think this is possible, but if you create a new RESTful controller that the form would use, other parts of the website will be able to use this new controller as well.
In complement to dardo's answer, using both spring MVC 2 and MVC 3 controllers is possible, but a bit tricky to set up.
In order to use both SimpleFormController and #Controller controllers in the same Spring context, I used to following definition :
<!-- ======== MVC Spring 3.x ======== -->
<!-- Scans within the base package of the application for #Components to configure as beans #Controller, #Service, #Configuration, etc. -->
<context:component-scan base-package="com.your.package" />
<!-- Enables the Spring MVC #Controller programming model -->
<!-- It's a shortcut equivalent to the (more complete) bean definition below (see bean AnnotationMethodHandlerAdapter).-->
<!--<mvc:annotation-driven />-->
<!-- This HandlerAdapter will register spring 3.x controllers (#Controller) into the DispatcherServlet -->
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<array>
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<property name="writeAcceptCharset" value="false"/>
</bean>
<bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter"/>
<bean class="org.springframework.http.converter.xml.SourceHttpMessageConverter"/>
<bean class="org.springframework.http.converter.xml.XmlAwareFormHttpMessageConverter"/>
<bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"/>
</array>
</property>
</bean>
<!-- This HandlerMapping allows to map urls defined in #RequestMapping annotations to the corresponding controllers -->
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
</bean>
<!-- ======== MVC Spring 2.x ======== -->
<!-- This HandlerAdapter will register spring 2.x controllers (#Controller) into the DispatcherServlet -->
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter" />
<!-- Url mapper -->
<bean id="urlMapper" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="urlMap">
<map>
<entry key="/foo.do" value-ref="fooController" />
<entry key="/bar.do" value-ref="barController" />
...
</map>
</property>
</bean>
I'm building very basic mvc application with Spring. It has one controller that should invoke validation on request body. The problem is that if I define the mapping in web.xml it stops finding the right controller, but when I modify the servlet application context Spring star making some new bindings on the fly but this time annotation based validation is ignored. How can I controll mappings in web.xml while still invoking annotation based validation?
Here are the details:
The controller:
#Controller
#RequestMapping("/api")
public class UserActionsController {
#RequestMapping(value="/choice", method = RequestMethod.POST)
public #ResponseBody NameValue addUserChoice(#Valid #RequestBody NameValue action)
{
return action;
}
}
This is the servlet application context:
<mvc:annotation-driven/>
<context:component-scan base-package="com.my.package" />
<bean
class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<property name="mediaTypes">
<map>
<entry key="json" value="application/json" />
</map>
</property>
<property name="defaultContentType" value="application/json" />
<property name="defaultViews">
<list>
<bean
class="org.springframework.web.servlet.view.json.MappingJacksonJsonView" />
</list>
</property>
</bean>
Web xml:
<servlet>
<servlet-name>action-api</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>action-api</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
The configuration above is working. The problem starts when I try to change web.xml so the controller will only be responsible for "/api/*". I change it to <url-pattern>/api/*</url-pattern>. In that case Spring cannot find the right controller.
(DispatcherServlet:819) - DispatcherServlet with name 'action-api' processing POST request for [/api/choice]
(RequestMappingHandlerMapping:209) - Looking up handler method for path /choice
(RequestMappingHandlerMapping:219) - Did not find handler method for [/choice]
(PageNotFound:1080) - No mapping found for HTTP request with URI [/api/choice] in DispatcherServlet with name 'action-api'
(DispatcherServlet:913) - Successfully completed request
Modifying the servlet application context helps, Spring now able to find the controller, but validation is not invoked anymore.
<bean
class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="alwaysUseFullPath" value="true" />
<property name="messageConverters">
<util:list id="beanList">
<bean class="org.springframework.http.converter.StringHttpMessageConverter"/>
<bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"/>
</util:list>
</property>
</bean>
<bean
class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
<property name="alwaysUseFullPath" value="true" />
</bean>
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="alwaysUseFullPath" value="true" />
</bean>
Here is the log:
(DispatcherServlet:819) - DispatcherServlet with name 'action-api' processing POST request for [/api/choice]
(RequestMappingHandlerMapping:209) - Looking up handler method for path /choice
(RequestMappingHandlerMapping:219) - Did not find handler method for [/choice]
(DefaultAnnotationHandlerMapping:124) - Mapping [/api/choice] to HandlerExecutionChain with handler [com.my.package.controller.UserActionsController#1f86dbd] and 1 interceptor
(HandlerMethodInvoker:638) - Reading [com.my.package.model.NameValue] as "application/json" using [org.springframework.http.converter.json.MappingJacksonHttpMessageConverter#2059ef]
(HandlerMethodInvoker:173) - Invoking request handler method: public com.my.package.model.NameValue com.citypath.dima.controller.UserActionsController.addUserChoice(com.my.package.model.NameValue)
(AnnotationMethodHandlerAdapter:1037) - Written [com.my.package.model.NameValue#166685b] as "application/json;charset=UTF-8" using [org.springframework.http.converter.json.MappingJacksonHttpMessageConverter#2059ef]
(DispatcherServlet:957) - Null ModelAndView returned to DispatcherServlet with name 'action-api': assuming HandlerAdapter completed request handling
(DispatcherServlet:913) - Successfully completed request
Looks like Spring making some binding on the fly, but this time validators are ignored.
I need to have 2 controllers for, say '/api' and '/something'. How can I define it in web.xml so Spring will be able to locate them and to invoke validation?
Thanks.
Spring #Controllers URLs are always interpreted relative the the Spring Dispatcher Servlet that handles them. So if you map the dispatcher servlet to /api/* in web.xml then the URL to your controller above is /api/api/choice
So you can configure two spring dispatcher servelts in web.xml one mapped to /api in the web.xml and one mapped to /somethingelse in web.xml then you can just remove /api from the #RequestMappings
In my app I am using a single Dispatcher Servlet for api and UI and I use public static final String called URL in my various API controllers to build up the paths to the various resources exposed by the API. Below is an example from my API.
#Controller
#RequestMapping(CompanyPermissionsResourceController.PATH)
public class CompanyPermissionsResourceController extends BaseApiController
{
public static final String PATH = CompanyResourceController.PATH + "/permissions";
Are you sure you are making post request to /api/choice?
#RequestMapping(value="/choice", method = RequestMethod.POST)
Try Changing to
#RequestMapping(value="/choice", method = RequestMethod.GET)
public #ResponseBody NameValue addUserChoice(#Valid #RequestBody NameValue action)
{
return action;
}
I don't think it works like this. Put all the path /api/choice at method level.
I have a web application which is exposing a rest web service by cxf jax-rs. In my application context file I have something like this:
...
<bean id="service" class="SomeClass">
<constructor-arg index="0">
<ref bean="bean1" />
</constructor-arg>
<constructor-arg index="1"
value="some value" />
</bean>
<jaxrs:server id="restContainer" address="/">
<jaxrs:serviceBeans>
<ref bean="service" />
</jaxrs:serviceBeans>
<jaxrs:providers>
<bean class="org.codehaus.jackson.jaxrs.JacksonJsonProvider" />
</jaxrs:providers>
</jaxrs:server>
...
I also have a constructor in my service class that accepts those two parameters and initializes the service.
When I deploy my application, spring context loader is creating the service bean correctly and the correct constructor is getting called. The problem is when the first Rest request comes to service. Cxf Jax-rs is creating its own instance by "default constructor" and I will lose those two properties.
The same thing happens if I user property setters instead of constructor args. When I researched cxf jax-rs, none of the examples had a service which has some properties! Is there a reason for this or is this some implementation constraint by cxf?
Any ideas?
Which interceptor can use in Spring 3.0 ?
I want to get Action name and method name in this.
HandlerInterceptorAdapter is working , but i cant get the method name and action name on this..
Any Help..?
dispatcher-servlet.xml
<!-- Handle Interceptor -->
<mvc:interceptors> <bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor"
/> <mvc:interceptor> <mvc:mapping path="/*" />
<bean class="com.asd.MyInterceptor"
/>
</mvc:interceptor> </mvc:interceptors>
Implement HandlerInterceptor interface. One of the parameters in preHandle and postHandle methods of that interface is Object handler. It is in fact a HandlerMethod instance which should provided you everything you need.