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 isNoArgConstructorRequired()58 public boolean isNoArgConstructorRequired() { 59 return false; 60 } 61 62 @Inject(value = "guice.module", required = false) setModule(String moduleClassName)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) setDevelopmentMode(String developmentMode)76 void setDevelopmentMode(String developmentMode) { 77 this.developmentMode = developmentMode.trim().equals("true"); 78 } 79 80 Set<Class<?>> boundClasses = new HashSet<Class<?>>(); 81 getClassInstance(String name)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") buildBean(Class clazz, Map extraContext)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 createInjector()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") buildInterceptor(InterceptorConfig interceptorConfig, Map interceptorRefParams)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 superBuildInterceptor(InterceptorConfig interceptorConfig, Map interceptorRefParams)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 ProvidedInterceptor(InterceptorConfig config, Map params, Class<? extends Interceptor> interceptorClass)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 validate(Binder binder)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 inject()217 void inject() { 218 delegate = superBuildInterceptor(config, params); 219 } 220 destroy()221 public void destroy() { 222 if (null != delegate) { 223 delegate.destroy(); 224 } 225 } 226 init()227 public void init() { 228 throw new AssertionError(); 229 } 230 intercept(ActionInvocation invocation)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 */ hasScope(Class<? extends Interceptor> interceptorClass)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