mapping filters and servlet in Sling - java

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

Related

Vaadin RequestDispatcher don't lead to JSP file in webapp dir

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.

How to access a spring-mvc flash redirectAttribute in the filter chain before the DispatcherServlet is invoked?

I have the following controller:
#Controller
#RequestMapping("/my-account")
public class AccountController {
#RequestMapping(value = "/foo/post",
method = RequestMethod.POST)
public String doPost(final RedirectAttributes redirectAttributes) {
redirectAttributes.addFlashAttribute("flashAttribute", "flashAttributeValue");
return "redirect:/my-account/foo/get";
}
#RequestMapping(value = "/foo/get",
method = RequestMethod.GET)
public void doGet(final HttpServletRequest request, final Model model) {
System.out.println("in request: " + RequestContextUtils.getInputFlashMap(request).get("flashAttribute"));
System.out.println("in model: " + model.asMap().get("flashAttribute"));
}
}
I would also like to access the flash attribute flashAttribute during the invocation of a filter in the filter chain that finally invokes springs default DispatcherServlet which in turn invokes AccountController.
public class FlashAttributeBasedFilter extends OncePerRequestFilter {
#Override
protected void doFilterInternal(final HttpServletRequest request, final HttpServletResponse response, final FilterChain filterChain)
throws ServletException, IOException {
String flashAttribute = // how to access the redirectAttribute flashAttribute here?
// do something with flashAttribute ...
filterChain.doFilter(request, response);
}
The DispatcherServlet uses a org.springframework.web.servlet.FlashMapManager that handles these flash attributes, but it doesn't provide read-only access so I think I would be messing something up if I would use it in the filter. And also the FlashMapManager instance is kept in the dispatcher servlet privately.
Does anybody have an idea how I can make the redirect attribute accessible in the filter chain for the GET request succeeding the POST?
Considering that all these methods return null into my filter (I don't understand why):
RequestContextUtils.getFlashMapManager(httpRequest)
RequestContextUtils.getInputFlashMap(httpRequest)
RequestContextUtils.getOutputFlashMap(httpRequest)
I used a drastic solution: read directly the into the session (where flash attributes are stored).
CopyOnWriteArrayList<FlashMap> what = (CopyOnWriteArrayList<FlashMap>) httpRequest.getSession().getAttribute("org.springframework.web.servlet.support.SessionFlashMapManager.FLASH_MAPS");
if (what != null) {
FlashMap flashMap = what.get(0);
[read flashMap as you read a HashMap]
}
I know, this code is super ugly but at the moment I don't find another solution.
Had the same problem, following works for me.
FlashMap flashMap = new SessionFlashMapManager().retrieveAndUpdate(request, null);
flashMap.get("parameter");

How can I get HttpServletRequest from ServletContext?

Is it possible to get HttpServletRequest from the ServletContext?
Is it possible to get HttpServletRequest from the ServletContext?
No.
The ServletContext represents the application. The application can cover many sessions and requests. But you can't get the "currently running" request or session via the ServletContext. Detail on how servlets and scopes work can be found in this related answer: How do servlets work? Instantiation, sessions, shared variables and multithreading.
You're unfortunately not clear on the concrete functional requirement where you need this solution. You apparently have a ServletContext at hands somehow in an instance of the class of interest, but not a HttpServletRequest. It's hard to propose an answer showing the right way how to grab the HttpServletRequest in an instance of such class anyway. Decent MVC frameworks like JSF and Spring MVC have ways to grab the HttpServletRequest associated with the current thread in any class you want.
In case you're not using a MVC framework and thus can't use its facilities, then you can achieve this manually by storing the request (and response) as a ThreadLocal<T> in the current thread via a servlet filter.
Here's a kickoff example how such a thread local context class can look like:
public final class YourContext implements AutoCloseable {
private static ThreadLocal<YourContext> instance = new ThreadLocal<>();
private HttpServletRequest request;
private HttpServletResponse response;
private YourContext(HttpServletRequest request, HttpServletResponse response) {
this.request = request;
this.response = response;
}
public static YourContext create(HttpServletRequest request, HttpServletResponse response) {
YourContext context = new YourContext(request, response);
instance.set(context);
return context;
}
public static YourContext getCurrentInstance() {
return instance.get();
}
#Override
public void close() {
instance.remove();
}
// ... (add methods here which return/delegate the request/response).
}
You can create (and close!!) it in a servlet filter as below.
#Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws ServletException, IOException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
try (YourContext context = YourContext.create(request, response)) {
chain.doFilter(request, response);
}
}
Do note that closing is very important. Otherwise the thread will get polluted after it has done its job and will be recycled for a different request or even a completely different purpose. In case you aren't on Java 7 yet and thus can't use try-with-resources statement as above, then use a try-finally block.
Then, in any artifact which is invoked by the same thread/request (i.e. other filters, any servlets, any beans/classes (in)directly invoked by those artifacts, etc), you can obtain the HttpServletRequest associated with the current thread as below:
YourContext context = YourContext.getCurrentInstance();
HttpServletRequest request = context.getRequest();
// ...
Or, better create a delegate method, depending on whatever you'd like to do with the current request, such as obtaining the request locale:
YourContext context = YourContext.getCurrentInstance();
Locale requestLocale = context.getRequestLocale();
// ...
As a real world example, Java EE's MVC framework JSF offers exactly this possibility via FacesContext.
FacesContext context = FacesContext.getCurrentInstance();
Locale requestLocale = context.getExternalContext().getRequestLocale();
// ...

call servlet method name display(HttpServletRequest request, HttpServletResponse response) from another 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"))

WebFilter urlPattern not working

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

Categories

Resources