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