PageRenderTime 73ms CodeModel.GetById 33ms app.highlight 22ms RepoModel.GetById 1ms app.codeStats 0ms

/extensions/struts2/src/com/google/inject/struts2/Struts2Factory.java

https://gitlab.com/metamorphiccode/guice
Java | 231 lines | 153 code | 37 blank | 41 comment | 18 complexity | 577cc8a5c5e605f0ac617a781008b4ea MD5 | raw file
  1/**
  2 * Copyright (C) 2009 Google Inc.
  3 *
  4 * Licensed under the Apache License, Version 2.0 (the "License");
  5 * you may not use this file except in compliance with the License.
  6 * You may obtain a copy of the License at
  7 *
  8 * http://www.apache.org/licenses/LICENSE-2.0
  9 *
 10 * Unless required by applicable law or agreed to in writing, software
 11 * distributed under the License is distributed on an "AS IS" BASIS,
 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13 * See the License for the specific language governing permissions and
 14 * limitations under the License.
 15 */
 16
 17package com.google.inject.struts2;
 18
 19import com.google.inject.AbstractModule;
 20import com.google.inject.Binder;
 21import com.google.inject.Injector;
 22import com.google.inject.internal.Annotations;
 23
 24import com.opensymphony.xwork2.ActionInvocation;
 25import com.opensymphony.xwork2.ObjectFactory;
 26import com.opensymphony.xwork2.config.ConfigurationException;
 27import com.opensymphony.xwork2.config.entities.InterceptorConfig;
 28import com.opensymphony.xwork2.inject.Inject;
 29import com.opensymphony.xwork2.interceptor.Interceptor;
 30
 31import java.lang.annotation.Annotation;
 32import java.util.ArrayList;
 33import java.util.HashSet;
 34import java.util.List;
 35import java.util.Map;
 36import java.util.Set;
 37import java.util.logging.Logger;
 38
 39/**
 40 * Cleanup up version from Bob's GuiceObjectFactory. Now works properly with
 41 * GS2 and fixes several bugs.
 42 *
 43 * @author dhanji@gmail.com
 44 * @author benmccann.com
 45 */
 46public class Struts2Factory extends ObjectFactory {
 47
 48  private static final long serialVersionUID = 1L;
 49  private static final Logger logger = Logger.getLogger(Struts2Factory.class.getName());
 50  private static final String ERROR_NO_INJECTOR =
 51      "Cannot find a Guice injector.  Are you sure you registered a GuiceServletContextListener "
 52    + "that uses the Struts2GuicePluginModule in your application's web.xml?";
 53
 54  private static @com.google.inject.Inject Injector injector;
 55
 56  private final List<ProvidedInterceptor> interceptors = new ArrayList<ProvidedInterceptor>();
 57  private volatile Injector strutsInjector;
 58
 59  @Override
 60  public boolean isNoArgConstructorRequired() {
 61    return false;
 62  }
 63
 64  @Inject(value = "guice.module", required = false)
 65  void setModule(String moduleClassName) {
 66    throw new RuntimeException("The struts2 plugin no longer supports"
 67        + " specifying a module via the 'guice.module' property in XML."
 68        + " Please install your module via a GuiceServletContextListener instead.");
 69  }
 70
 71  Set<Class<?>> boundClasses = new HashSet<Class<?>>();
 72
 73  public Class<?> getClassInstance(String name) throws ClassNotFoundException {
 74    Class<?> clazz = super.getClassInstance(name);
 75
 76    synchronized (this) {
 77      if (strutsInjector == null) {
 78        // We can only bind each class once.
 79        if (!boundClasses.contains(clazz)) {
 80          try {
 81            // Calling these methods now helps us detect ClassNotFoundErrors
 82            // early.
 83            clazz.getDeclaredFields();
 84            clazz.getDeclaredMethods();
 85
 86            boundClasses.add(clazz);
 87          } catch (Throwable t) {
 88            // Struts should still work even though some classes aren't in the
 89            // classpath. It appears we always get the exception here when
 90            // this is the case.
 91            return clazz;
 92          }
 93        }
 94      }
 95    }
 96
 97    return clazz;
 98  }
 99
100  @Override @SuppressWarnings("unchecked")
101  public Object buildBean(Class clazz, Map<String, Object> extraContext) {
102    if (strutsInjector == null) {
103      synchronized (this) {
104        if (strutsInjector == null) {
105          createInjector();
106        }
107      }
108    }
109    return strutsInjector.getInstance(clazz);
110  }
111
112  private void createInjector() {
113    logger.info("Loading struts2 Guice support...");
114
115    // Something is wrong, since this should be there if GuiceServletContextListener
116    // was present.
117    if (injector == null) {
118      logger.severe(ERROR_NO_INJECTOR);
119      throw new RuntimeException(ERROR_NO_INJECTOR);
120    }
121
122    this.strutsInjector = injector.createChildInjector(new AbstractModule() {
123      protected void configure() {
124
125        // Tell the injector about all the action classes, etc., so it
126        // can validate them at startup.
127        for (Class<?> boundClass : boundClasses) {
128          // TODO: Set source from Struts XML.
129          bind(boundClass);
130        }
131
132        // Validate the interceptor class.
133        for (ProvidedInterceptor interceptor : interceptors) {
134          interceptor.validate(binder());
135        }
136      }
137    });
138
139    // Inject interceptors.
140    for (ProvidedInterceptor interceptor : interceptors) {
141      interceptor.inject();
142    }
143
144    logger.info("Injector created successfully.");
145  }
146
147  @SuppressWarnings("unchecked")
148  public Interceptor buildInterceptor(InterceptorConfig interceptorConfig,
149      Map interceptorRefParams) throws ConfigurationException {
150    // Ensure the interceptor class is present.
151    Class<? extends Interceptor> interceptorClass;
152    try {
153      interceptorClass = (Class<? extends Interceptor>)
154          getClassInstance(interceptorConfig.getClassName());
155    } catch (ClassNotFoundException e) {
156      throw new RuntimeException(e);
157    }
158
159    ProvidedInterceptor providedInterceptor = new ProvidedInterceptor(
160        interceptorConfig, interceptorRefParams, interceptorClass);
161    interceptors.add(providedInterceptor);
162    return providedInterceptor;
163  }
164
165  private Interceptor superBuildInterceptor(InterceptorConfig interceptorConfig,
166      Map<String, String> interceptorRefParams) throws ConfigurationException {
167    return super.buildInterceptor(interceptorConfig, interceptorRefParams);
168  }
169
170  private class ProvidedInterceptor implements Interceptor {
171
172    private static final long serialVersionUID = 1L;
173
174    private final InterceptorConfig config;
175    private final Map<String, String> params;
176    private final Class<? extends Interceptor> interceptorClass;
177    private Interceptor delegate;
178
179    ProvidedInterceptor(InterceptorConfig config, Map<String, String> params,
180        Class<? extends Interceptor> interceptorClass) {
181      this.config = config;
182      this.params = params;
183      this.interceptorClass = interceptorClass;
184    }
185
186    void validate(Binder binder) {
187      // TODO: Set source from Struts XML.
188      if (hasScope(interceptorClass)) {
189        binder.addError("Scoping interceptors is not currently supported."
190            + " Please remove the scope annotation from "
191            + interceptorClass.getName() + ".");
192      }
193
194      // Make sure it implements Interceptor.
195      if (!Interceptor.class.isAssignableFrom(interceptorClass)) {
196        binder.addError(interceptorClass.getName() + " must implement "
197          + Interceptor.class.getName() + ".");
198      }
199    }
200
201    void inject() {
202      delegate = superBuildInterceptor(config, params);
203    }
204
205    public void destroy() {
206      if (null != delegate) {
207        delegate.destroy();
208      }
209    }
210
211    public void init() {
212      throw new AssertionError();
213    }
214
215    public String intercept(ActionInvocation invocation) throws Exception {
216      return delegate.intercept(invocation);
217    }
218  }
219
220  /**
221   * Returns true if the given class has a scope annotation.
222   */
223  private static boolean hasScope(Class<? extends Interceptor> interceptorClass) {
224    for (Annotation annotation : interceptorClass.getAnnotations()) {
225      if (Annotations.isScopeAnnotation(annotation.annotationType())) {
226        return true;
227      }
228    }
229    return false;
230  }
231}