Spring Integration with RESTEasy - jboss

In our existing integration, we are planning to replace Queue ( the entry point to our integration processing) with RESTEasy services.
We are processing the HTTP requests as below:
1) Asynchronous HTTP Request Processing for GET
2) Asynchronous Job Service for POST
I understand that spring integration provides and for HTTP requests. But this is not something we want, as the request processing is handled by RESTEasy.
Software stack:
RESTEasy 3.0.9 Framework
Spring Integration 4.1.2.RELEASE
JBOSS EAP 6.4.
Is there a component that we could use to integrate RESTEasy services with spring integration ?

There is no explicit component exist, it is all API work to be done. You need to use dependent jar files and integration code
Below are the minimal Jar files to be path in workspace environment using ant or maven:
org.jboss.resteasy:resteasy-jaxrs:3.0.10.Final
org.jboss.resteasy:resteasy-spring:3.0.10.Final
org.springframework.boot:spring-boot-starter-web:1.2.2.RELEASE
org.jboss.resteasy:resteasy-jackson2-provider:3.0.10.Final
Following listener entries in web.xml to be done:
<context-param>
<param-name>resteasy.servlet.mapping.prefix</param-name>
<param-value>/project</param-value>
</context-param>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/dispatcher-servlet.xml</param-value>
</context-param>
<listener>
<listener- class>org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap</listener-class>
</listener>
<listener>
<listener-class>org.jboss.resteasy.plugins.spring.SpringContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>RESTEasyService</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.concretepage.Application</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>RESTEasyService</servlet-name>
<url-pattern>/project/*</url-pattern>
</servlet-mapping>
Dispatch Servlet can be put into WEB-INF
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:component-scan base-package="com.concretepage" />
</beans>
Sample Java Service Code:
import java.util.Map;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Response;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
#Path("/manage" )
#Component
public class ExService {
#Autowired
private ExRepository repository;
#GET
#Path("/{id}")
#Produces("application/json")
public Response getEmp(#PathParam("id") String id) {
Map<String,String> map = repository.getEmpDetail(id);
return Response.ok(map).build();
}
}
For more detail You may refer to http://docs.jboss.org/resteasy/docs/3.0.9.Final/userguide/html_single/index.html#RESTEasy_Spring_Integration

Use <int:gateway> to do the integration with spring.
<int:gateway id="providerGateway" service-interface="com.stack.overflow.TestInterface"
default-request-channel="requestChannel">
<int:method name="getDataByID" request-channel="requestChannel"/>
<int:method name="postDataByID" request-channel="requestChannel"/>
</int:gateway>
Where com.stack.overflow.TestInterface is the Resource Interface see below:
#Path(RestConstants.SERVICES)
public interface TestInterface {
#Path(RestConstants.TEST1)
#GET
#Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public Response getDataByID();
#Path(RestConstants.TEST2)
#POST
#Produces({ MediaType.TEXT_PLAIN })
public Response postDataByID(String edi);
}
You can have different message channel if desired (see the gateway above) for a request. e.g. a request to getDataByID, will be put on the requestChannel. You can read from this channel and do the required processing as you require and then send a response back.

Related

How to get Websphere to prompt for a database JNDI connection

I have an EAR application, containing an EJB and a WAR.
In the EJB I am using JPA to connect to the database, and then the WAR deals with the REST endpoints and calls methods defined in the EJB:
e.g - EJB Stateless Bean:
#PersistenceContext
private EntityManager em;
and EJB persistence.xml:
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
version="2.0">
<persistence-unit name="WOTISEJB">
<jta-data-source>java:comp/env/jdbc/appds</jta-data-source>
<class>com...</class>
</persistence-unit>
</persistence>
Web class:
#Path("/getByType")
#ManagedBean
public class GetByTypeResource
{
#EJB
EjbDao ejbDao;
#GET
#Produces(MediaType.APPLICATION_JSON)
public String getData(#Context HttpServletRequest request, #PathParam("type") Type type)
{
JsonObject response = ejbDao.getByType(type);
StringWriter sw = new StringWriter();
try (JsonWriter jw = Json.createWriter(sw)) {
jw.write(response);
}
String retVal = sw.toString();
return retVal;
}
}
I presume I don't need anything in my web.xml as all of the EntityManager definitions are in the EJB code (and just called from the WEB application) - but just in case it's relevant:
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<servlet>
<servlet-name>appname</servlet-name>
<servlet-class>com.ibm.websphere.jaxrs.server.IBMRestServlet</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>com.app.ApplicationConfig</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>appname</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
<display-name>App Name</display-name>
</web-app>
When I install the application onto Websphere 9.0.5, I was expecting to be prompted as part of the installation to map the jndi name java:comp/env/jdbc/appds to the JDBC datasource I have already created in the console; however it is just using the default datasource in WAS instead.
What configuration elements am I missing to get the installation process to prompt me for the DSN mapping? In order words I don't want to put the jbdc name directly in the config, but have an indirect lookup which is configured on deploy.
Additionally, am I missing any configuration in my web.xml so that it also knows about the DSN when it calls the methods on the EJB classes, or will that happen automatically?

Spring MVC REST nohandler error

Im new to spring MVC and REST.. I'm having an issue with a simple test controller I've put together from example I've found here and from the spring docs..
When I hit the url http://localhost:8080/test-api/user/14 I get the error below
Im getting the error:
Sep 23, 2015 11:26:55 AM org.springframework.web.servlet.PageNotFound noHandlerFound
WARNING: No mapping found for HTTP request with URI [/test-api/user/14] in DispatcherServlet with name 'testapi'
Im using xml to config.. Im not ready to move to java config.
web.xml
Spring Web MVC Application
<servlet>
<servlet-name>springtest</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springtest</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/testapi-servlet.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
testapi-servlet.xml - only contains the component scan and annotation driven elements
<context:component-scan base-package="com.springtest.testapi" />
<mvc:annotation-driven />
SpringTest.java
package com.springtest.testapi.api;
#RestController
public class SpringTest {
#RequestMapping(value="/user/{id}", method = RequestMethod.GET)
public User getUser(#PathVariable int id) {
User u = new User(id,"Test","Me");
return u;
}
What handler should I be defining.. None of the examples or docs state that a handler needs to be defined..
Remove the contextConfigLocation.
Replace the following:
<servlet-mapping>
<servlet-name>springtest</servlet-name>
<url-pattern>/test-api</url-pattern>
</servlet-mapping>
Make sure your xml file is test-api-servlet.xml and not testapi-servlet.xml
I found my issue. I mispelled the package in the component scan. The sample code I have was edited so It didn't fully represent what I had and was actually correct.

Mixing REST and JSP in Spring MVC, Cannot find JSP

I'm sure this is a noob question, and I've spent the better part of an hour trawling stackoverflow for an answer but nobody seems to have my case so here we go...
I have a new webapp that uses Spring MVC. Most of the app (99%) is pure REST, so it doesn't have a "view" as such but rather simply sends JSON back down the wire, or sends an alternate HTTP Status for errors etc.
The exception is the login page which needs to be an actual JSP, but somehow the configuration I am using to map my REST controllers is leaving me in a state where normal JSP mappings fail.
Here's what I've got:
In my dispatcher servlet config, the relevant portions are:
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/"/>
<property name="suffix" value=".jsp"/>
</bean>
In my attempts to get it working, I have also added a mapping to the "HomeController" which currently just redirects to my login JSP:
<bean name="/" class="com.somepackage.HomeController"/>
Now, in the web.xml I have:
<servlet>
<servlet-name>spring-dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>spring-dispatcher</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/spring-dispatcher-servlet.xml
</param-value>
</context-param>
This works fine for my RESTful controllers, which look like this:
#Controller
#RequestMapping(value = "/api/user")
public class BlahBlahController {...
My "HomeController", which just looks like this:
#Controller
#RequestMapping(value = "/")
public class HomeController extends AbstractController {
#Override
protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response) throws Exception {
return new ModelAndView("login");
}
}
IS triggered when I hit the "/" url, but I get this error in the logs:
WARNING: No mapping found for HTTP request with URI [/WEB-INF/pages/login.jsp] in DispatcherServlet with name 'spring-dispatcher'
Now I get what it's saying, it doesn't know how to resolve /WEB-INF/pages/login.jsp (this page does exist btw), but I'm stuck as to how I need to alter things to get this to work.
I'm a little confused on how it's supposed to work. Anyone got any clues?
Thanks.
OK.. I found the answer, it's the url-pattern in the dispatcher config.
Instead of:
<servlet-mapping>
<servlet-name>spring-dispatcher</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
It should be
<servlet-mapping>
<servlet-name>spring-dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
I had actually found this answer elsewhere and tried it but "thought" it wasn't working, then realized the reason I thought this was unrelated to the root cause.
No idea why this would work and the other wouldn't.. but one problem at a time...
Put RequestMapping at the method level, I tried at my code and it worked. You don't need to define HomeController bean if you are using #Controller and having a proper "context:component-scan"
#Override
#RequestMapping(value = "/")
protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response) throws Exception {
return new ModelAndView("login");
}
you can also use below code if you just want to redirect a login view for all "/" access.
<mvc:view-controller path="/" view-name="login"/>
Checkout the mvc show case project from github for a helpful reference.

How to check JBoss deployers are working

I am trying to get resteasy working on JBoss AS6 Final (SEAM 2 app), but I cant seem the get the most basic example working, as I understand it, resteasy should be ready to go, I have tried the following example from here but the urls simply result in 404 errors with no response
package uk.co.rest.test;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.core.Application;
public class Library extends Application {
#GET
#Path("/books")
public String getBooks() {
System.out.println("Check");
return "done";
}
}
with the following added to my web.xml
<context-param>
<param-name>resteasy.servlet.mapping.prefix</param-name>
<param-value>/rest</param-value>
</context-param>
<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>uk.co.rest.test.Library</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>resteasy-servlet</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
I get the feeling that the resteasy.deployer that is bundled with JBoss is not doing its job, but im not sure how to go about debugging it
Any help would be great im pulling my hair out over this one!!
RESTEasy must be configured in order to be exposed as a service. You can do it either directly or via Seam's resource servlet.
To use RESTEasy directly, I find the easiest way is configuring it as a Servlet filter. There's little to do other than adding the filter to your web.xml as documented in http://docs.jboss.org/resteasy/docs/2.3.0.GA/userguide/html/Installation_Configuration.html#filter.
When using Seam this is however unnecessary, as Seam is capable of deploying RESTEasy services via its resource servlet quite simply (documented in http://docs.jboss.org/seam/2.2.0.GA/reference/en-US/html/webservices.html#d0e22093). You first declare RESTEasy's application component like this:
<resteasy:application resource-path-prefix="/rest" />
And create your providers that will be automatically deployed into the configured path, for example:
#Name("libraryService")
#Path("/library")
public class Library implements Serializable {
#In(create=true) private transient BookHome bookHome;
#GET #Path("/{book}")
#Produces("text/plain")
public String getBooks(#PathParam("book") String id) {
bookHome.setId(id);
return bookHome.getInstance().getTitle();
}
}
You can then access the RESTEasy service via:
http://localhost:8080/yourapp/seam/resource/rest/library/1
The advantage of going the Seam way is mostly ease of use. You do need to include an extra jar: jboss-seam-resteasy.jar.
You seem to have misunderstood the role of javax.ws.rs.Application. Your Library class does not have to extend javax.ws.rs.Application in order to expose the getBooks()-method.
Create a class that extends javax.ws.rs.Application. Override the getSingletons()-methods and return a set of instances that has methods you wish to expose:
public class MyApplication extends javax.ws.rs.Application {
#Override public Set<Object> getSingletons(){
return Collections.<Object>singleton(new Library());
}
}
In your web.xml, change the javax.ws.rs.Application init-param, so that it points to the MyApplication class.

No Endpoint mapping found using annotation driven Spring WS 2.0.2 with dynamic wsdl

Im using annotation driven Spring WS 2.0.2 to create a simple Webservice, but the enpoint mapping was not found.
Input and Output are jdom Elements to keep it as simple as possible.
The Webservice is running with Java 1.6 on Tomcat 6.0.29 wich returns an error
page (The requested Resource () is not available) to my SoapUI Service Test.
Here is the Error I get in my logging:
WARNING: No endpoint found for [SaajSoapMessage (http://foo.bar/myTest)myRequest]
Here are the parts of the configuration I deem relvant for the Endpoint mapping:
(If there are more relevant parts I am missing please ask back...)
Schema (WEB-INF/xsd/myTest.xsd)
targetNamespace="http://foo.bar/myTest"
...
<element name="myRequest" type="tns:string"/>
<element name="myResponse" type="tns:string"/>
web.xml (WEB-INF/web.xml)
<servlet-class>
org.springframework.ws.transport.http.MessageDispatcherServlet
</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/config.xml</param-value>
</init-param>
<init-param>
<param-name>transformWsdlLocations</param-name>
<param-value>true</param-value>
</init-param>
Spring config (/WEB-INF/spring/config.xml)
<sws:annotation-driven/>
<sws:dynamic-wsdl id="myTest"
portTypeName="myTest"
localUri="/"
targetNamespace="http://foo.bar/myTest">
<sws:xsd location="/WEB-INF/xsd/myTest.xsd"/>
</sws:dynamic-wsdl>
Endpoint (src/main/java/bar/foo/MyEndpoint.java)
#Endpoint
public class MyEndpoint{
#PayloadRoot(localPart="myRequest",namespace="http://foo.bar/myTest")
#ResponsePayload
public Element mySearch( #RequestPayload Element myRequest){
return myRequest;
}
}
Searching for a sollution I found it contained in this answer
Adding
...
xmlns:context="http://www.springframework.org/schema/context"
...
xsi:schemaLocation=" ...
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd ... "
<context:component-scan base-package="bar.foo"/>
to my Spring configuration let the servlet find my Endpoint.
My problem was, that no sample code in a spring documentation I found contained
this step and its relevance.
Well - actually I found this code snipplet in a tutorial earlier, but it was a bit overloaded with features I did not need, and as in the official docs it was not explained why it was necessary.