Author: dhanji
Date: Fri Jun 26 17:59:38 2009
New Revision: 1038

Added:
     
trunk/struts2/example/src/com/google/inject/struts2/example/ExampleListenerAndModule.java
       - copied, changed from r1037,  
/trunk/struts2/example/src/com/google/inject/struts2/example/ExampleModule.java
    trunk/struts2/plugin/src/com/google/inject/servlet/
    trunk/struts2/plugin/src/com/google/inject/servlet/Struts2Factory.java
Removed:
    trunk/struts2/example/root/WEB-INF/Counter.jsp
     
trunk/struts2/example/src/com/google/inject/struts2/example/ExampleModule.java
Modified:
    trunk/servlet/servlet.iml
    trunk/servlet/src/com/google/inject/servlet/UriPatternType.java
    trunk/struts2/example/root/WEB-INF/classes/struts.xml
    trunk/struts2/example/root/WEB-INF/web.xml
     
trunk/struts2/plugin/src/com/google/inject/struts2/GuiceObjectFactory.java
    trunk/struts2/plugin/src/struts-plugin.xml

Log:
Rewrote struts2 plugin and added some bugfixes to the servlet regex  
dispatcher.
Struts2 plugin now works with Guice Servlet properly (removing the cycle  
problem) and doesn't do any malarkey like catching throwables and  
System.exit(1)ing.

Modified: trunk/servlet/servlet.iml
==============================================================================
--- trunk/servlet/servlet.iml   (original)
+++ trunk/servlet/servlet.iml   Fri Jun 26 17:59:38 2009
@@ -1,6 +1,6 @@
  <?xml version="1.0" encoding="UTF-8"?>
  <module relativePaths="true" type="JAVA_MODULE" version="4">
-  <component name="NewModuleRootManager" inherit-compiler-output="true">
+  <component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_5"  
inherit-compiler-output="true">
      <exclude-output />
      <content url="file://$MODULE_DIR$">
        <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />

Modified: trunk/servlet/src/com/google/inject/servlet/UriPatternType.java
==============================================================================
--- trunk/servlet/src/com/google/inject/servlet/UriPatternType.java      
(original)
+++ trunk/servlet/src/com/google/inject/servlet/UriPatternType.java     Fri Jun 
 
26 17:59:38 2009
@@ -95,7 +95,6 @@

    /**
     * Matchers URIs using a regular expression.
-   * NOTE(dhanji): No path info is available when using regex mapping.
     *
     * @author [email protected] (Dhanji R. Prasanna)
     */
@@ -113,7 +112,15 @@
      public String extractPath(String path) {
        Matcher matcher = pattern.matcher(path);
        if (matcher.matches() && matcher.groupCount() >= 1) {
-         return path.substring(0, matcher.start(1));
+
+        // Try to capture the everything before the regex begins to match
+        // the path. This is a rough approximation to try and get parity
+        // with the servlet style mapping where the path is a capture of
+        // the URI before the wildcard.
+        int end = matcher.start(1);
+        if (end < path.length()) {
+          return path.substring(0, end);
+        }
        }
        return null;
      }

Modified: trunk/struts2/example/root/WEB-INF/classes/struts.xml
==============================================================================
--- trunk/struts2/example/root/WEB-INF/classes/struts.xml       (original)
+++ trunk/struts2/example/root/WEB-INF/classes/struts.xml       Fri Jun 26  
17:59:38 2009
@@ -4,13 +4,13 @@

  <struts>

-  <constant name="guice.module"
-            value="com.google.inject.struts2.example.ExampleModule"/>
+  <!-- No need to specify a module here. See ExampleListenerAndModule. -->

+  <!-- Register some actions, these get injected for you by Guice -->
    <package name="default" extends="struts-default">
-    <action name="Count"
+    <action name="Count"
          class="com.google.inject.struts2.example.Count">
-      <result>/WEB-INF/Counter.jsp</result>
+      <result>/Counter.jsp</result>
      </action>
    </package>


Modified: trunk/struts2/example/root/WEB-INF/web.xml
==============================================================================
--- trunk/struts2/example/root/WEB-INF/web.xml  (original)
+++ trunk/struts2/example/root/WEB-INF/web.xml  Fri Jun 26 17:59:38 2009
@@ -3,24 +3,18 @@
    "http://java.sun.com/dtd/web-app_2_3.dtd";>

  <web-app>
-
+
+  <listener>
+       
<listener-class>com.google.inject.struts2.example.ExampleListenerAndModule</listener-class>
+  </listener>
+
    <filter>
      <filter-name>guice</filter-name>
      <filter-class>com.google.inject.servlet.GuiceFilter</filter-class>
    </filter>

-  <filter>
-    <filter-name>struts2</filter-name>
-     
<filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
-  </filter>
-
    <filter-mapping>
      <filter-name>guice</filter-name>
-    <url-pattern>/*</url-pattern>
-  </filter-mapping>
-
-  <filter-mapping>
-    <filter-name>struts2</filter-name>
      <url-pattern>/*</url-pattern>
    </filter-mapping>


Copied:  
trunk/struts2/example/src/com/google/inject/struts2/example/ExampleListenerAndModule.java
  
(from r1037,  
/trunk/struts2/example/src/com/google/inject/struts2/example/ExampleModule.java)
==============================================================================
---  
/trunk/struts2/example/src/com/google/inject/struts2/example/ExampleModule.java 
 
(original)
+++  
trunk/struts2/example/src/com/google/inject/struts2/example/ExampleListenerAndModule.java
        
Fri Jun 26 17:59:38 2009
@@ -16,16 +16,29 @@

  package com.google.inject.struts2.example;

-import com.google.inject.AbstractModule;
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import com.google.inject.Singleton;
+import com.google.inject.servlet.GuiceServletContextListener;
+import com.google.inject.servlet.ServletModule;
+import org.apache.struts2.dispatcher.FilterDispatcher;

  /**
   * Example application module.
   *
   * @author [email protected] (Bob Lee)
   */
-public class ExampleModule extends AbstractModule {
+public class ExampleListenerAndModule extends GuiceServletContextListener {

-  protected void configure() {
-    bind(Service.class).to(ServiceImpl.class);
+  protected Injector getInjector() {
+    return Guice.createInjector(new ServletModule() {
+      @Override
+      protected void configureServlets() {
+        bind(Service.class).to(ServiceImpl.class);
+
+        bind(FilterDispatcher.class).in(Singleton.class);
+         
filter("/*").through(org.apache.struts2.dispatcher.FilterDispatcher.class);
+      }
+    });
    }
  }

Added:  
trunk/struts2/plugin/src/com/google/inject/servlet/Struts2Factory.java
==============================================================================
--- (empty file)
+++ trunk/struts2/plugin/src/com/google/inject/servlet/Struts2Factory.java      
 
Fri Jun 26 17:59:38 2009
@@ -0,0 +1,251 @@
+/**
+ * Copyright (C) 2009 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.inject.servlet;
+
+import com.google.inject.AbstractModule;
+import com.google.inject.Binder;
+import com.google.inject.Injector;
+import com.google.inject.Module;
+import com.google.inject.ScopeAnnotation;
+import com.opensymphony.xwork2.ActionInvocation;
+import com.opensymphony.xwork2.ObjectFactory;
+import com.opensymphony.xwork2.config.ConfigurationException;
+import com.opensymphony.xwork2.config.entities.InterceptorConfig;
+import com.opensymphony.xwork2.inject.Inject;
+import com.opensymphony.xwork2.interceptor.Interceptor;
+import java.lang.annotation.Annotation;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.logging.Logger;
+
+/**
+ * Cleanup up version from Bob's GuiceObjectFactory. Now works properly  
with
+ * GS2 and fixes several bugs.
+ *
+ * @author [email protected]
+ */
+public class Struts2Factory extends ObjectFactory {
+
+  static final Logger logger =
+      Logger.getLogger(Struts2Factory.class.getName());
+
+  Module module;
+  volatile Injector strutsInjector;
+  boolean developmentMode = false;
+  List<ProvidedInterceptor> interceptors
+      = new ArrayList<ProvidedInterceptor>();
+  private static final String ERROR_NO_INJECTOR =
+      "Cannot find a Guice injector in the servlet context. Are you"
+          + " sure you registered GuiceServletContextListener in your  
application's web.xml?";
+
+  @Override
+  public boolean isNoArgConstructorRequired() {
+    return false;
+  }
+
+  @Inject(value = "guice.module", required = false)
+  void setModule(String moduleClassName) {
+    try {
+      // Instantiate user's module.
+      @SuppressWarnings({"unchecked"})
+      Class<? extends Module> moduleClass =
+          (Class<? extends Module>) Class.forName(moduleClassName);
+      this.module = moduleClass.newInstance();
+    } catch (Exception e) {
+      throw new RuntimeException(e);
+    }
+  }
+
+  @Inject(value = "struts.devMode", required = false)
+  void setDevelopmentMode(String developmentMode) {
+    this.developmentMode = "true".equals(developmentMode.trim());
+  }
+
+  Set<Class<?>> boundClasses = new HashSet<Class<?>>();
+
+  public Class getClassInstance(String name) throws ClassNotFoundException  
{
+    Class<?> clazz = super.getClassInstance(name);
+
+    synchronized (this) {
+      if (strutsInjector == null) {
+        // We can only bind each class once.
+        if (!boundClasses.contains(clazz)) {
+          try {
+            // Calling these methods now helps us detect  
ClassNotFoundErrors
+            // early.
+            clazz.getDeclaredFields();
+            clazz.getDeclaredMethods();
+
+            boundClasses.add(clazz);
+          } catch (Throwable t) {
+            // Struts should still work even though some classes aren't in  
the
+            // classpath. It appears we always get the exception here when
+            // this is the case.
+            return clazz;
+          }
+        }
+      }
+    }
+
+    return clazz;
+  }
+
+  @SuppressWarnings("unchecked")
+  public Object buildBean(Class clazz, Map extraContext) {
+    if (strutsInjector == null) {
+      synchronized (this) {
+        if (strutsInjector == null) {
+          createInjector();
+        }
+      }
+    }
+
+    return strutsInjector.getInstance(clazz);
+  }
+
+  private void createInjector() {
+    logger.info("Loading struts2 Guice support...");
+
+    // Attach to parent Guice injector from GS2.
+    Injector injector = (Injector) GuiceFilter.getServletContext()
+        .getAttribute(GuiceServletContextListener.INJECTOR_NAME);
+
+    // Something is wrong, since this should be there if  
GuiceServletContextListener
+    // was present.
+    if (null == injector) {
+      logger.severe(ERROR_NO_INJECTOR);
+      throw new RuntimeException(ERROR_NO_INJECTOR);
+    }
+
+    if (module != null) {
+      throw new RuntimeException("The struts2 plugin no longer supports  
specifying a module"
+          + "via the 'guice.module' property in XML."
+          + " Please install your module via a GuiceServletContextListener  
instead.");
+    }
+
+    this.strutsInjector = injector.createChildInjector(new  
AbstractModule() {
+      protected void configure() {
+
+        // Tell the injector about all the action classes, etc., so it
+        // can validate them at startup.
+        for (Class<?> boundClass : boundClasses) {
+          // TODO: Set source from Struts XML.
+          bind(boundClass);
+        }
+
+        // Validate the interceptor class.
+        for (ProvidedInterceptor interceptor : interceptors) {
+          interceptor.validate(binder());
+        }
+      }
+    });
+
+    // Inject interceptors.
+    for (ProvidedInterceptor interceptor : interceptors) {
+      interceptor.inject();
+    }
+
+    logger.info("Injector created successfully.");
+  }
+
+  @SuppressWarnings("unchecked")
+  public Interceptor buildInterceptor(InterceptorConfig interceptorConfig,
+      Map interceptorRefParams) throws ConfigurationException {
+    // Ensure the interceptor class is present.
+    Class<? extends Interceptor> interceptorClass;
+    try {
+      interceptorClass =  
getClassInstance(interceptorConfig.getClassName());
+    } catch (ClassNotFoundException e) {
+      throw new RuntimeException(e);
+    }
+
+    ProvidedInterceptor providedInterceptor = new ProvidedInterceptor(
+        interceptorConfig, interceptorRefParams, interceptorClass);
+    interceptors.add(providedInterceptor);
+    return providedInterceptor;
+  }
+
+  Interceptor superBuildInterceptor(InterceptorConfig interceptorConfig,
+      Map interceptorRefParams) throws ConfigurationException {
+    return super.buildInterceptor(interceptorConfig, interceptorRefParams);
+  }
+
+  class ProvidedInterceptor implements Interceptor {
+
+    final InterceptorConfig config;
+    final Map params;
+    final Class<? extends Interceptor> interceptorClass;
+    Interceptor delegate;
+
+    ProvidedInterceptor(InterceptorConfig config, Map params,
+        Class<? extends Interceptor> interceptorClass) {
+      this.config = config;
+      this.params = params;
+      this.interceptorClass = interceptorClass;
+    }
+
+    void validate(Binder binder) {
+      // TODO: Set source from Struts XML.
+      if (hasScope(interceptorClass)) {
+        binder.addError("Scoping interceptors is not currently supported."
+            + " Please remove the scope annotation from "
+            + interceptorClass.getName() + ".");
+      }
+
+      // Make sure it implements Interceptor.
+      if (!Interceptor.class.isAssignableFrom(interceptorClass)) {
+        binder.addError(interceptorClass.getName() + " must implement "
+          + Interceptor.class.getName() + ".");
+      }
+    }
+
+    void inject() {
+      delegate = superBuildInterceptor(config, params);
+    }
+
+    public void destroy() {
+      if (null != delegate) {
+        delegate.destroy();
+      }
+    }
+
+    public void init() {
+      throw new AssertionError();
+    }
+
+    public String intercept(ActionInvocation invocation) throws Exception {
+      return delegate.intercept(invocation);
+    }
+  }
+
+  /**
+   * Returns true if the given class has a scope annotation.
+   */
+  private static boolean hasScope(
+      Class<? extends Interceptor> interceptorClass) {
+    for (Annotation annotation : interceptorClass.getAnnotations()) {
+      if (annotation.annotationType()
+          .isAnnotationPresent(ScopeAnnotation.class)) {
+        return true;
+      }
+    }
+    return false;
+  }
+}

Modified:  
trunk/struts2/plugin/src/com/google/inject/struts2/GuiceObjectFactory.java
==============================================================================
---  
trunk/struts2/plugin/src/com/google/inject/struts2/GuiceObjectFactory.java      
 
(original)
+++  
trunk/struts2/plugin/src/com/google/inject/struts2/GuiceObjectFactory.java      
 
Fri Jun 26 17:59:38 2009
@@ -37,6 +37,10 @@
  import java.util.Set;
  import java.util.logging.Logger;

+/**
+ * @deprecated Use {...@link com.google.inject.servlet.Struts2Factory}  
instead.
+ */
+...@deprecated
  public class GuiceObjectFactory extends ObjectFactory {

    static final Logger logger =
@@ -213,7 +217,9 @@
      }

      public void destroy() {
-      delegate.destroy();
+      if (null != delegate) {
+        delegate.destroy();
+      }
      }

      public void init() {

Modified: trunk/struts2/plugin/src/struts-plugin.xml
==============================================================================
--- trunk/struts2/plugin/src/struts-plugin.xml  (original)
+++ trunk/struts2/plugin/src/struts-plugin.xml  Fri Jun 26 17:59:38 2009
@@ -8,7 +8,7 @@

    <bean type="com.opensymphony.xwork2.ObjectFactory"
          name="guice"
-        class="com.google.inject.struts2.GuiceObjectFactory"/>
+        class="com.google.inject.servlet.Struts2Factory"/>

    <!--  Make the Guice object factory the automatic default -->
    <constant name="struts.objectFactory" value="guice" />

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"google-guice-dev" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to 
[email protected]
For more options, visit this group at 
http://groups.google.com/group/google-guice-dev?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to