001: /*
002: * Copyright 2007 Tim Peierls
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package org.directwebremoting.guice;
017:
018: import java.util.ArrayList;
019: import java.util.List;
020: import java.util.prefs.Preferences;
021:
022: import javax.servlet.ServletContext;
023: import javax.servlet.ServletContextEvent;
024: import javax.servlet.ServletContextListener;
025:
026: import org.apache.commons.logging.Log;
027: import org.apache.commons.logging.LogFactory;
028:
029: import com.google.inject.AbstractModule;
030: import com.google.inject.Guice;
031: import com.google.inject.Injector;
032: import com.google.inject.Stage;
033:
034: import static org.directwebremoting.guice.DwrGuiceUtil.popServletContext;
035: import static org.directwebremoting.guice.DwrGuiceUtil.pushServletContext;
036:
037: /**
038: * Register a concrete subclass of this as a servlet context listener to
039: * configure an {@link Injector} and stash it in the {@link ServletContext}.
040: * @author Tim Peierls [tim at peierls dot net]
041: */
042: public abstract class DwrGuiceServletContextListener extends
043: AbstractDwrModule implements ServletContextListener {
044: /* (non-Javadoc)
045: * @see javax.servlet.ServletContextListener#contextInitialized(javax.servlet.ServletContextEvent)
046: */
047: public void contextInitialized(
048: ServletContextEvent servletContextEvent) {
049: ServletContext servletContext = servletContextEvent
050: .getServletContext();
051: pushServletContext(servletContext);
052: try {
053: Stage stage = getStage();
054: Injector injector = Guice.createInjector(stage, this );
055: publishInjector(servletContext, injector);
056: } finally {
057: popServletContext();
058: }
059: }
060:
061: /* (non-Javadoc)
062: * @see javax.servlet.ServletContextListener#contextDestroyed(javax.servlet.ServletContextEvent)
063: */
064: public void contextDestroyed(ServletContextEvent servletContextEvent) {
065: List<Exception> exceptions = new ArrayList<Exception>();
066: DwrScopes.GLOBAL.closeAll(new ExceptionLoggingCloseableHandler(
067: exceptions));
068: for (Exception e : exceptions) {
069: log.warn(
070: "During context destroy, closing globally-scoped Closeables: "
071: + e, e);
072: }
073: }
074:
075: /**
076: * Define this method to configure bindings at servlet context initialization.
077: * Call {@link AbstractModule#install AbstractModule.install(Module)} within
078: * this method to use binding code from other modules.
079: */
080: @Override
081: protected abstract void configure();
082:
083: /**
084: * Override this method to specify which stage to run Guice in.
085: * Default behavior is to look first in user preferences and then
086: * in system preferences for node "org/directwebremoting/guice"
087: * with a value for key "stage". If not found, the default is
088: * Stage.PRODUCTION.
089: */
090: protected Stage getStage() {
091: Stage stage = Stage.PRODUCTION;
092:
093: try {
094: Preferences userNode = Preferences
095: .userNodeForPackage(PACKAGE);
096: String userStage = userNode.get(STAGE_KEY, null);
097: if (userStage != null) {
098: stage = Stage.valueOf(userStage);
099: } else {
100: Preferences systemNode = Preferences
101: .systemNodeForPackage(PACKAGE);
102: String systemStage = systemNode.get(STAGE_KEY, null);
103: if (systemStage != null) {
104: stage = Stage.valueOf(systemStage);
105: }
106: }
107: } catch (Exception e) {
108: // ignore errors reading Preferences
109: }
110:
111: return stage;
112: }
113:
114: /**
115: * Subclasses can use this during stage determination and binding to
116: * read values from the current servlet context.
117: */
118: protected ServletContext getServletContext() {
119: return DwrGuiceUtil.getServletContext();
120: }
121:
122: /**
123: * Returns the Injector instance installed in the given ServletContext.
124: */
125: protected static Injector getPublishedInjector(
126: ServletContext servletContext) {
127: Injector injector = (Injector) servletContext
128: .getAttribute(INJECTOR);
129:
130: if (injector == null) {
131: throw new IllegalStateException(
132: "Cannot find Injector in servlet context."
133: + " You need to register a concrete extension of "
134: + DwrGuiceServletContextListener.class
135: .getName()
136: + " as a servlet context listener in your web.xml.");
137: }
138:
139: return injector;
140: }
141:
142: protected static void publishInjector(
143: ServletContext servletContext, Injector injector) {
144: servletContext.setAttribute(INJECTOR, injector);
145: }
146:
147: /**
148: * The key under which a provided Injector is stashed in a ServletContext.
149: * The name is prefixed by the package to avoid conflicting with other
150: * listeners using the same technique.
151: */
152: private static final String INJECTOR = DwrGuiceServletContextListener.class
153: .getPackage().getName()
154: + ".Injector";
155:
156: /** The name of the node to examine for a STAGE property. */
157: private static final Class<?> PACKAGE = DwrGuiceServletContextListener.class;
158:
159: /** The node property to examine for a value for Stage. */
160: private static final String STAGE_KEY = "stage";
161:
162: /**
163: * The log stream
164: */
165: private static final Log log = LogFactory
166: .getLog(DwrGuiceServletContextListener.class);
167: }
|