001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.wicket.guice; 018 019import java.lang.reflect.InvocationTargetException; 020 021import javax.servlet.ServletContext; 022 023import com.google.inject.Guice; 024import com.google.inject.Injector; 025import com.google.inject.Module; 026import com.google.inject.Stage; 027import org.apache.wicket.protocol.http.IWebApplicationFactory; 028import org.apache.wicket.protocol.http.WebApplication; 029import org.apache.wicket.protocol.http.WicketFilter; 030import org.apache.wicket.util.string.Strings; 031 032 033/** 034 * Implementation of IWebApplicationFactory that pulls the WebApplication object out of a Guice 035 * Module. 036 * 037 * Configuration example: 038 * 039 * <pre> 040 * <filter> 041 * <filter-name>MyApplication</filter-name> 042 * <filter-class>org.apache.wicket.protocol.http.WicketFilter</filter-class> 043 * <init-param> 044 * <param-name>applicationFactoryClassName</param-name> 045 * <param-value>org.apache.wicket.guice.GuiceWebApplicationFactory</param-value> 046 * </init-param> 047 * <init-param> 048 * <param-name>module</param-name> 049 * <param-value>com.company.MyGuiceModule,com.company.MyOtherGuiceModule</param-value> 050 * </init-param> 051 * <init-param> 052 * <param-name>wicket-guice.stage</param-name> 053 * <param-value>DEVELOPMENT</param-value> 054 * </init-param> 055 * </filter> 056 * </pre> 057 * 058 * This factory will create an Injector configured using the Guice Module implementation you pass it 059 * above. Multiple modules can be specified by naming multiple classes separated by a comma. The 060 * Guice Module (MyGuiceModule in the example above) needs to bind WebApplication.class and provide 061 * a concrete implementation of it. 062 * 063 * The stage used when creating the Injector may be specified by the optional wicket-guice.stage 064 * parameter. When this parameter is not present this factory does not use specify a Stage when 065 * creating the Injector. This parameter can also be set as a context parameter to provide 066 * configuration for all instances in the web application. 067 * 068 * Alternatively, you can dig the Injector out of the ServletContext as an attribute, like so: 069 * 070 * <pre> 071 * <filter> 072 * <filter-name>MyApplication</filter-name> 073 * <filter-class>org.apache.wicket.protocol.http.WicketFilter</filter-class> 074 * <init-param> 075 * <param-name>applicationFactoryClassName</param-name> 076 * <param-value>org.apache.wicket.guice.GuiceWebApplicationFactory</param-value> 077 * </init-param> 078 * <init-param> 079 * <param-name>injectorContextAttribute</param-name> 080 * <param-value>GuiceInjector</param-value> 081 * </init-param> 082 * </filter> 083 * </pre> 084 * 085 * <b>NB: You no longer have to add a GuiceComponentInjector manually in your 086 * {@link WebApplication#init()} method - this factory will do that for you automatically.</b> 087 * 088 * @author Alastair Maw (almaw) 089 * 090 */ 091public class GuiceWebApplicationFactory implements IWebApplicationFactory 092{ 093 /** */ 094 public static final String STAGE_PARAMETER = "wicket-guice.stage"; 095 096 /** 097 * @see IWebApplicationFactory#createApplication(WicketFilter) 098 */ 099 @Override 100 public WebApplication createApplication(final WicketFilter filter) 101 { 102 Injector injector; 103 104 String injectorContextAttribute = filter.getFilterConfig().getInitParameter( 105 "injectorContextAttribute"); 106 107 Stage stage = null; 108 109 String stageContextAttribute = filter.getFilterConfig().getInitParameter(STAGE_PARAMETER); 110 if (stageContextAttribute == null) 111 { 112 stageContextAttribute = filter.getFilterConfig() 113 .getServletContext() 114 .getInitParameter(STAGE_PARAMETER); 115 } 116 if (stageContextAttribute != null) 117 { 118 stage = Stage.valueOf(stageContextAttribute.trim()); 119 } 120 121 if (injectorContextAttribute != null) 122 { 123 ServletContext sc = filter.getFilterConfig().getServletContext(); 124 125 // Try to dig the Injector out of the ServletContext, for integration with context 126 // listener-based instantiation of Guice. 127 injector = (Injector)sc.getAttribute(injectorContextAttribute); 128 if (injector == null) 129 { 130 throw new RuntimeException( 131 "Could not find Guice Injector in the ServletContext under attribute: " + 132 injectorContextAttribute); 133 } 134 } 135 else if (filter.getFilterConfig().getInitParameter("module") != null) 136 { 137 String paramValue = filter.getFilterConfig().getInitParameter("module"); 138 String moduleNames[] = Strings.split(paramValue, ','); 139 Module modules[] = new Module[moduleNames.length]; 140 ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); 141 for (int i = 0; i < moduleNames.length; i++) 142 { 143 String moduleName = moduleNames[i].trim(); 144 try 145 { 146 // see http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6500212 147 Class<?> moduleClazz = Class.forName(moduleName, false, classLoader); 148 Object moduleObject = moduleClazz.getDeclaredConstructor().newInstance(); 149 modules[i] = (Module)moduleObject; 150 } 151 catch (InstantiationException | ClassNotFoundException | IllegalAccessException 152 | NoSuchMethodException | InvocationTargetException e) 153 { 154 throw new RuntimeException( 155 "Could not create new instance of Guice Module class " + moduleName, e); 156 } 157 } 158 if (stage != null) 159 { 160 injector = Guice.createInjector(stage, modules); 161 } 162 else 163 { 164 injector = Guice.createInjector(modules); 165 } 166 } 167 else 168 { 169 throw new RuntimeException( 170 "To use GuiceWebApplicationFactory, you must specify either an 'injectorContextAttribute' or a 'module' init-param."); 171 } 172 WebApplication app = injector.getInstance(WebApplication.class); 173 app.getComponentInstantiationListeners().add(new GuiceComponentInjector(app, injector)); 174 return app; 175 } 176 177 /** {@inheritDoc} */ 178 @Override 179 public void destroy(final WicketFilter filter) 180 { 181 } 182}