Pull back struts2 extension code in preperation for changes to make it better.

git-svn-id: https://google-guice.googlecode.com/svn/trunk@1430 d779f126-a31b-0410-b53b-1d3aecad763e
diff --git a/extensions/struts2/build.properties b/extensions/struts2/build.properties
new file mode 100644
index 0000000..46349a2
--- /dev/null
+++ b/extensions/struts2/build.properties
@@ -0,0 +1,6 @@
+lib.dir=../../lib
+ext.lib.dir=lib
+src.dir=src
+build.dir=build
+module=com.google.inject.struts2
+fragment=true
diff --git a/extensions/struts2/build.xml b/extensions/struts2/build.xml
new file mode 100644
index 0000000..dbd5f2d
--- /dev/null
+++ b/extensions/struts2/build.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0"?>
+
+<project name="guice-struts2-plugin" basedir="." default="jar">
+
+  <import file="../../common.xml"/>
+  
+  <path id="compile.classpath">
+    <fileset dir="${lib.dir}" includes="*.jar"/>
+  	<fileset dir="${ext.lib.dir}" includes="*.jar"/>
+    <pathelement path="../../build/classes"/>
+    <fileset dir="../servlet/build" includes="*.jar"/>
+  </path>
+
+  <target name="jar" depends="jar.withdeps, manifest" description="Build jar.">
+    <jar destfile="${build.dir}/${ant.project.name}-${version}.jar"
+        manifest="${build.dir}/META-INF/MANIFEST.MF">
+      <zipfileset src="${build.dir}/${ant.project.name}-with-deps.jar"
+          excludes="com/google/inject/internal/**"/>
+    </jar>
+  </target>
+
+</project>
diff --git a/extensions/struts2/example/build.properties b/extensions/struts2/example/build.properties
new file mode 100644
index 0000000..a155282
--- /dev/null
+++ b/extensions/struts2/example/build.properties
@@ -0,0 +1,3 @@
+lib.dir=../lib
+src.dir=src
+build.dir=build
diff --git a/extensions/struts2/example/build.xml b/extensions/struts2/example/build.xml
new file mode 100644
index 0000000..8ebb1fe
--- /dev/null
+++ b/extensions/struts2/example/build.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0"?>
+
+<project name="guice-struts2-example">
+
+  <import file="../../common.xml"/>
+  
+  <property file="build.properties"/>
+  
+  <path id="compile.classpath">
+    <fileset dir="${lib.dir}" includes="*.jar"/>
+    <fileset dir="../../build/dist" includes="*.jar"/>
+  </path>
+
+</project>
diff --git a/extensions/struts2/example/root/WEB-INF/classes/struts.xml b/extensions/struts2/example/root/WEB-INF/classes/struts.xml
new file mode 100644
index 0000000..de434c3
--- /dev/null
+++ b/extensions/struts2/example/root/WEB-INF/classes/struts.xml
@@ -0,0 +1,17 @@
+<!DOCTYPE struts PUBLIC
+    "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
+    "http://struts.apache.org/dtds/struts-2.0.dtd">
+
+<struts>
+
+  <!-- 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" 
+        class="com.google.inject.struts2.example.Count">
+      <result>/Counter.jsp</result>
+    </action>      
+  </package>
+
+</struts>
diff --git a/extensions/struts2/example/root/WEB-INF/web.xml b/extensions/struts2/example/root/WEB-INF/web.xml
new file mode 100644
index 0000000..5878242
--- /dev/null
+++ b/extensions/struts2/example/root/WEB-INF/web.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0"?>
+<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
+  "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-mapping>
+    <filter-name>guice</filter-name>
+    <url-pattern>/*</url-pattern>
+  </filter-mapping>
+
+</web-app>
diff --git a/extensions/struts2/example/src/com/google/inject/struts2/example/Count.java b/extensions/struts2/example/src/com/google/inject/struts2/example/Count.java
new file mode 100644
index 0000000..76e7ec9
--- /dev/null
+++ b/extensions/struts2/example/src/com/google/inject/struts2/example/Count.java
@@ -0,0 +1,53 @@
+/**
+ * Copyright (C) 2006 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.struts2.example;
+
+import com.google.inject.Inject;
+import static com.opensymphony.xwork2.Action.SUCCESS;
+
+public class Count {
+
+  final Counter counter;
+  final Service service;
+  String message;
+
+  @Inject
+  public Count(Counter counter, Service service) {
+    this.counter = counter;
+    this.service = service;
+  }
+
+  public String execute() {
+    return SUCCESS;
+  }
+
+  public int getCount() {
+    return counter.increment();
+  }
+
+  public String getStatus() {
+    return service.getStatus();
+  }
+
+  public String getMessage() {
+    return message;
+  }
+
+  public void setMessage(String message) {
+    this.message = message;
+  }
+}
diff --git a/extensions/struts2/example/src/com/google/inject/struts2/example/Counter.java b/extensions/struts2/example/src/com/google/inject/struts2/example/Counter.java
new file mode 100644
index 0000000..c375b98
--- /dev/null
+++ b/extensions/struts2/example/src/com/google/inject/struts2/example/Counter.java
@@ -0,0 +1,33 @@
+/**
+ * Copyright (C) 2006 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.struts2.example;
+
+import com.google.inject.servlet.SessionScoped;
+
+/**
+ * Session-scoped counter.
+ */
+@SessionScoped
+public class Counter {
+
+  int count = 0;
+
+  /** Increments the count and returns the new value. */
+  public synchronized int increment() {
+    return count++;
+  }
+}
diff --git a/extensions/struts2/example/src/com/google/inject/struts2/example/ExampleListenerAndModule.java b/extensions/struts2/example/src/com/google/inject/struts2/example/ExampleListenerAndModule.java
new file mode 100644
index 0000000..4fc5cac
--- /dev/null
+++ b/extensions/struts2/example/src/com/google/inject/struts2/example/ExampleListenerAndModule.java
@@ -0,0 +1,44 @@
+/**
+ * Copyright (C) 2006 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.struts2.example;
+
+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 crazybob@google.com (Bob Lee)
+ */
+public class ExampleListenerAndModule extends GuiceServletContextListener {
+
+  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);
+      }
+    });
+  }
+}
diff --git a/extensions/struts2/example/src/com/google/inject/struts2/example/Main.java b/extensions/struts2/example/src/com/google/inject/struts2/example/Main.java
new file mode 100644
index 0000000..eb4f0e2
--- /dev/null
+++ b/extensions/struts2/example/src/com/google/inject/struts2/example/Main.java
@@ -0,0 +1,42 @@
+/**
+ * Copyright (C) 2006 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.struts2.example;
+
+import org.mortbay.jetty.Connector;
+import org.mortbay.jetty.Server;
+import org.mortbay.jetty.nio.SelectChannelConnector;
+import org.mortbay.jetty.webapp.WebAppContext;
+
+/**
+ * Starts the example web server on port 8080. Run from "./struts2/example".
+ */
+public class Main {
+
+  public static void main(String[] args) throws Exception {
+    Server server = new Server();
+
+    Connector connector = new SelectChannelConnector();
+    connector.setPort(8080);
+    server.setConnectors(new Connector[] { connector });
+
+    WebAppContext webapp = new WebAppContext("./root", "/example");
+    server.addHandler(webapp);
+
+    server.start();
+    server.join();
+  }
+}
diff --git a/extensions/struts2/example/src/com/google/inject/struts2/example/Service.java b/extensions/struts2/example/src/com/google/inject/struts2/example/Service.java
new file mode 100644
index 0000000..419fd85
--- /dev/null
+++ b/extensions/struts2/example/src/com/google/inject/struts2/example/Service.java
@@ -0,0 +1,6 @@
+package com.google.inject.struts2.example;
+
+public interface Service {
+
+  String getStatus();
+}
diff --git a/extensions/struts2/example/src/com/google/inject/struts2/example/ServiceImpl.java b/extensions/struts2/example/src/com/google/inject/struts2/example/ServiceImpl.java
new file mode 100644
index 0000000..63b410f
--- /dev/null
+++ b/extensions/struts2/example/src/com/google/inject/struts2/example/ServiceImpl.java
@@ -0,0 +1,8 @@
+package com.google.inject.struts2.example;
+
+public class ServiceImpl implements Service {
+
+  public String getStatus() {
+    return "We're looking good.";
+  }
+}
diff --git a/extensions/struts2/example/struts2-example.iml b/extensions/struts2/example/struts2-example.iml
new file mode 100644
index 0000000..da28d64
--- /dev/null
+++ b/extensions/struts2/example/struts2-example.iml
@@ -0,0 +1,141 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module relativePaths="true" type="JAVA_MODULE" version="4">
+  <component name="NewModuleRootManager" inherit-compiler-output="true">
+    <exclude-output />
+    <content url="file://$MODULE_DIR$">
+      <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
+    </content>
+    <orderEntry type="inheritedJdk" />
+    <orderEntry type="sourceFolder" forTests="false" />
+    <orderEntry type="module-library">
+      <library>
+        <CLASSES>
+          <root url="jar://$MODULE_DIR$/../lib/servlet-api-2.5.jar!/" />
+        </CLASSES>
+        <JAVADOC />
+        <SOURCES />
+      </library>
+    </orderEntry>
+    <orderEntry type="module-library">
+      <library>
+        <CLASSES>
+          <root url="jar://$MODULE_DIR$/../lib/jetty-util-6.1.0.jar!/" />
+        </CLASSES>
+        <JAVADOC />
+        <SOURCES />
+      </library>
+    </orderEntry>
+    <orderEntry type="module-library">
+      <library>
+        <CLASSES>
+          <root url="jar://$MODULE_DIR$/../lib/ant-1.6.5.jar!/" />
+        </CLASSES>
+        <JAVADOC />
+        <SOURCES />
+      </library>
+    </orderEntry>
+    <orderEntry type="module-library">
+      <library>
+        <CLASSES>
+          <root url="jar://$MODULE_DIR$/../lib/struts2-api-2.0.5.jar!/" />
+        </CLASSES>
+        <JAVADOC />
+        <SOURCES />
+      </library>
+    </orderEntry>
+    <orderEntry type="module-library">
+      <library>
+        <CLASSES>
+          <root url="jar://$MODULE_DIR$/../lib/struts-2.0.5-lib.zip!/" />
+        </CLASSES>
+        <JAVADOC />
+        <SOURCES />
+      </library>
+    </orderEntry>
+    <orderEntry type="module-library">
+      <library>
+        <CLASSES>
+          <root url="jar://$MODULE_DIR$/../lib/commons-logging-1.0.4.jar!/" />
+        </CLASSES>
+        <JAVADOC />
+        <SOURCES />
+      </library>
+    </orderEntry>
+    <orderEntry type="module-library">
+      <library>
+        <CLASSES>
+          <root url="jar://$MODULE_DIR$/../lib/ognl-2.6.9.jar!/" />
+        </CLASSES>
+        <JAVADOC />
+        <SOURCES />
+      </library>
+    </orderEntry>
+    <orderEntry type="module-library">
+      <library>
+        <CLASSES>
+          <root url="jar://$MODULE_DIR$/../lib/jsp-api-2.1.jar!/" />
+        </CLASSES>
+        <JAVADOC />
+        <SOURCES />
+      </library>
+    </orderEntry>
+    <orderEntry type="module-library">
+      <library>
+        <CLASSES>
+          <root url="jar://$MODULE_DIR$/../lib/xwork-2.0.0.jar!/" />
+        </CLASSES>
+        <JAVADOC />
+        <SOURCES />
+      </library>
+    </orderEntry>
+    <orderEntry type="module-library">
+      <library>
+        <CLASSES>
+          <root url="jar://$MODULE_DIR$/../lib/jsp-2.1.jar!/" />
+        </CLASSES>
+        <JAVADOC />
+        <SOURCES />
+      </library>
+    </orderEntry>
+    <orderEntry type="module-library">
+      <library>
+        <CLASSES>
+          <root url="jar://$MODULE_DIR$/../lib/jetty-6.1.0.jar!/" />
+        </CLASSES>
+        <JAVADOC />
+        <SOURCES />
+      </library>
+    </orderEntry>
+    <orderEntry type="module-library">
+      <library>
+        <CLASSES>
+          <root url="jar://$MODULE_DIR$/../lib/freemarker-2.3.8.jar!/" />
+        </CLASSES>
+        <JAVADOC />
+        <SOURCES />
+      </library>
+    </orderEntry>
+    <orderEntry type="module-library">
+      <library>
+        <CLASSES>
+          <root url="jar://$MODULE_DIR$/../lib/struts2-core-2.0.5.jar!/" />
+        </CLASSES>
+        <JAVADOC />
+        <SOURCES />
+      </library>
+    </orderEntry>
+    <orderEntry type="module-library">
+      <library>
+        <CLASSES>
+          <root url="jar://$MODULE_DIR$/../lib/core-3.1.1.jar!/" />
+        </CLASSES>
+        <JAVADOC />
+        <SOURCES />
+      </library>
+    </orderEntry>
+    <orderEntry type="module" module-name="guice" />
+    <orderEntry type="module" module-name="servlet" />
+    <orderEntry type="module" module-name="struts2-plugin" />
+  </component>
+</module>
+
diff --git a/extensions/struts2/lib/ant-1.6.5.jar b/extensions/struts2/lib/ant-1.6.5.jar
new file mode 100644
index 0000000..3beb3b8
--- /dev/null
+++ b/extensions/struts2/lib/ant-1.6.5.jar
Binary files differ
diff --git a/extensions/struts2/lib/commons-logging-1.0.4.jar b/extensions/struts2/lib/commons-logging-1.0.4.jar
new file mode 100644
index 0000000..b73a80f
--- /dev/null
+++ b/extensions/struts2/lib/commons-logging-1.0.4.jar
Binary files differ
diff --git a/extensions/struts2/lib/core-3.1.1.jar b/extensions/struts2/lib/core-3.1.1.jar
new file mode 100644
index 0000000..ae0b635
--- /dev/null
+++ b/extensions/struts2/lib/core-3.1.1.jar
Binary files differ
diff --git a/extensions/struts2/lib/freemarker-2.3.8.jar b/extensions/struts2/lib/freemarker-2.3.8.jar
new file mode 100644
index 0000000..737bfb5
--- /dev/null
+++ b/extensions/struts2/lib/freemarker-2.3.8.jar
Binary files differ
diff --git a/extensions/struts2/lib/jetty-6.1.0.jar b/extensions/struts2/lib/jetty-6.1.0.jar
new file mode 100644
index 0000000..6b01acd
--- /dev/null
+++ b/extensions/struts2/lib/jetty-6.1.0.jar
Binary files differ
diff --git a/extensions/struts2/lib/jetty-util-6.1.0.jar b/extensions/struts2/lib/jetty-util-6.1.0.jar
new file mode 100644
index 0000000..b2afbc0
--- /dev/null
+++ b/extensions/struts2/lib/jetty-util-6.1.0.jar
Binary files differ
diff --git a/extensions/struts2/lib/jsp-2.1.jar b/extensions/struts2/lib/jsp-2.1.jar
new file mode 100644
index 0000000..c07d0f9
--- /dev/null
+++ b/extensions/struts2/lib/jsp-2.1.jar
Binary files differ
diff --git a/extensions/struts2/lib/jsp-api-2.1.jar b/extensions/struts2/lib/jsp-api-2.1.jar
new file mode 100644
index 0000000..3ecd2f5
--- /dev/null
+++ b/extensions/struts2/lib/jsp-api-2.1.jar
Binary files differ
diff --git a/extensions/struts2/lib/ognl-2.6.9.jar b/extensions/struts2/lib/ognl-2.6.9.jar
new file mode 100644
index 0000000..0f1c0fb
--- /dev/null
+++ b/extensions/struts2/lib/ognl-2.6.9.jar
Binary files differ
diff --git a/extensions/struts2/lib/servlet-api-2.5.jar b/extensions/struts2/lib/servlet-api-2.5.jar
new file mode 100644
index 0000000..fb52493
--- /dev/null
+++ b/extensions/struts2/lib/servlet-api-2.5.jar
Binary files differ
diff --git a/extensions/struts2/lib/struts-2.0.5-lib.zip b/extensions/struts2/lib/struts-2.0.5-lib.zip
new file mode 100644
index 0000000..d5d75bf
--- /dev/null
+++ b/extensions/struts2/lib/struts-2.0.5-lib.zip
Binary files differ
diff --git a/extensions/struts2/lib/struts2-api-2.0.5.jar b/extensions/struts2/lib/struts2-api-2.0.5.jar
new file mode 100644
index 0000000..0d59962
--- /dev/null
+++ b/extensions/struts2/lib/struts2-api-2.0.5.jar
Binary files differ
diff --git a/extensions/struts2/lib/struts2-core-2.0.5.jar b/extensions/struts2/lib/struts2-core-2.0.5.jar
new file mode 100644
index 0000000..5e8702b
--- /dev/null
+++ b/extensions/struts2/lib/struts2-core-2.0.5.jar
Binary files differ
diff --git a/extensions/struts2/lib/xwork-2.0.0.jar b/extensions/struts2/lib/xwork-2.0.0.jar
new file mode 100644
index 0000000..1418069
--- /dev/null
+++ b/extensions/struts2/lib/xwork-2.0.0.jar
Binary files differ
diff --git a/extensions/struts2/pom.xml b/extensions/struts2/pom.xml
new file mode 100644
index 0000000..38d313a
--- /dev/null
+++ b/extensions/struts2/pom.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>com.google.inject.extensions</groupId>
+    <artifactId>extensions-parent</artifactId>
+    <version>3.0-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>guice-struts2</artifactId>
+
+  <name>Google Guice - Extensions - Struts2</name>
+
+  <dependencies>
+    <dependency>
+      <groupId>com.google.inject.extensions</groupId>
+      <artifactId>guice-servlet</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>javax.servlet</groupId>
+      <artifactId>servlet-api</artifactId>
+      <version>2.5</version>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.struts</groupId>
+      <artifactId>struts2-core</artifactId>
+      <version>2.2.1</version>
+      <scope>provided</scope>
+    </dependency>
+  </dependencies>
+
+</project>
diff --git a/extensions/struts2/src/com/google/inject/servlet/Struts2Factory.java b/extensions/struts2/src/com/google/inject/servlet/Struts2Factory.java
new file mode 100644
index 0000000..494811b
--- /dev/null
+++ b/extensions/struts2/src/com/google/inject/servlet/Struts2Factory.java
@@ -0,0 +1,249 @@
+/**
+ * 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.internal.Annotations;
+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 dhanji@gmail.com
+ */
+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 (Annotations.isScopeAnnotation(annotation.annotationType())) {
+        return true;
+      }
+    }
+    return false;
+  }
+}
diff --git a/extensions/struts2/src/com/google/inject/struts2/GuiceObjectFactory.java b/extensions/struts2/src/com/google/inject/struts2/GuiceObjectFactory.java
new file mode 100644
index 0000000..c6aabb6
--- /dev/null
+++ b/extensions/struts2/src/com/google/inject/struts2/GuiceObjectFactory.java
@@ -0,0 +1,245 @@
+/**
+ * Copyright (C) 2006 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.struts2;
+
+import com.google.inject.AbstractModule;
+import com.google.inject.Binder;
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import com.google.inject.Module;
+import com.google.inject.internal.Annotations;
+import com.google.inject.servlet.ServletModule;
+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;
+
+/**
+ * @deprecated Use {@link com.google.inject.servlet.Struts2Factory} instead.
+ */
+@Deprecated
+public class GuiceObjectFactory extends ObjectFactory {
+
+  static final Logger logger =
+      Logger.getLogger(GuiceObjectFactory.class.getName());
+
+  Module module;
+  volatile Injector injector;
+  boolean developmentMode = false;
+  List<ProvidedInterceptor> interceptors
+      = new ArrayList<ProvidedInterceptor>();
+
+  @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 = developmentMode.trim().equals("true");
+  }
+
+  Set<Class<?>> boundClasses = new HashSet<Class<?>>();
+
+  public Class getClassInstance(String name) throws ClassNotFoundException {
+    Class<?> clazz = super.getClassInstance(name);
+
+    synchronized (this) {
+      if (injector == 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 (injector == null) {
+      synchronized (this) {
+        if (injector == null) {
+          createInjector();
+        }
+      }
+    }
+
+    return injector.getInstance(clazz);
+  }
+
+  private void createInjector() {
+    try {
+      logger.info("Creating injector...");
+      this.injector = Guice.createInjector(new AbstractModule() {
+        protected void configure() {
+          // Install default servlet bindings.
+          install(new ServletModule());
+
+          // Install user's module.
+          if (module != null) {
+            logger.info("Installing " + module + "...");
+            install(module);
+          }
+          else {
+            logger.info("No module found. Set 'guice.module' to a Module "
+                + "class name if you'd like to use one.");
+          }
+
+          // 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();
+      }
+
+    } catch (Throwable t) {
+      t.printStackTrace();
+      System.exit(1);
+    }
+    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 (Annotations.isScopeAnnotation(annotation.annotationType())) {
+        return true;
+      }
+    }
+    return false;
+  }
+}
diff --git a/extensions/struts2/src/struts-plugin.xml b/extensions/struts2/src/struts-plugin.xml
new file mode 100644
index 0000000..381a166
--- /dev/null
+++ b/extensions/struts2/src/struts-plugin.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<!DOCTYPE struts PUBLIC
+  "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
+  "http://struts.apache.org/dtds/struts-2.0.dtd">
+    
+<struts>
+
+  <bean type="com.opensymphony.xwork2.ObjectFactory" 
+        name="guice"
+        class="com.google.inject.servlet.Struts2Factory"/>
+
+  <!--  Make the Guice object factory the automatic default -->
+  <constant name="struts.objectFactory" value="guice" />
+
+</struts>
diff --git a/extensions/struts2/struts2-plugin.iml b/extensions/struts2/struts2-plugin.iml
new file mode 100644
index 0000000..3a12397
--- /dev/null
+++ b/extensions/struts2/struts2-plugin.iml
@@ -0,0 +1,140 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module relativePaths="true" type="JAVA_MODULE" version="4">
+  <component name="NewModuleRootManager" inherit-compiler-output="true">
+    <exclude-output />
+    <content url="file://$MODULE_DIR$">
+      <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
+    </content>
+    <orderEntry type="inheritedJdk" />
+    <orderEntry type="sourceFolder" forTests="false" />
+    <orderEntry type="module" module-name="guice" />
+    <orderEntry type="module-library">
+      <library>
+        <CLASSES>
+          <root url="jar://$MODULE_DIR$/lib/jsp-2.1.jar!/" />
+        </CLASSES>
+        <JAVADOC />
+        <SOURCES />
+      </library>
+    </orderEntry>
+    <orderEntry type="module-library">
+      <library>
+        <CLASSES>
+          <root url="jar://$MODULE_DIR$/lib/jetty-6.1.0.jar!/" />
+        </CLASSES>
+        <JAVADOC />
+        <SOURCES />
+      </library>
+    </orderEntry>
+    <orderEntry type="module-library">
+      <library>
+        <CLASSES>
+          <root url="jar://$MODULE_DIR$/lib/jetty-util-6.1.0.jar!/" />
+        </CLASSES>
+        <JAVADOC />
+        <SOURCES />
+      </library>
+    </orderEntry>
+    <orderEntry type="module-library">
+      <library>
+        <CLASSES>
+          <root url="jar://$MODULE_DIR$/lib/xwork-2.0.0.jar!/" />
+        </CLASSES>
+        <JAVADOC />
+        <SOURCES />
+      </library>
+    </orderEntry>
+    <orderEntry type="module-library">
+      <library>
+        <CLASSES>
+          <root url="jar://$MODULE_DIR$/lib/freemarker-2.3.8.jar!/" />
+        </CLASSES>
+        <JAVADOC />
+        <SOURCES />
+      </library>
+    </orderEntry>
+    <orderEntry type="module-library">
+      <library>
+        <CLASSES>
+          <root url="jar://$MODULE_DIR$/lib/servlet-api-2.5.jar!/" />
+        </CLASSES>
+        <JAVADOC />
+        <SOURCES />
+      </library>
+    </orderEntry>
+    <orderEntry type="module-library">
+      <library>
+        <CLASSES>
+          <root url="jar://$MODULE_DIR$/lib/core-3.1.1.jar!/" />
+        </CLASSES>
+        <JAVADOC />
+        <SOURCES />
+      </library>
+    </orderEntry>
+    <orderEntry type="module-library">
+      <library>
+        <CLASSES>
+          <root url="jar://$MODULE_DIR$/lib/struts2-api-2.0.5.jar!/" />
+        </CLASSES>
+        <JAVADOC />
+        <SOURCES />
+      </library>
+    </orderEntry>
+    <orderEntry type="module-library">
+      <library>
+        <CLASSES>
+          <root url="jar://$MODULE_DIR$/lib/ant-1.6.5.jar!/" />
+        </CLASSES>
+        <JAVADOC />
+        <SOURCES />
+      </library>
+    </orderEntry>
+    <orderEntry type="module-library">
+      <library>
+        <CLASSES>
+          <root url="jar://$MODULE_DIR$/lib/ognl-2.6.9.jar!/" />
+        </CLASSES>
+        <JAVADOC />
+        <SOURCES />
+      </library>
+    </orderEntry>
+    <orderEntry type="module-library">
+      <library>
+        <CLASSES>
+          <root url="jar://$MODULE_DIR$/lib/struts2-core-2.0.5.jar!/" />
+        </CLASSES>
+        <JAVADOC />
+        <SOURCES />
+      </library>
+    </orderEntry>
+    <orderEntry type="module-library">
+      <library>
+        <CLASSES>
+          <root url="jar://$MODULE_DIR$/lib/struts-2.0.5-lib.zip!/" />
+        </CLASSES>
+        <JAVADOC />
+        <SOURCES />
+      </library>
+    </orderEntry>
+    <orderEntry type="module-library">
+      <library>
+        <CLASSES>
+          <root url="jar://$MODULE_DIR$/lib/commons-logging-1.0.4.jar!/" />
+        </CLASSES>
+        <JAVADOC />
+        <SOURCES />
+      </library>
+    </orderEntry>
+    <orderEntry type="module-library">
+      <library>
+        <CLASSES>
+          <root url="jar://$MODULE_DIR$/lib/jsp-api-2.1.jar!/" />
+        </CLASSES>
+        <JAVADOC />
+        <SOURCES />
+      </library>
+    </orderEntry>
+    <orderEntry type="module" module-name="servlet" />
+  </component>
+</module>
+