Wow! Please! Do it again!: Java
Showing posts with label Java. Show all posts
Showing posts with label Java. Show all posts

Saturday, September 29, 2012

DEV: Eclipse Juno SR1 (4.2.1)

Get it here.

Friday, September 7, 2012

Dev: SLF4J 1.7.0 (Logger) now supports varargs

Prior to SLF4J 1.7.0 (1.6.6 and below)

    String name = "1";
    Long id = 1L;
    int age = 99;

    // one or more variables
    logger.info("[doSomething: id]={}", id);
    logger.info("[doSomething: id, name]={},{}", id, name);

    // 3 or more variables
    logger.info("[doSomething: id, name, age]={},{},{}", new Object[] {id, name, age});

In SLF4J 1.7.0, we need not declare an Object array for >= 3 variables.

    String name = "1";
    Long id = 1L;
    int age = 99;
    String status = "A";

    // one or more variables
    logger.info("[doSomething: id]={}", id);
    logger.info("[doSomething: id, name]={},{}", id, name);

    // 3 or more variables
    logger.info("[doSomething: id, name, age]={},{},{}", id, name, age);
    logger.info("[doSomething: id, name, age, status]={},{},{},{}", id, name, age, status);

Read more here (6th of September, 2012).

Wednesday, August 15, 2012

Web Dev: Spring Security - Create custom implementation of RedirectStrategy

Spring Security has the interface RedirectStrategy for one reason that is pretty obvious, to perform server-side redirects. However, it only comes with one implementation, DefaultRedirectStrategy.

Spring Security may perform server-side redirects for:
  • Session timeout/invalid.
  • Concurrent number of sessions per user exceeded.
  • Authentication success.
  • Authentication failure.
  • Access denied to certain resources.

I have had 2 real life requirements (so far) to create custom implementations for RedirectStrategy:

Case 1:
1. The system I was building had 2 different set of pages (simply put, 2 different sites).
2. One site was for customers and the other for administrators.
3. Each set of pages are protected by their own login page.
4. A different path was used to differentiate which site to display to the user:

  • /contextPath/cust/login.htm
  • /contextPath/admin/login.htm
5. Any redirect from Spring Security should be able to handle both sites (/cust and /admin) gracefully.
6. Session timeout URL is configured to "/login.htm?timeout=1". If configured to "/cust/login.htm?timeout=1" then it won't be able to handle session timeout in the /admin site.
7. Therefore, a custom RedirectStrategy (ServletPathRedirectStrategy) was the ideal place to:
  • From the request URL, detect which site it is coming from. For example, if the original request was "/contextPath/cust/accounts.htm", the site is cust.
  • The ServletPathRedirectStrategy would construct the target URL to be "/contextPath/cust/login.htm?timeout=1".
Case 2:
1. Using Spring Web Flow, JSF 2.1 and PrimeFaces to build a site.
2. More information on JsfRedirectStrategy here.

Steps:
1. Create subclass of DefaultRedirectStrategy, let's say CustomRedirectStrategy.
2. Copy the implementation from DefaultRedirectStrategy.calculateRedirectUrl to CustomRedirectStrategy. Why? Because calculateRedirectUrl was declared as private!
3. Override the sendRedirect method to fulfill your redirect requirements. Be sure to use calculateRedirectUrl as how it's used in DefaultRedirectStrategy for consistency.
4. Declare your CustomRedirectStrategy (bean name "redirectStrategy") in Spring config (XML or Annotations, I won't go there).
5. Inject "redirectStrategy" into the following beans:

  • concurrentSessionFilter - Existing class org.springframework.security.web.session.ConcurrentSessionFilter has setter for redirectStrategy.
  • invalidSessionStrategy - Unable to inject to SimpleRedirectInvalidSessionStrategy because no setter available (setRedirectStrategy). Just clone the entire SimpleRedirectInvalidSessionStrategy and add the setter.
  • authenticationEntryPoint - Existing implementation org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint declares redirectStrategy as a final attribute. Same drill, copy clone entire class and add the setter.
  • authenticationSuccessHandler - Existing implementations SavedRequestAwareAuthenticationSuccessHandler and SimpleUrlAuthenticationSuccessHandler both have the setter.
  • authenticationFailureHandler - Existing implementations ExceptionMappingAuthenticationFailureHandler and SimpleUrlAuthenticationFailureHandler both have the setter.
  • logoutSuccessHandler - Existing implementation SimpleUrlLogoutSuccessHandler has the setter.
  • Any custom bean that does server-side redirections - For example, hdivFilter?

Versions:
1. Spring Security 3.1.2
2. Spring Framework 3.1.2
3. JSF Mojarra 2.1.11
4. PrimeFaces 3.4 RC1
5. Spring Web Flow 2.3.1





Web Dev: Spring Security + JSF Ajax redirects

I'm using SWF 2.3.1 (Spring Web Flow) + JSF (Mojarra 2.1.11) + PrimeFaces 3.4 RC1 Spring Security 3.1.2.

Scenario:
1. Upon login, user is presented with a form with a standard commandButton (which is ajax enabled by default)
2. Session timeout is set to 5 minutes in web.xml
3. After 10 minutes (user had to take a dump/leak), user comes back and clicks on the commandButton.

Outcome (actual):
Nothing happens, on screen at least. This is because Spring Security filters would trigger a server side redirect (HTTP Status Code 302), and the ajax client wasn't built to handle such response.

Outcome (expected):
User should be redirected to the login page, and optionally displaying some message like "Sorry, your session has timed out due to inactivity. Please login again."

Solution:
Create a custom JsfRedirectStrategy (extends org.springframework.security.web.DefaultRedirectStrategy). It will basically do the following:

1. Check if the current request is an Ajax one.
/**
 * Copied from org.springframework.faces.webflow.JsfAjaxHandler.isAjaxRequestInternal
 * @param request
 * @return
 */
private boolean isAjaxRequest(HttpServletRequest request) {
 String header = request.getHeader("Faces-Request");
 String param = request.getParameter("javax.faces.partial.ajax");
 return ("partial/ajax".equals(header) || "true".equals(param)) ? true : false;
}
2. If yes, output (spit out) XML, so that the ajax client will perform a server-side redirect.
3. If not, perform server-side redirect as usual (refer to DefaultRedirectStrategy).

Download source for JsfRedirectStrategy here.


Web Dev: PrimeFaces 3.4 ResetInput component

PrimeFaces 3.4 RC1 is out! One of the couple of new features introduced is the ResetInput (p:resetInput) component. It can be found in the PrimeFaces Showcase Labs page as of now, and will be in the Showcase page once 3.4 GA is released. Information on this component can be found there.

Look at the following scenario:
1. There are n number of input fields. All of them are marked as required. All of them are bound to attributes in the backing bean.
2. There is also a commandButton labelled "Reset", which is NOT a typical HTML reset button (<input type="reset"). This commandButton will invoke the backing bean to clear values that are bound by the input fields.
3. Of course, there has to be a "Submit" button.
4. Now enter values for (n - 1) fields. For example, if the form has 5 fields, enter values for 4 fields only.
5. Click "Submit". Validation error occurs because all fields are required.
6. Now click "Reset". All previously entered values are intact. Why?

This is because JSF stores the submitted values in the input components' states. Updating the values in the backing bean would not work. The ResetInput component will clear the states of all editable input components.

Prior to the availability of this feature in PrimeFaces, there's a project titled PrimeFaces Extensions with a component called pe:resetEditableValues that achieves the same result as p:resetInput.