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>
+