I have been banging on this project’s view with a few different technologies. I prototyped the thing in ZK, which turned out to be a complete piece of shit after trying to get it to work in a real world scenario. (More on that later.) Now it’s all about JSF. ICEfaces has some pretty neat components and I have almost everything mocked up. Getting the flows and conversations to work with JPA is no problem with Spring Web Flow, either. The issue is getting ICEfaces into the mix.


One particular pain is this hack done in ICEfaces 1.8.2 (I don’t know when it originally went in to the code) to grab the SWF FlowExecutor, the SpringWebFlowInstantiationServlet. I was wondering why my application context was being loaded twice, populating the MXJ database with a shitload of fake data for testing AGAIN, and then getting unique key exception. Well, this little bitch completely loads your application context a second time, side-effects and all. This new version of it should handle everything that needs to handled, without the retardation:

package com.icesoft.faces.env;

import java.io.IOException;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import org.springframework.webflow.executor.FlowExecutor;

public class SpringWebFlowInstantiationServlet
	extends HttpServlet
{

	private static FlowExecutor flowExecutor;

	public static FlowExecutor getFlowExecutor() {
		return flowExecutor;
	}

	private static void setFlowExecutor(FlowExecutor flowExecutor) {
		SpringWebFlowInstantiationServlet.flowExecutor = flowExecutor;
	}

	@Override
	public void init(ServletConfig servletConfig)
		throws ServletException
	{
		super.init(servletConfig);

		final WebApplicationContext webApplicationContext = WebApplicationContextUtils.getWebApplicationContext(servletConfig.getServletContext());

		final String[] beanNames = webApplicationContext.getBeanNamesForType(FlowExecutor.class);

		if (beanNames.length == 0) {
			throw new IllegalStateException("No bean of type FlowExecutor defined in context");
		} else if (beanNames.length > 1) {
			throw new IllegalStateException("More than one bean of type FlowExecutor defined in context.");
		} else {
			setFlowExecutor(webApplicationContext.getBean(beanNames[0], FlowExecutor.class));
		}
	}

	@Override
	public void service(HttpServletRequest request, HttpServletResponse response)
		throws ServletException, IOException
	{
		// this servlet is for instantiation SpringWebFlow but does not handle
		// requests
	}

}

I don’t know why that was so difficult the first time around. Maybe I’m missing something, but didn’t anyone think, “Wow, there must be a better way.” Not loading the Spring ContextLoaderListener isn’t optional for a lot of things, so why load it what would be a second time to fetch a single bean? It makes no sense.

While we’re at it with the patching of ICEfaces, there are some patches that needs to be made to ICEfaces to get it to work with Spring Security 3.0.0.

diff -ur core/src/com/icesoft/faces/context/BridgeExternalContext.java src/com/icesoft/faces/context/BridgeExternalContext.java
--- core/src/com/icesoft/faces/context/BridgeExternalContext.java       2009-09-03 15:58:18.000000000 -0500
+++ src/com/icesoft/faces/context/BridgeExternalContext.java     2009-12-29 13:01:35.000000000 -0600
@@ -95,6 +95,13 @@
         } catch (Throwable t) {
             Log.debug("Spring Security not detected.");
         }
+        try {
+            SpringAuthenticationClass = Class.forName("org.springframework.security.core.Authentication");
+            AuthenticationClass = SpringAuthenticationClass;
+            Log.debug("Spring Security 3 detected.");
+        } catch (Throwable t) {
+            Log.debug("Spring Security 3 not detected.");
+        }
     }

     protected static final RequestAttributes NOOPRequestAttributes = new RequestAttributes() {
diff -ur core/src/com/icesoft/faces/env/SpringAuthWrapper.java src/com/icesoft/faces/env/SpringAuthWrapper.java
--- core/src/com/icesoft/faces/env/SpringAuthWrapper.java       2008-11-13 04:11:26.000000000 -0600
+++ src/com/icesoft/faces/env/SpringAuthWrapper.java     2009-12-29 13:02:37.000000000 -0600
@@ -33,16 +33,17 @@

 package com.icesoft.faces.env;

-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.springframework.security.Authentication;
-import org.springframework.security.GrantedAuthority;
-import org.springframework.security.context.HttpSessionContextIntegrationFilter;
-import org.springframework.security.context.SecurityContext;
-
 import java.security.Principal;
+import java.util.Collection;
 import java.util.Map;

+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.context.SecurityContext;
+import org.springframework.security.web.context.HttpSessionContextIntegrationFilter;
+
 public class SpringAuthWrapper implements Authorization {
     private final static Log Log = LogFactory.getLog(SpringAuthWrapper.class);
     private final Authentication authentication;
@@ -57,13 +58,13 @@
         }
         Log.trace("isUserInRole ROLE: " + role);

-        GrantedAuthority[] authorities = authentication.getAuthorities();
+        Collection<GrantedAuthority> authorities = authentication.getAuthorities();
         if (authentication.getPrincipal() == null || authorities == null) {
             return false;
         }

-        for (int i = 0; i < authorities.length; i++) {
-            if (role.equals(authorities[i].getAuthority())) {
+        for (GrantedAuthority authority : authorities) {
+            if (role.equals(authority.getAuthority())) {
                 return true;
             }
         }
diff -ur core/src/com/icesoft/util/SeamUtilities.java src/com/icesoft/util/SeamUtilities.java
--- core/src/com/icesoft/util/SeamUtilities.java        2009-06-24 09:25:58.000000000 -0500
+++ src/com/icesoft/util/SeamUtilities.java      2009-12-28 21:51:29.000000000 -0600
@@ -67,7 +67,7 @@
     private static int springLoaded = 0;

     private static String SPRING_SECURITY_CONTEXT_HOLDER =
-            "org.springframework.security.context.SecurityContextHolder";
+            "org.springframework.security.core.context.SecurityContextHolder";
     private static int springSecurityLoaded = 0;

     static {

Yeah, really just a package name changes and that authorities return value again. It should probably check for both versions in SeamUtilities, but I only use one.

  • Digg
  • Delicious
  • StumbleUpon
  • Technorati Favorites
  • Reddit
  • Yahoo Buzz
  • Twitter
  • DZone
  • Google Bookmarks
  • LinkedIn
  • Amazon Wish List
  • Share/Bookmark