Home | History | Annotate | Download | only in struts2
      1 /**
      2  * Copyright (C) 2006 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 
     17 package com.google.inject.struts2;
     18 
     19 import com.google.inject.AbstractModule;
     20 import com.google.inject.Binder;
     21 import com.google.inject.Guice;
     22 import com.google.inject.Injector;
     23 import com.google.inject.Module;
     24 import com.google.inject.internal.Annotations;
     25 import com.google.inject.servlet.ServletModule;
     26 
     27 import com.opensymphony.xwork2.ActionInvocation;
     28 import com.opensymphony.xwork2.ObjectFactory;
     29 import com.opensymphony.xwork2.config.ConfigurationException;
     30 import com.opensymphony.xwork2.config.entities.InterceptorConfig;
     31 import com.opensymphony.xwork2.inject.Inject;
     32 import com.opensymphony.xwork2.interceptor.Interceptor;
     33 
     34 import java.lang.annotation.Annotation;
     35 import java.util.ArrayList;
     36 import java.util.HashSet;
     37 import java.util.List;
     38 import java.util.Map;
     39 import java.util.Set;
     40 import java.util.logging.Logger;
     41 
     42 /**
     43  * @deprecated Use {@link com.google.inject.struts2.Struts2Factory} instead.
     44  */
     45 @Deprecated
     46 public class GuiceObjectFactory extends ObjectFactory {
     47 
     48   static final Logger logger =
     49       Logger.getLogger(GuiceObjectFactory.class.getName());
     50 
     51   Module module;
     52   volatile Injector injector;
     53   boolean developmentMode = false;
     54   List<ProvidedInterceptor> interceptors
     55       = new ArrayList<ProvidedInterceptor>();
     56 
     57   @Override
     58   public boolean isNoArgConstructorRequired() {
     59     return false;
     60   }
     61 
     62   @Inject(value = "guice.module", required = false)
     63   void setModule(String moduleClassName) {
     64     try {
     65       // Instantiate user's module.
     66       @SuppressWarnings({"unchecked"})
     67       Class<? extends Module> moduleClass =
     68           (Class<? extends Module>) Class.forName(moduleClassName);
     69       this.module = moduleClass.newInstance();
     70     } catch (Exception e) {
     71       throw new RuntimeException(e);
     72     }
     73   }
     74 
     75   @Inject(value = "struts.devMode", required = false)
     76   void setDevelopmentMode(String developmentMode) {
     77     this.developmentMode = developmentMode.trim().equals("true");
     78   }
     79 
     80   Set<Class<?>> boundClasses = new HashSet<Class<?>>();
     81 
     82   public Class getClassInstance(String name) throws ClassNotFoundException {
     83     Class<?> clazz = super.getClassInstance(name);
     84 
     85     synchronized (this) {
     86       if (injector == null) {
     87         // We can only bind each class once.
     88         if (!boundClasses.contains(clazz)) {
     89           try {
     90             // Calling these methods now helps us detect ClassNotFoundErrors
     91             // early.
     92             clazz.getDeclaredFields();
     93             clazz.getDeclaredMethods();
     94 
     95             boundClasses.add(clazz);
     96           } catch (Throwable t) {
     97             // Struts should still work even though some classes aren't in the
     98             // classpath. It appears we always get the exception here when
     99             // this is the case.
    100             return clazz;
    101           }
    102         }
    103       }
    104     }
    105 
    106     return clazz;
    107   }
    108 
    109   @SuppressWarnings("unchecked")
    110   public Object buildBean(Class clazz, Map extraContext) {
    111     if (injector == null) {
    112       synchronized (this) {
    113         if (injector == null) {
    114           createInjector();
    115         }
    116       }
    117     }
    118 
    119     return injector.getInstance(clazz);
    120   }
    121 
    122   private void createInjector() {
    123     try {
    124       logger.info("Creating injector...");
    125       this.injector = Guice.createInjector(new AbstractModule() {
    126         protected void configure() {
    127           // Install default servlet bindings.
    128           install(new ServletModule());
    129 
    130           // Install user's module.
    131           if (module != null) {
    132             logger.info("Installing " + module + "...");
    133             install(module);
    134           }
    135           else {
    136             logger.info("No module found. Set 'guice.module' to a Module "
    137                 + "class name if you'd like to use one.");
    138           }
    139 
    140           // Tell the injector about all the action classes, etc., so it
    141           // can validate them at startup.
    142           for (Class<?> boundClass : boundClasses) {
    143             // TODO: Set source from Struts XML.
    144             bind(boundClass);
    145           }
    146 
    147           // Validate the interceptor class.
    148           for (ProvidedInterceptor interceptor : interceptors) {
    149             interceptor.validate(binder());
    150           }
    151         }
    152       });
    153 
    154       // Inject interceptors.
    155       for (ProvidedInterceptor interceptor : interceptors) {
    156         interceptor.inject();
    157       }
    158 
    159     } catch (Throwable t) {
    160       t.printStackTrace();
    161       System.exit(1);
    162     }
    163     logger.info("Injector created successfully.");
    164   }
    165 
    166   @SuppressWarnings("unchecked")
    167   public Interceptor buildInterceptor(InterceptorConfig interceptorConfig,
    168       Map interceptorRefParams) throws ConfigurationException {
    169     // Ensure the interceptor class is present.
    170     Class<? extends Interceptor> interceptorClass;
    171     try {
    172       interceptorClass = getClassInstance(interceptorConfig.getClassName());
    173     } catch (ClassNotFoundException e) {
    174       throw new RuntimeException(e);
    175     }
    176 
    177     ProvidedInterceptor providedInterceptor = new ProvidedInterceptor(
    178         interceptorConfig, interceptorRefParams, interceptorClass);
    179     interceptors.add(providedInterceptor);
    180     return providedInterceptor;
    181   }
    182 
    183   Interceptor superBuildInterceptor(InterceptorConfig interceptorConfig,
    184       Map interceptorRefParams) throws ConfigurationException {
    185     return super.buildInterceptor(interceptorConfig, interceptorRefParams);
    186   }
    187 
    188   class ProvidedInterceptor implements Interceptor {
    189 
    190     final InterceptorConfig config;
    191     final Map params;
    192     final Class<? extends Interceptor> interceptorClass;
    193     Interceptor delegate;
    194 
    195     ProvidedInterceptor(InterceptorConfig config, Map params,
    196         Class<? extends Interceptor> interceptorClass) {
    197       this.config = config;
    198       this.params = params;
    199       this.interceptorClass = interceptorClass;
    200     }
    201 
    202     void validate(Binder binder) {
    203       // TODO: Set source from Struts XML.
    204       if (hasScope(interceptorClass)) {
    205         binder.addError("Scoping interceptors is not currently supported."
    206             + " Please remove the scope annotation from "
    207             + interceptorClass.getName() + ".");
    208       }
    209 
    210       // Make sure it implements Interceptor.
    211       if (!Interceptor.class.isAssignableFrom(interceptorClass)) {
    212         binder.addError(interceptorClass.getName() + " must implement "
    213           + Interceptor.class.getName() + ".");
    214       }
    215     }
    216 
    217     void inject() {
    218       delegate = superBuildInterceptor(config, params);
    219     }
    220 
    221     public void destroy() {
    222       if (null != delegate) {
    223         delegate.destroy();
    224       }
    225     }
    226 
    227     public void init() {
    228       throw new AssertionError();
    229     }
    230 
    231     public String intercept(ActionInvocation invocation) throws Exception {
    232       return delegate.intercept(invocation);
    233     }
    234   }
    235 
    236   /**
    237    * Returns true if the given class has a scope annotation.
    238    */
    239   private static boolean hasScope(Class<? extends Interceptor> interceptorClass) {
    240     for (Annotation annotation : interceptorClass.getAnnotations()) {
    241       if (Annotations.isScopeAnnotation(annotation.annotationType())) {
    242         return true;
    243       }
    244     }
    245     return false;
    246   }
    247 }
    248