001: /**
002: * Copyright (C) 2006 Google Inc.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */package com.google.inject.struts2;
016:
017: import com.google.inject.AbstractModule;
018: import com.google.inject.Guice;
019: import com.google.inject.Injector;
020: import com.google.inject.Module;
021: import com.google.inject.servlet.ServletModule;
022: import com.opensymphony.xwork2.ActionInvocation;
023: import com.opensymphony.xwork2.ObjectFactory;
024: import com.opensymphony.xwork2.config.ConfigurationException;
025: import com.opensymphony.xwork2.config.entities.InterceptorConfig;
026: import com.opensymphony.xwork2.inject.Inject;
027: import com.opensymphony.xwork2.interceptor.Interceptor;
028: import java.util.HashSet;
029: import java.util.Map;
030: import java.util.Set;
031: import java.util.logging.Logger;
032:
033: public class GuiceObjectFactory extends ObjectFactory {
034:
035: static final Logger logger = Logger
036: .getLogger(GuiceObjectFactory.class.getName());
037:
038: Module module;
039: Injector injector;
040: boolean developmentMode = false;
041:
042: @Override
043: public boolean isNoArgConstructorRequired() {
044: return false;
045: }
046:
047: @Inject(value="guice.module",required=false)
048: void setModule(String moduleClassName) {
049: try {
050: // Instantiate user's module.
051: @SuppressWarnings({"unchecked"})
052: Class<? extends Module> moduleClass = (Class<? extends Module>) Class
053: .forName(moduleClassName);
054: this .module = moduleClass.newInstance();
055: } catch (Exception e) {
056: throw new RuntimeException(e);
057: }
058: }
059:
060: @Inject(value="struts.devMode",required=false)
061: void setDevelopmentMode(String developmentMode) {
062: this .developmentMode = developmentMode.trim().equals("true");
063: }
064:
065: Set<Class<?>> boundClasses = new HashSet<Class<?>>();
066:
067: public Class getClassInstance(String name)
068: throws ClassNotFoundException {
069: Class<?> clazz = super .getClassInstance(name);
070:
071: synchronized (this ) {
072: if (injector == null) {
073: // We can only bind each class once.
074: if (!boundClasses.contains(clazz)) {
075: try {
076: // Calling these methods now helps us detect ClassNotFoundErrors
077: // early.
078: clazz.getDeclaredFields();
079: clazz.getDeclaredMethods();
080:
081: boundClasses.add(clazz);
082: } catch (Throwable t) {
083: // Struts should still work even though some classes aren't in the
084: // classpath. It appears we always get the exception here when
085: // this is the case.
086: return clazz;
087: }
088: }
089: }
090: }
091:
092: return clazz;
093: }
094:
095: public Object buildBean(Class clazz, Map extraContext) {
096: synchronized (this ) {
097: if (injector == null) {
098: try {
099: logger.info("Creating injector...");
100: this .injector = Guice
101: .createInjector(new AbstractModule() {
102: protected void configure() {
103: install(new ServletModule());
104:
105: // Tell the injector about all the action classes, etc., so it
106: // can validate them at startup.
107: for (Class<?> boundClass : boundClasses) {
108: bind(boundClass);
109: }
110: }
111: });
112: } catch (Throwable t) {
113: t.printStackTrace();
114: System.exit(1);
115: }
116: logger.info("Injector created successfully.");
117: }
118: }
119:
120: return injector.getInstance(clazz);
121: }
122:
123: public Interceptor buildInterceptor(
124: InterceptorConfig interceptorConfig,
125: Map interceptorRefParams) throws ConfigurationException {
126: try {
127: getClassInstance(interceptorConfig.getClassName());
128: } catch (ClassNotFoundException e) {
129: throw new RuntimeException(e);
130: }
131:
132: // Defer the creation of interceptors so that we don't have to create the
133: // injector until we've bound all the actions. This enables us to
134: // validate all the dependencies at once.
135: return new LazyLoadedInterceptor(interceptorConfig,
136: interceptorRefParams);
137: }
138:
139: Interceptor super BuildInterceptor(
140: InterceptorConfig interceptorConfig,
141: Map interceptorRefParams) throws ConfigurationException {
142: return super .buildInterceptor(interceptorConfig,
143: interceptorRefParams);
144: }
145:
146: class LazyLoadedInterceptor implements Interceptor {
147:
148: final InterceptorConfig config;
149: final Map params;
150:
151: LazyLoadedInterceptor(InterceptorConfig config, Map params) {
152: this .config = config;
153: this .params = params;
154: }
155:
156: Interceptor delegate = null;
157:
158: synchronized Interceptor getDelegate() {
159: if (delegate == null) {
160: delegate = super BuildInterceptor(config, params);
161: delegate.init();
162: }
163: return delegate;
164: }
165:
166: public void destroy() {
167: getDelegate().destroy();
168: }
169:
170: public void init() {
171: throw new AssertionError();
172: }
173:
174: public String intercept(ActionInvocation invocation)
175: throws Exception {
176: return getDelegate().intercept(invocation);
177: }
178: }
179: }
|