How to dispatch servlet requests to Jersey resource methods - java

I am wondering if it is possible to dispatch a request from a servlet to a Jersey (JAX-RS implementation) resource class. I am trying to do it but it doesn't seem to work and according to my logging, the jersey resource is never reached.
Code examples are below. Is what I'm trying to do impossible for some reason?
Please note, the Jersey resource works correctly when I access it directly in a web browser via the address bar.
Also please note that 'RequestDispatcher.forward()' works as expected. It is just 'include' that doesn't.
The servlet
//The Jersey dispatcher url-filter is set to '/api/*'
String servletID = "/api/items";
RequestDispatcher dispatcher = getServletContext().getRequestDispatcher(servletID);
dispatcher.include(request, response);
The Jersey resource
#GET #Path("/items")
#Produces ({MediaType.TEXT_XML})
public JAXBElement<Items> getItems(#PathParam("project") String project) throws IOException, JAXBException {
log.debug("reached getItems");
//Omitted code that returns 'Items' object wrapped in JAXBElement
}
Relevant parts of web.xml
<servlet>
<servlet-name>jerseyDispatcher</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>uk.co.web.api.resource</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>jerseyDispatcher</servlet-name>
<url-pattern>/api/*</url-pattern>
</servlet-mapping>

It is possible you forward the request.
HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
RequestDispatcher requestDispatcher = null;
requestDispatcher = httpServletRequest.getRequestDispatcher("/items");
dispatcher.forward(request, response);
return;
However note if you receive a GET request and try to forward to a POST resource,
It will throw a 405 error.
Edit:
Let me understand what you are trying to achieve, if you need write content to response output stream you could use jersey Resource Filter.
public class YourResourceFilter implements ResourceFilter
{
public ContainerRequestFilter getRequestFilter()
{
return new ContainerRequestFilter()
{
#Override
public ContainerRequest filter(ContainerRequest containerRequest)
{
//Pre- editing the request
return containerRequest;
}
};
}
#Override
public ContainerResponseFilter getResponseFilter()
{
return new ContainerResponseFilter()
{
#Override
public ContainerResponse filter(ContainerRequest containerRequest, ContainerResponse containerResponse)
{
// after the request has been completed by your jersey resource
return containerResponse;
}
};
}
}

I got it to work, sort of (Jersey 2.13) by configuring Jersey as a filter, and not a servlet, in web.xml. Then, you can tell the container to apply the filter to included requests too:
<filter-mapping>
<filter-name>Jersey Web Application</filter-name>
<url-pattern>/api/*</url-pattern>
<dispatcher>FORWARD</dispatcher>
<dispatcher>INCLUDE</dispatcher>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>
RequestDispatcher.include will then work for request handled by Jersey, too. There's a caveat, though. Jersey calls response.getOutputStream, so all output must be performed through said output stream - this rules out JSP pages, that use response.getWriter instead. So, unless you figure out how to work around the problem, forget about including a Jersey resource in a JSP page or, vice versa, including the result of evaluating a JSP as part of a REST response.

Related

Redirect the servlet request to another servlet

In our app for all the notification we trigger through mail.
All the templates have non sso link
>/Userlogin?param1=param2value&param2=param2value">Link to access app
I need to modify this link in all templates to
>/Userloginsso?param1=param2value&param2=param2value">Link to access app
Since there are many templates and takes lot of manual effort, is there any way we can redirect the request of Userlogin to Userloginsso. Any configuration that we can do in web.xml ?
Considering you have a mapping for Userlogin in web.xml as below:
<web-app>
<servlet>
<servlet-name>Userlogin</servlet-name>
<servlet-path>com.something.Userlogin</servlet-path>
</servlet>
<servlet-mapping>
<servlet-name>Userlogin</servlet-name>
<url-pattern>/Userlogin</url-pattern>
</servlet-mapping>
</web-app>
Modify existing mapping to :
<web-app>
<servlet>
<servlet-name>Userloginsso</servlet-name>
<servlet-path>com.something.Userloginsso</servlet-path>
</servlet>
<servlet-mapping>
<servlet-name>Userloginsso</servlet-name>
<url-pattern>/Userlogin</url-pattern>
</servlet-mapping>
</web-app>
Now all calls to Userlogin will be redirected to Userloginsso servlet.
You could do a simple redirect in your UserLogin servlet with the following:
public void doGet (HttpServletRequest request, HttpServletResponse response) throws IOException {
String param1 = request.getParameter ("param1");
String param2 = request.getParameter ("param2");
// other parameters
// Build the new url: if too much parameters, prefer using a StringBuilder over String concatenation for better performances
String baseUrl = request.getContextPath () + "/Userloginsso?param1=" + param1 + "&param2=" + param2;
String encodedUrl = response.encodeRedirectURL (baseUrl);
response.sendRedirect (encodedUrl);
}
If I understand your question correctly you could use a filter example here get the url and foward it somplace else in your app. Or and url rewrite library such us this one
If you still want a servlet you could use a ProxyServlet. There are already many good implementations.
Examples:
Complex proxy servlet with all features
Simple proxy servlet, limited features

tomcat jersey retrieve full context path

I'm implementing ApplicationEventListener, I need to retrieve the context path, the one declared in my web.xml:
<servlet-mapping>
<servlet-name>MyApplication</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
I'm implementing onEvent method
#Override
public void onEvent(ApplicationEvent event) {
if (event.getType() == ApplicationEvent.Type.INITIALIZATION_FINISHED) {
final ResourceModel resourceModel = event.getResourceModel();
}
}
I can also use #Context ServletContext servletContext in ResourceConfig to pass the info if necessary but I don't know how to reach this.
From a servlet using HttpServletRequest, it's possible to call request.getContextPath(), but obviously I can't use HttpServletRequest.
Generally speaking, in my application I need a way to retrieve servlet-mapping
Thanks
Edit:
listener class: org.glassfish.jersey.server.monitoring.ApplicationEventListe‌​ner

Confusion between HttpServlet class and using it with Jersey

I am building servlets which implement a RESTful API. I understand the Jersey is a framework for deciphering and using given URL's. How do I use it in conjunction with the HttpServlet class.
I don't understand how the two work with each other. I guess this is a very broadstrokes question but I have done a fair share of reading but am still stuck on this seemingly trivial concept. I have attempted to deploy apps with classes that extend the HttpServletclass AND use Jersey annotations.
#Path("/api")
public class API extends HttpServlet{
#GET
#Path("/{name}")
#Produces("text/hmtl")
public String doGetSayHello(#PathParam("name") String name){
return "Hello" + name;
}
#GET
#Path("/articles")
#Produces("text/json")
public String doGetArticles(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
JSONObject obj = new JSONObject();
obj.put("interns", interns);
obj.put("company", "Stack Overflow");
return obj.toString();
}
}
Any help or informative materials would be greatly appreciated!
Actually you are confused because you don't understand how jersey works. Jersey framework basically uses com.sun.jersey.spi.container.servlet.ServletContainer servlet to intercept all the incoming requests. As we configure in our projects web.xml, that all the incoming rest request should be handled by that servlet. There is an init-param that is configured with the jersey servlet to find your REST service classes. REST service classes are not Servlet and they need NOT to extend the HttpServlet as you did in your code. These REST service classes are simple POJOs annotated to tell the jersey framework about different properties such as path, consumes, produces etc. When you return from your service method, jersey takes care of marshalling those objects in the defined 'PRODUCES' responseType and write it on the client stream. Here is a sample of jersey config in web.xml
<servlet>
<servlet-name>REST</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.rest.services;
</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>REST</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
Jersey uses a servlet to route URLs to the appropriate service. Your service itself does not need to extend a servlet.
At a high level, Jersey's ServletContainer class accepts the requests, and then based on your Jersey configuration, your web service will be invoked. You configure what url patterns are processed by Jersey. Check out section 5.3 http://www.vogella.com/articles/REST/.

Unable to access Spring Security information during a servlet multipart post

I'm unable to access Spring Security information during a servlet multipart post. The spring security information is available during regular get and post methods, but is not available for a multipart post method. I tried unsuccessfully to access this security information directly through SecurityContextHolder.getContext().getAuthentication() and through an injected service that accesses SecurityContextHolder.getContext().getAuthentication().
I also implemented an HttpRequestHandler and a ServletWrappingController. Once again, I was able to successuly inject spring beans into them and access Spring Security info for regular get and post methods, but I was not able access Spring Security info for a multipart posts. I know that there are new MultiPart capabilities built into Spring 3.0 but because our website will require full access to the file upload stream I won't be able to use them. For that reason, I am focusing on the HttpServlet, HttpRequestHandler and the ServletWrappingController.
The code I'm posting here is all test code written to solve this specific problem I'm facing with security information not being available during a multipart upload (not meant to be of production quality). It is for an HttpServlet.
Please let me know if there's something I'm doing wrong. Or if not, if there's a workaround or a better way to accomplish a multipart upload with access to Spring Security info while maintaining access to the file upload stream? Any assistance that someone can offer with this problem will be greatly appreciated!
Below is the test servlet code. Comments below as to what works and what doesn't is based on a user logged in to the website using Spring Security 3.1:
//many import statements not displayed
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.context.support.SpringBeanAutowiringSupport;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
public class UploadServlet extends HttpServlet {
public void service(HttpServletRequest req, HttpServletResponse res) throws IOException, ServletException {
super.service(req, res);
}
public void init(ServletConfig config) throws ServletException {
super.init(config);
SpringBeanAutowiringSupport.processInjectionBasedOnServletContext(this,
config.getServletContext());
}
//The following is always injected and available
//however, it only returns valid security information for regular get and post methods,
//not for multipart post methods
#Autowired
private CustomUserService customUserService;
//The following is always injected and available and always returns the expected data
#Autowired
private GuideService guideService;
//the following does not work when the client issues a multipart post, it does work for non-multipart
public boolean getAuthenticated(){
boolean authorized = false;
for (GrantedAuthority authority : SecurityContextHolder.getContext().getAuthentication().getAuthorities()) {
if(authority.getAuthority().equals("ROLE_USER") || authority.getAuthority().equals("ROLE_ADMIN")) {
authorized = true;
break;
}
}
return authorized;
}
//The following test get method works fine
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
if(getAuthenticated()){
PrintWriter out = resp.getWriter();
out.write("<h1>Guide Info</h1><br/>");
Guide guide = guideService.findById(2l);
out.write(guide.getName() + "<br/>");
out.write(guide.getDescription() + "<br/>");
out.write("UserName: " + customUserService.getCurrentUser().getUsername() + "<br/>");
}
else{
PrintWriter out = resp.getWriter();
out.write("<h1>You're not authorized</h1><br/>");
}
}
//This post method
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//the following always works, whether the clients posts using multipart or not
String guideName = guideService.findById(2l).getName();
//the following does not work when the client issues a multipart post, it does work for non-multipart
String userName = customUserService.getCurrentUser().getUsername();
//the following does not work when the client issues a multipart post, it does work for non-multipart
if(getAuthenticated()){
String responseString = RESP_SUCCESS;
boolean isMultipart = ServletFileUpload.isMultipartContent(req);
if (isMultipart) {
ServletFileUpload upload = new ServletFileUpload();
//commmons fileupload code
// Not a multi-part MIME request.
else {
//...
}
//...
}
else{
//...
}
}
}
Here is the relevant portion of web.xml:
<servlet>
<servlet-name>fgm</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>WEB-INF/spring/webmvc-config.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>fgm</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>UploadServlet</servlet-name>
<servlet-class>com.guides.servlet.UploadServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>UploadServlet</servlet-name>
<url-pattern>/upload</url-pattern>
</servlet-mapping>
I can confirm that Spring 3.0.x and Spring Security 3.0.x together work with multipart posts as well as they work with other types of requests. I've run into similar behavior, and in our case, the security filter wasn't getting applied to the request due to our mistake in the filter mappings.
Can you post the parts of your web.xml that define the security filter, and map it to the desired paths?
This might help you, if you're using Spring MVC:
{
#RequestMapping(method = RequestMethod.POST, value = "/some/post/url")
public void postFile(MultipartHttpServletRequest request) {
MultipartFile multipartFile = request.getFileMap().get("fileControlName");
...
}
}
Security details as provided by SecurityContextHolder are (by default) stored in a ThreadLocal.
Does upload servlet creates a new thread to handle multiparts ? Try changing the SecurityContextHolderStrategy to MODE_INHERITABLETHREADLOCAL
Similar issues: How to set up Spring Security SecurityContextHolder strategy?
It might be worth checking how your client is performing the multi-part post, are you using a different mechanism/library to your standard post?
If I had to guess I would say your client code isn't authenticating correctly for the multi-part use-case.
E.g. Using standard Java for the normal post and Apache libs for the multipart post and forgetting to set the appropriate http headers when using the Apache stuff.

Display forwarded JSP with url-pattern "/*"

To improve my java skills, I'm trying to build a simple j2ee framework (MVC).
I built it to handle every request in a FrontServlet. Here is the mapping that I used :
web.xml :
<servlet>
<servlet-name>Front</servlet-name>
<servlet-class>test.FrontServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Front</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
My problem is that when I forward the request from the FrontServlet to a JSP, obviously, the JSP request is handle by the FrontServlet and the view isn't rendered.
How can I resolve this problem by keeping the url-pattern "/*" ?
Is there a way to render a JSP in a Servlet without performance losses ?
Thanks in advance for your reply !
Solution 1 (#Bryan Kyle)
I'm trying to follow your advise. I created this filter :
public void doFilter(ServletRequest request,
ServletResponse response, FilterChain chain)
throws IOException, ServletException
{
HttpServletRequest req = (HttpServletRequest) request;
if(!req.getRequestURL().toString().endsWith("jsp"))
{
// I changed the servlet url-pattern to "/front.controller"
req.getRequestDispatcher("/front.controller").forward(req, response);
/*chain.doFilter(req, resp);*/
}
}
<filter>
<filter-name>Filter</filter-name>
<filter-class>test.Filter</filter-class>
</filter>
<filter-mapping>
<filter-name>Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Is it right?
Thanks !
A Filter is an inappropriate solution for a front controller approach.
You want to refine the url-pattern of your servlet so that it matches e.g. /pages/* or *.do. You don't want your front controller to kick in on irrelevant requests like CSS/JS/images/etc. To take /pages/* as an example, assuming that you've a JSP in /WEB-INF/foo.jsp, then the following in a servlet
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.getRequestDispatcher("/WEB-INF" + request.getPathInfo() + ".jsp").forward(request, response);
}
should display the JSP in question on http://localhost:8080/contextname/pages/foo.
See also:
Design patterns in Java web applications
Hidden features of JSP/Servlet
I think the problem here might be that you're using a Servlet instead of a ServletFilter.
A ServletFilter, as the name suggests filters requests by providing pre- and post-processing on the request. You'd probably want to use a Filter if you needed to do something like the following:
Provide security checks across an entire application
Set request properties that are picked up by a servlet or jsp
Compress a response
Log timing information
Etc.
Have a look at the documentation about Servlet Filters.

Categories