I've done my java web app in Java EE with HttpServlet and JSP. I normally map my Servlet like this:
#WebServlet(urlPatterns = "/main")
public class MainServlet extends HttpServlet{
I do my servlet stuff and would like to pass data to JSP file like this:
RequestDispatcher dispatcher = req.getRequestDispatcher("/main.jsp");
dispatcher.forward(req, resp);
The main.jsp is in my web app folder (I use IntelliJ Idea).
The question is, I've initially made my UI with Vaadin 8. Using following:
#Theme("mytheme")
#CDIUI("users")
#SuppressWarnings("serial")
public class Vaadin extends UI
and then override init.
Now I would like to add a single HttpServlet and override doGet and then call the dispatcher to forward data to jsp. Here's the problem adding Vaadin somehow broke the path to tsp, as jsp does not display, instead a standard vaadin
Request was not handled by any registered handler.
appears, I know the servlet was mapped properly as the servlet starts and does work, what does not work is the running the JSP file.
Can anyone advise?
It seems that you need to implement yet a WebFilter to process JSP. Your dispatcher forwards the request but it is then a request that is again handled by some filter by Vaadin I guess. Also I am not sure if you need any servlet and/or dispatcher (not sure what your actual use is).
Anyway, with WebFilter it is possible to intercept this processing. Check the following example
#WebFilter(filterName="jspFilter", urlPatterns="*")
public class JspFilter implements Filter {
#Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
try {
HttpServletRequest hreq = (HttpServletRequest)request;
String path = hreq.getPathTranslated();
if(path.toLowerCase().endsWith(".jsp")) {
try(Writer writer = response.getWriter();
Reader reader = new FileReader(path) ) {
processJsp(reader, writer);
return;
} catch (Exception e) { /* TODO: handle exception */};
}
} catch (Exception e) { /* TODO: handle exception */};
chain.doFilter(request, response); // forward to filter chain by default
}
#Override public void destroy() {}
#Override public void init(FilterConfig filterConfig)
throws ServletException {}
}
This filter checks all request. If URI (here checked from translated/absolute path) is ending with .jsp it is processed with processJsp(reader, writer) that you might want to implement to do the forwarding to JSP parser or so.
Related
I have multiple servlets in my web app. And I want to perform a specific action each time a request comes to MyServlet (only) and not when request is for any other servlet. Overriding destroy isn't going to solve this.
If I write a custom ServletRequestListener, that action will be performed for all requests, if I put that action in requestDestroyed method, irrespective of which servlet in my web app is being called.
So, does writing requestDestroyed method as a part of servlet itself like below solves this problem ? Or is there any other/better way?
public class MyServlet implements HttpServlet {
public void init(ServletConfig config) throws ServletException {
//init stuff
}
public void service(ServletRequest req, ServletResponse res)
throws ServletException {
try {
//do some stuff
} finally {
requestDestroyed(request);
}
}
private void requestDestroyed(HttpServletRequest request) {
//some clean up stuff only for this particular servlet
}
}
I am developing a shopping cart using servlets, have two servlets :
1. ShopingCart.java
2. TotalAmount.java
In ShopingCart.java i have created sessions and synchronise them using
synchronized(session) // lock session protect this from multiple threads
{
TotalAmount cart = (TotalAmount)session.getAttribute("Cart");
if(cart == null) // new sesssion, just create a cart
{
cart = new TotalAmount();
session.setAttribute("Cart", cart);
}
// I have to call cart.display();
and my display method in TotalAmount.java contains (request,response) as parameters.
so, how can i pass the request and response to display method?
yes, i need request and response parameters in display method to save some variable data in session in TotalAmount.java
Please Help..
I can pass the request and response to display method of TotalAmount.java by calling
Display(request,response);
As I already have the object of TotalAmount in ShopingCart.java
As per Java EE specification, servlet are independents and the only official way to interact with one is via their service(ServletRequest req, ServletResponse res) or doXXX method.
If you want to call a specific method of another servlet you have 2 broad solutions :
make the objects know each other by dependancy injection (Java EE CDI, Spring framework, etc.) - clean and neat provided you have one DI mechanism
manually register them via static method - say you want to access Servlet2 from Servlet1
class Servlet1 implement HttpServlet {
private static Servlet2 servlet2 = null;
public static void setServlet2(Servlet2 servlet2) {
this.servlet2 = servlet2;
}
// ... other code
servlet2.display(...);
// ...
}
class Servlet2 implements HttpServlet {
#Override
public void init(ServletConfig config) {
Servlet1.setServlet2(this);
// ... other init code eventually
}
// ...
}
It should work but is not very nice because of the static misuse.
forward to the other servlet and pass a request attribute to indicate that a special action is requested (assuming Servlet2 is named "Servlet2" in web.xml)
in Servlet1 :
request.setAttribute("DISPLAY", true);
request.getServletContext().getNamedDispatcher("Servlet2").forward(req, resp);
in Servlet2 :
public void service(ServletRequest req, ServletResponse resp) {
if (req.getAttribute("DISPLAY") != null) {
display(req, resp);
}
else {
super.service(req, resp); // or directly your code
}
}
Still a nice solution because attribute will not be set in a direct call (of course, you can use req.getRequestDispatcher("/Servlet2URL") instead of getServletContext().getNamedDispatcher("Servlet2"))
I'm trying to use WebFilter with JSF 2, but my filter not is working. The urlPattern is not recognized.
My Filter class:
#WebFilter(urlPatterns = {"/rws/*"})
public class AuthorizationFilter implements Filter {
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
HttpServletRequest req = (HttpServletRequest) request;
HttpSession session = req.getSession(true);
Object o = session.getAttribute("user");
HttpServletResponse res = (HttpServletResponse) response;
if(o == null)
res.sendRedirect(req.getContextPath() + "/login.xhtml");
else
chain.doFilter(request, response);
}
#Override
public void init(FilterConfig filterConfig) throws ServletException {
}
#Override
public void destroy() {
}
}
In my structure I want to protect all pages that are in the rws folder, but I could not configure the filter.
I've tried
# WebFilter ("/ rws / *")
# WebFilter ("/ faces / rws / *")
My filter never is executed!!
I noticed that the url does not change when I browse pages.
For example, the user opens the index.xhtml performs login and then redirects to page loginOk.xhtml.
LoginOk.xhtml page has links to pages that are in the folder rws.
When I click the link url does not change, ie, I'm browsing in a folder page rws but the url in the browser remains the same (http://jsftest.com:8080/TestePrimeFaces/faces/loginOK.xhtml). Is that the problem?
Used a commandLink as link, do not know if it is the most suitable.
Does anyone know where is the problem?
add "#Component" like this.
#Component
#WebFilter(urlPatterns = {"/rws/*"})
public class AuthorizationFilter implements Filter { ...
Servlet filters don't get triggered when you perform a non-redirect JSF navigation on postback. JSF navigation does namely by default not create a new HTTP request (which would trigger the filter), but it just changes the content of the HTTP response while still keeping the same HTTP request (that's also exactly why you don't see a change in browser's address bar).
Adding the FORWARD dispatcher to the filter mapping as some may suggest won't work as JSF on Facelets doesn't use RequestDispatcher#forward() unlike "plain" JSP/Servlet and many other MVC frameworks.
If you want to trigger the filter, just send a new request by a redirect.
So, instead of
public String login() {
// ...
return "home";
}
just do
public String login() {
// ...
return "home?faces-redirect=true";
}
If you worry about faces messages being lost due to the redirect, just make use of the flash scope.
See also:
What is the difference between redirect and navigation/forward and when to use what?
How to navigate in JSF? How to make URL reflect current page (and not previous one)
How to show faces message in the redirected page
I'm working on a Jetty/RESTEasy app. If I throw a WebApplicationException(myResponse) from one of my REST endpoints, it sends the given response to the client.
When a filter detects an error, I want the same behavior:
It should stop execution from proceeding, and
It should give the user a clear, JSON-formatted error that does not include a stack trace.
Obviously, just writing to the response stream and returning works from within the doFilter method. But this doesn't work for other methods called by doFilter.
Throwing any exception will meet condition #1 but I haven't figured out a sane way to meet condition #2 then. (You can see my best attempt at the bottom.)
As Perception explained in his answer, WebApplicationExceptions are treated like any other exception in the context of a Filter, and therefore give the user a nice ugly stack trace.
So, to sum up my questions:
Do serveltt containers have any equivalent to throw new WebApplicationException(Response)?
And perhaps more importantly, how do other java projects handle this?
I have this code in one filter and it works, but I'd prefer a more elegant solution that automatically applies to all filters:
public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain) throws IOException, ServletException {
try {
doFilterOrThrow(request, response, chain);
} catch (WebApplicationException e) {
Response res = e.getResponse();
((HttpServletResponse) response).sendError(res.getStatus(), (String) res.getEntity());
}
}
The specific handling you mention for web application exceptions is only defined within the context of a JAX-RS container, which, by the way, is not the same thing as a Servlet container.
Web filters are handled by the Servlet container, which does not know or care that a JAX-RS container exists within the same application server. It also does not know or care about web application exceptions. So when you throw the WAE from within the filter it is treated just the same as any other exception (server error with a stack trace, or a preconfigured error page if you set one up in your web application).
It would seem to me if you are indicating an error to the client you could simply do so from the filter, by writing directly to the response stream. But if you are trying to leverage some existing JAX-RS logic then a (RESTEasy specific) solution would be to flag the request as error'ed out in your filter, then generate a WAE in JAX-RS, using a provider class. Example:
#WebFilter(urlPatterns = "*")
public class ForwardingFilter implements Filter {
#Override
public void destroy() {
return;
}
#Override
public void doFilter(final ServletRequest request,
final ServletResponse response, final FilterChain chain)
throws IOException, ServletException {
// Add an error response to be processed by the JAX-RS container.
// This would obviously be based on some condition.
request.setAttribute("errorResponse",
Response.status(500).entity("Didn't work out!").build());
chain.doFilter(request, response);
}
#Override
public void init(FilterConfig arg0) throws ServletException {
return;
}
}
#Provider
#ServerInterceptor
#HeaderDecoratorPrecedence
#RequestScoped
public class ForwardingHandlerProvider implements PreProcessInterceptor {
#Override
public ServerResponse preProcess(final HttpRequest request,
final ResourceMethod method) throws Failure,
WebApplicationException {
final Response errorResponse = (Response) request
.getAttribute("errorResponse");
if (errorResponse != null)
throw new WebApplicationException(errorResponse);
return null;
}
}
Since the provider exists in JAX-RS land, the web application exception is processed according to the rules of Section 3.3.4 of the JAX-RS specification, and you get the desired response at the client side.
* EDIT:*
The bottom line is, there is no standard Java EE prescribed way (currently) to handle servlet exceptions in a centralized fashion similar to what is available in JAX-RS. Since you are using JBoss/RestEASY though, you could utilize the JBoss Seam Catch library to get pretty close.
#HandlesExceptions
public class ExceptionHandler {
public void handleServletException(
final #Handles #WebRequest CaughtException<ServletException> caught,
#Context final HttpServletResponse response) {
try {
response.sendError(500, "An error occured");
} catch (final IOException ioe) {
System.err.println("Dumb IO Exception: " + ioe);
}
}
}
The above illustrates an exception handler, as described in the Seam Catch documentation. Note that the library is in massive flux right now, so you will want to utilize it only as a last resort.
I have a requirement where my requests to pages are to be filtered by an intercepting filter. Based on different conditions, the request has to be redirected to different pages.
I have created a bundle and registered the servlet and filter in the bundle activator, taking a cue from here.
Following is the code snippet:
Hashtable initParams = new Hashtable(); // to pass a dictionary object to
// service.register
initParams.put("sling.servlet.resourceTypes","/login");
initParams.put("sling.servlet.extensions","jsp");
service.registerServlet("/myServlet", this.myServlet, initParams, null);
initParams = new Hashtable();
initParams.put("sling.filter.scope","REQUEST");
service.registerFilter(this.checkPageRequest, "/.*",null, 2, null);
service.registerFilter(this.checkValidSession, "/.*", null, 1, null);
I am facing two issues:
I am not able to identify where I am mapping a filter to corresponding servlet. My understanding is that the checkPageRequest filter would be called followed by checkValidSession. if there is no requestdispatcher.forward(..), the myServlet servlet would be hit. In my case, the filters are getting called as expected by using filterChain.doFilter(..), but the servlet is not getting called.
Since my filters have to intercept all the page requests, so when I do a requestdispatcher.forward(..) to any page, the same filter gets called again, getting into a loop.
I am developing this as OSGi bundle to be deployed on a DayCQ environment.
As you're working with Sling, you should rather use Sling's standard SCR-based methods to register your components, described at http://sling.apache.org/site/filters.html for filters and http://sling.apache.org/site/servlets.html for servlets.
Registering servlets and filters directly with the HttpService as you seem to be doing will "fight" with the SlingMainServlet, which should get all requests in a Sling application.
Well your Filter and Servlet should have the same URL mapping. Ofcourse the Filter will get called first.
Let the Filter preprocess the data and let the servlet add the data in request object and dispatch it to JSP. See below Example,
#SlingFilter(order=1)
#Properties({
#Property(name="service.pid", value="com.videojet.hiresite.filters.AddNewUserFilter",propertyPrivate=false),
#Property(name="service.description",value="Preproceesing Filter", propertyPrivate=false),
#Property(name="service.vendor",value="XXX Tech", propertyPrivate=false),
#Property(name="pattern",value="/services/videojet/v1/.*", propertyPrivate=false)
// The Property Above property Maps your Filter to URL
})
public class AddNewUserFilter implements javax.servlet.Filter{
private final Logger log = LoggerFactory.getLogger(this.getClass());
public void destroy() {
// TODO Auto-generated method stub
}
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
log.info("AddNewUserFilter Invoked Invoked");
// Preprocessing here and just call chain.doFilter(xxx);
And the Servlet
#SlingServlet(
paths={"/services/videojet/v1/AddNewUserController/view","/services/videojet/v1/AddNewUserController/userExists"
,"/services/videojet/v1/AddNewUserController/addUser"}
)
#Properties({
#Property(name="service.pid", value="com.videojet.hiresite.controllers.AddNewUserController",propertyPrivate=false),
#Property(name="service.description",value="Adds new user", propertyPrivate=false),
#Property(name="service.vendor",value="XXX Tech", propertyPrivate=false)
})
public class AddNewUserController extends SlingAllMethodsServlet{
/**
* #author Oliver Kaunds
*/
///content/dam/videojetdocuments
private static final long serialVersionUID = 1L;
private final Logger log = LoggerFactory.getLogger(this.getClass());
#Reference
protected AddNewUserService addNewUserService;
#Override
protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) throws ServletException, IOException
{
log.info(":: Do GET Called ");
String path =request.getRequestURI();
log.info("PATH :: "+ path);
try{
if(path.equals("/services/videojet/v1/AddNewUserController/view"))
{
/* Do the dispatching here One Servlet can have more than one Request
Mappings . My Each mapping serves a purpose. */
List<HRRepresentative> list =addNewUserService.getHRRepresentative();
request.setAttribute("hrList",list );
HttpSession session = request.getSession();
String userOperation =(String)session.getAttribute("userOp");
request.setAttribute("userOp", userOperation);
session.removeAttribute("userOp");
//throw new Exception("My Exception");
RequestDispatcher dispatcher =request.getRequestDispatcher("/content/videojet/en/addnewuser.html"); // Dispatch to JSP here
dispatcher.forward(request, response);
}
This is a Tried and Tested code