RESTEasy Asynchronous Job Service + Spring MVC? - rest

I am using the RESTEasy integration with Spring MVC as described here in section "39.2. Spring MVC Integration"
http://docs.jboss.org/resteasy/docs/2.0.0.GA/userguide/html/RESTEasy_Spring_Integration.html
I'd like to experiment with RESTEasy's implementation of the "async job service" as described here:
http://docs.jboss.org/resteasy/docs/2.3.4.Final/userguide/html/async_job_service.html
Reading the doc, my assumption is that RESTEasy will intercept the request and respond with a HTTP 202 and do the job queueing and tracking and create the .../async/jobs endpoint. So I modified my web.xml as described in the documention. Here's what it looks like:
<web-app>
<context-param>
<param-name>resteasy.async.job.service.enabled</param-name>
<param-value>true</param-value>
</context-param>
<context-param>
<param-name>resteasy.async.job.service.base.path</param-name>
<param-value>/asynch/jobs</param-value>
</context-param>
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
I tried to test whether this works by making a call to one of my REST services like this (running under Tomcat 6):
POST http://localhost:8080/myservice?async=true
According to the documentation this service is supposed to return a HTTP 202 but it returned the normal HTTP 200 as if I had called without the async=true query param.
I didn't change anything else with my services. Am I missing something?
Btw, here's what the service annotation looks like:
#Controller
#Path("/")
public class MyServices {
#POST
#Produces({MediaType.APPLICATION_XML})
#Path("myservice")
public Response createMyResource(#Context UriInfo uri, myResource) {
// create the resource
// construct and return a OK Response
}
}
Has anyone tried this successfully? If not, do you have another easy to use alternative for making async calls to RESTEasy RESTful services (that also works with Spring running under tomcat)
Thanks.

Try with asynch=true not async=true

Related

Jersey REST service

Am using Jersey 1.19 for a REST service..
The URL pattern in web.xml is:
<servlet-mapping>
<servlet-name>Jersey REST Service</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
In the Java class am using a method which is doing a kind of redirect to another page saved in a web folder. It looks fine up to the point when I call a specific resource:
http://localhost:8084/userProfile/rest/user
This should redirect to:
http://localhost:8084/userProfile/signup/index.jsp
but it redirects to:
http://localhost:8084/userProfile/rest/signup/index.jsp
Which normally doesn't exist.
The method in the Java Class:
#Path("/user")
public class userProfile {
#GET
#Produces(MediaType.TEXT_HTML)
public Response returnForm() throws URISyntaxException {
URI uri = new URI("/signup/index.jsp");
return Response.temporaryRedirect(uri).build();
}
}
How can I avoid redirection to a URL including /rest/?
The solution is/was really simple... the Path should go one step back to
avoid the url-pattern /rest/*:
....
URI uri = new URI("../signup/index.jsp");
...
Thx!

No 'Access-Control-Allow-Origin' header is present on the requested resource - Resteasy

I am working on a webapplication comprises UI-Angular , Server-Java , RestEasy 3.0.9.Final for rest api calls
When i tried to access the rest service from another domain am getting below error
CANNOT LOAD Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8080' is therefore not allowed access.
I configured my server side to respond with the cross domain calls and this is working with the GET Call but POST Call is creating ERROR
web.xml
<context-param>
<param-name>resteasy.providers</param-name>
<param-value>com.test.sample.app.CorsFeature</param-value>
</context-param>
<listener>
<listener-class>
org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>resteasy-servlet</servlet-name>
<servlet-class>
org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>com.test.sample.app.Application</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>resteasy-servlet</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
<context-param>
<param-name>resteasy.servlet.mapping.prefix</param-name>
<param-value>/rest</param-value>
</context-param>
<context-param>
<param-name>resteasy.scan</param-name>
<param-value>true</param-value>
</context-param>
Service class
#GET
#Path("/getnameAtt")
#Produces(MediaType.APPLICATION_JSON)
public Response getHostnameAttributes() {
return Response
.status(200)
.header("Access-Control-Allow-Origin", "*")
.header("Access-Control-Allow-Headers",
"origin, content-type, accept, authorization")
.header("Access-Control-Allow-Credentials", "true")
.header("Access-Control-Allow-Methods",
"GET, POST, PUT, DELETE, OPTIONS, HEAD")
.header("Access-Control-Max-Age", "1209600")
.entity(new TestImpl().getHostNameAttributes())
.build();
}
#POST
#Path("/getSeq")
#Produces(MediaType.APPLICATION_JSON)
public Response getCurrentSequence(String request) {
return Response
.status(200)
.header("Access-Control-Allow-Origin", "*")
.header("Access-Control-Allow-Headers",
"origin, content-type, accept, authorization")
.header("Access-Control-Allow-Credentials", "true")
.header("Access-Control-Allow-Methods",
"GET, POST, PUT, DELETE, OPTIONS, HEAD")
.header("Access-Control-Max-Age", "1209600")
.entity(new TestImpl().getCurrentSeq(request))
.build();
}
Since i am new to resteasy not able to figure out why this was not working.
Any help would be greatly appreciated . Waiting for your response.
Thanks
Your resource methods won't get hit, so their headers will never get set. The reason is that there is what's called a preflight request before the actual request, which is an OPTIONS request. So the error comes from the fact that the preflight request doesn't produce the necessary headers.
For RESTeasy, you should use CorsFilter. You can see here for some example how to configure it. This filter will handle the preflight request. So you can remove all those headers you have in your resource methods.
See Also:
HTTP access control (CORS)
Seems your resource POSTmethod won't get hit as #peeskillet mention. Most probably your ~POST~ request won't work, because it may not be a simple request. The only simple requests are GET, HEAD or POST and request headers are simple(The only simple headers are Accept, Accept-Language, Content-Language, Content-Type= application/x-www-form-urlencoded, multipart/form-data, text/plain).
Since in you already add Access-Control-Allow-Origin headers to your Response, you can add new OPTIONS method to your resource class.
#OPTIONS
#Path("{path : .*}")
public Response options() {
return Response.ok("")
.header("Access-Control-Allow-Origin", "*")
.header("Access-Control-Allow-Headers", "origin, content-type, accept, authorization")
.header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS, HEAD")
.header("Access-Control-Max-Age", "2000")
.build();
}
After facing a similar issue, below is what I did :
Created a class extending javax.ws.rs.core.Application and added a Cors Filter to it.
To the CORS filter, I added corsFilter.getAllowedOrigins().add("http://localhost:4200");.
Basically, you should add the URL which you want to allow Cross-Origin Resource Sharing. Ans you can also use "*" instead of any specific URL to allow any URL.
public class RestApplication
extends Application
{
private Set<Object> singletons = new HashSet<Object>();
public MessageApplication()
{
singletons.add(new CalculatorService()); //CalculatorService is your specific service you want to add/use.
CorsFilter corsFilter = new CorsFilter();
// To allow all origins for CORS add following, otherwise add only specific urls.
// corsFilter.getAllowedOrigins().add("*");
System.out.println("To only allow restrcited urls ");
corsFilter.getAllowedOrigins().add("http://localhost:4200");
singletons = new LinkedHashSet<Object>();
singletons.add(corsFilter);
}
#Override
public Set<Object> getSingletons()
{
return singletons;
}
}
And here is my web.xml:
<web-app id="WebApp_ID" version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<display-name>Restful Web Application</display-name>
<!-- Auto scan rest service -->
<context-param>
<param-name>resteasy.scan</param-name>
<param-value>true</param-value>
</context-param>
<context-param>
<param-name>resteasy.servlet.mapping.prefix</param-name>
<param-value>/rest</param-value>
</context-param>
<listener>
<listener-class>
org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap
</listener-class>
</listener>
<servlet>
<servlet-name>resteasy-servlet</servlet-name>
<servlet-class>
org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher
</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>com.app.RestApplication</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>resteasy-servlet</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
</web-app>
The most important code which I was missing when I was getting this issue was, I was not adding my class extending javax.ws.rs.Application i.e RestApplication to the init-param of <servlet-name>resteasy-servlet</servlet-name>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>com.app.RestApplication</param-value>
</init-param>
And therefore my Filter was not able to execute and thus the application was not allowing CORS from the URL specified.

Spring MVC Servlet being hit twice for a POST request

I've got an estrange issue while using Spring MVC in order to implement RESTful services for my web application. Everything seems to work OK while performing GET requests, however, the behaviour I'm dealing with when doing POST requests puzzles me. Well, I've implemented this very basic controller code:
#Controller
#RequestMapping("/services")
public class RestService {
#RequestMapping(value = "/test/post", method = RequestMethod.POST)
public void postTest(#RequestBody String postString)
throws PersistenceException {
System.out.println(postString);
}
}
When I perform a POST request against it using Curl:
curl --data "Hello world" http://localhost:8080/SpringMVC-REST/services/test/post
First time my Controller is reached properly and the String is displayed. However, don't know why, the Spring MVC servlet is being called again after that, in this case with a wrong url request. The framework is not finding the matching service case, obviously:
Jun 02, 2014 4:06:21 PM org.springframework.web.servlet.DispatcherServlet noHandlerFound
WARNING: No mapping found for HTTP request with URI [/SpringMVC-REST/services/test/services/test/post] in DispatcherServlet with name 'mvc-dispatcher'
Debugger's stack seems to be slightly different for the first and second cases:
It seems like second time the Spring MVC framework is trying to render the output, even I'm not interested in it, cause I'm not accesing it via web UI. The servlet configuration I use is the standard one:
<web-app id="WebApp_ID" version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<display-name>Spring MVC REST</display-name>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/mvc-dispatcher-servlet.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>mvc-dispatcher</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>mvc-dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
That happens to me with Tomcat 6 and 7 and spring-web 3.2.8.RELEASE. Can anybody see the problem here?
use #ResponseBody before method return type..it should solve your problem.
so it should be like
#Controller
#RequestMapping("/services")
public class RestService {
#RequestMapping(value = "/test/post", method = RequestMethod.POST)
public #ResponseBody void postTest(#RequestBody String postString)
throws PersistenceException {
System.out.println(postString);
}
}

Tomcat7 REST Service with Basic Authentification XMLHttpRequest

I'm just setting up a small TestScenario. I'm exposing a REST Service on Tomcat 7 with Jersey. The service is called by another Javascript/HTML5 Application via XMLHttpRequest.
For testing I just run the REST Service inside my eclipse installation with Tomcat.
Calling the REST Service from JavaScript works fine without any authentication setup.
Now I'm trying to add Basic Authentication mechanism to my REST Services. In the web.xml of my web project i added
<?xml version="1.0" encoding="UTF-8"?><web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
<display-name>ImageLinksServices</display-name>
<servlet>
<servlet-name>Jersey REST Service</servlet-name>
<servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>com.xxx.xxx.services</param-value>
</init-param>
<init-param>
<param-name>readonly</param-name>
<param-value>false</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Jersey REST Service</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
<filter>
<filter-name>CorsFilter</filter-name>
<filter-class>org.apache.catalina.filters.CorsFilter</filter-class>
<init-param>
<param-name>cors.allowed.origins</param-name>
<param-value>*</param-value>
</init-param>
<init-param>
<param-name>cors.allowed.methods</param-name>
<param-value>GET,POST,HEAD,OPTIONS,PUT,DELETE</param-value>
</init-param>
<init-param>
<param-name>cors.allowed.headers</param-name>
<param-value>Content-Type,X-Requested-With,accept,Origin,Access-Control-Request-Method,Access-Control-Request-Headers</param-value>
</init-param>
<init-param>
<param-name>cors.exposed.headers</param-name>
<param-value>Access-Control-Allow-Origin,Access-Control-Allow-Credentials</param-value>
</init-param>
<init-param>
<param-name>cors.support.credentials</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>cors.preflight.maxage</param-name>
<param-value>10</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CorsFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<security-constraint>
<web-resource-collection>
<web-resource-name>Wildcard means whole app requires authentication</web-resource-name>
<url-pattern>/*</url-pattern>
<http-method>GET</http-method>
<http-method>POST</http-method>
</web-resource-collection>
<auth-constraint>
<role-name>tomcat1</role-name>
</auth-constraint>
<user-data-constraint>
<!-- transport-guarantee can be CONFIDENTIAL, INTEGRAL, or NONE -->
<transport-guarantee>NONE</transport-guarantee>
</user-data-constraint>
</security-constraint>
<login-config>
<auth-method>BASIC</auth-method>
</login-config>
</web-app>
Calling the REST URL from Browser works fine. He asks for user and password then the Response of the REST service is displayed.
But when i try to call it from a Javascript with the following snipplet i receive always a 403 error and a warning that
OPTIONS http://localhost:10080/xxxx/rest/fileupload No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:63342' is therefore not allowed access
Code Snipplet i'm currently using:
xhr.open('POST', url, true);
//xhr.open("POST", url, true, "user1", "tomcat1");
xhr.setRequestHeader("Authorization","Basic "+ btoa("user1:tomcat1"));
xhr.withCredentials = "true";
xhr.onreadystatechange = function(){
if(xhr.readyState == 4){
if(xhr.status == 200){
var jsonResponse = JSON.parse(xhr.responseText);
What I'm doing wrong ? I'm totally confused why now after adding authentication the Browser complains about No Access Control Header is present. Before adding authentication to the service the call works also with CORS.
What I can see from the HTTP Request that the Basic Authentication Header seems to be set correctly.
Request URL:http://localhost:10080/xxx/rest/fileupload
Request Method:OPTIONS
Status Code:403 Forbidden
Request Headersview source
Accept:*/*
Accept-Encoding:gzip,deflate,sdch
Accept-Language:de-DE,de;q=0.8,en-US;q=0.6,en;q=0.4
Access-Control-Request-Headers:authorization, content-type
Access-Control-Request-Method:POST
Authorization:Basic dXNlcjE6dG9tY2F0MQ==
Connection:keep-alive
Host:localhost:10080
Origin:http://localhost:63342
Referer:http://localhost:63342/xxx/html/index.html
User-Agent:Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.57 Safari/537.36
Response Headersview source
Content-Length:0
Content-Type:text/plain
Date:Thu, 05 Dec 2013 12:58:46 GMT
Server:Apache-Coyote/1.1
Can anyone help me to understand what I'm doing wrong. I confused if a Tmocat configruation is mssing or my Javascript is wrong.
I don't know if you managed to resolve your issue, but I ran into the same problem and debugged through the org.apache.catalina.filters.CorsFilter to figure out why the request was being forbidden.
According to the W3 CORS Spec Section 6.2 Preflight Requests, the preflight must reject the request if any header submitted does not match the allowed headers.
The default configuration for the CorsFilter cors.allowed.headers (as is yours) does not include the Authorization header that is submitted with the request.
I updated the cors.allowed.headers filter setting to accept the authorization header and the preflight request is now successful.
<filter>
<filter-name>CorsFilter</filter-name>
<filter-class>org.apache.catalina.filters.CorsFilter</filter-class>
<init-param>
<param-name>cors.allowed.headers</param-name>
<param-value>Content-Type,X-Requested-With,accept,Origin,Access-Control-Request-Method,Access-Control-Request-Headers,Authorization</param-value>
</init-param>
</filter>

REST Service - #POST call works while #GET doesn't

I am very new in REST services and I am facing a problem during the last two weeks. I am using Jersey. I am trying to use a simple REST client in order to call a POST method, which accepts a JSON object as a parameter and stores it to a database. My approach didn't work, but I decided to go one step behind, so now I am using an even simpler client with a simpler provider, in order to just test my POST and GET methods. The strange thing is that while I am able to call the POST method:
#POST
#Path("/store")
#Consumes(MediaType.TEXT_PLAIN)
#Produces(MediaType.TEXT_PLAIN)
public String storeData(String str) throws SQLException {
String query = "insert into myDB.test (id, name) values ('1', '" + str + "')";
MyDB db = new MyDB();
db.runQuery(query);
return responseCode.toString();
}
This works just fine!
But in the same class, the #GET method is not working and returns a 404 error.
My code is as following:
#GET
#Path("/retrieve")
#Produces(MediaType.TEXT_PLAIN)
public String getResponse() {
return "Hello!";
}
I know that my question might be quite simple to many... but I'm trying to find out what I'm doing wrong so as to go on to my actual implementation...
Thanks a lot in advance.
Marina
here is my client-side code
public class TestClient {
public static void main(String[] args) {
ClientConfig clientConfig = new DefaultClientConfig();
Client client = Client.create(clientConfig);
WebResource webResource = client.resource("http://localhost:8080/server_classes/rest/server/retrieve");
System.out.println(webResource.accept(MediaType.TEXT_PLAIN).post(ClientResponse.class, "hello"));
}
}
And here is my web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
<display-name>server_classes</display-name>
<servlet>
<servlet-name>Jersey REST Service</servlet-name>
<servlet-class> com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>server_classes</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Jersey REST Service</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
</web-app>
My package is named server_classes and the resource's path is #Path("/server")
I tried the vogella tutorial again, from the beginning, just changing the annotation paths and the methods (for not just giving a "Hello Jersey" response). But now, I am not able to run anything. There is only a 404 error!
O also deleted Tomcat's instance, then the whole tomcat installation and re-installed it, the problem still the same. I am working on Ubuntu 12.04 if this helps..
Thanks!
try to change your request from post to get, as your servlet-mapping expects:
webResource.accept(MediaType.TEXT_PLAIN).get(ClientResponse.class);