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: */
017: package org.apache.jetspeed.engine;
018:
019: import java.io.IOException;
020: import java.security.Principal;
021:
022: import javax.security.auth.Subject;
023: import javax.servlet.ServletConfig;
024: import javax.servlet.ServletContext;
025: import javax.servlet.ServletException;
026: import javax.servlet.http.HttpServlet;
027: import javax.servlet.http.HttpServletRequest;
028: import javax.servlet.http.HttpServletResponse;
029: import javax.servlet.http.HttpSessionEvent;
030: import javax.servlet.http.HttpSessionListener;
031:
032: import org.apache.commons.configuration.Configuration;
033: import org.apache.commons.configuration.PropertiesConfiguration;
034: import org.apache.commons.lang.exception.ExceptionUtils;
035: import org.apache.commons.logging.Log;
036: import org.apache.commons.logging.LogFactory;
037: import org.apache.jetspeed.Jetspeed;
038: import org.apache.jetspeed.PortalReservedParameters;
039: import org.apache.jetspeed.cache.ContentCacheKeyGenerator;
040: import org.apache.jetspeed.cache.JetspeedCache;
041: import org.apache.jetspeed.components.ComponentManager;
042: import org.apache.jetspeed.components.SpringComponentManager;
043: import org.apache.jetspeed.components.factorybeans.ServletConfigFactoryBean;
044: import org.apache.jetspeed.container.session.PortalSessionsManager;
045: import org.apache.jetspeed.engine.servlet.ServletHelper;
046: import org.apache.jetspeed.exception.JetspeedException;
047: import org.apache.jetspeed.pipeline.valve.SecurityValve;
048: import org.apache.jetspeed.request.RequestContext;
049: import org.apache.jetspeed.request.RequestContextComponent;
050: import org.apache.jetspeed.security.SecurityHelper;
051: import org.apache.jetspeed.security.UserPrincipal;
052: import org.apache.jetspeed.services.JetspeedPortletServices;
053: import org.apache.jetspeed.services.PortletServices;
054: import org.apache.jetspeed.statistics.PortalStatistics;
055:
056: /**
057: * Jetspeed Servlet entry point.
058: *
059: * @author <a href="mailto:david@bluesunrise.com">David Sean Taylor </a>
060: * @version $Id: JetspeedServlet.java 553340 2007-07-04 22:00:09Z taylor $
061: */
062: public class JetspeedServlet extends HttpServlet implements
063: JetspeedEngineConstants, HttpSessionListener {
064: private static Log log;
065: private static Log console;
066:
067: /**
068: * In certain situations the init() method is called more than once,
069: * somtimes even concurrently. This causes bad things to happen, so we use
070: * this flag to prevent it.
071: */
072: private static boolean firstInit = true;
073:
074: /**
075: * Whether init succeeded or not.
076: */
077: private static Throwable initFailure = null;
078:
079: /**
080: * Should initialization activities be performed during doGet() execution?
081: */
082: private static boolean firstDoGet = true;
083:
084: /**
085: * The Jetspeed Engine
086: */
087: private static Engine engine;
088: private static RequestContextComponent contextComponent;
089:
090: private static String webappRoot;
091:
092: // -------------------------------------------------------------------
093: // I N I T I A L I Z A T I O N
094: // -------------------------------------------------------------------
095: private static final String INIT_START_MSG = "Jetspeed Starting Initialization...";
096: private static final String INIT_DONE_MSG = "Jetspeed Initialization complete, Ready to service requests.";
097:
098: /**
099: * Intialize Servlet.
100: */
101: public final void init(ServletConfig config)
102: throws ServletException {
103: synchronized (this .getClass()) {
104: if (log == null) {
105: log = LogFactory.getLog(JetspeedServlet.class);
106: console = LogFactory.getLog(CONSOLE_LOGGER);
107: }
108:
109: console.info(INIT_START_MSG);
110:
111: super .init(config);
112:
113: if (!firstInit) {
114: log
115: .info("Double initialization of Jetspeed was attempted!");
116: console
117: .info("Double initialization of Jetspeed was attempted!");
118: return;
119: }
120: // executing init will trigger some static initializers, so we have
121: // only one chance.
122: firstInit = false;
123:
124: try {
125:
126: ServletContext context = config.getServletContext();
127:
128: String propertiesFilename = ServletHelper
129: .findInitParameter(context, config,
130: JETSPEED_PROPERTIES_KEY,
131: JETSPEED_PROPERTIES_DEFAULT);
132:
133: String applicationRoot = ServletHelper
134: .findInitParameter(context, config,
135: APPLICATION_ROOT_KEY,
136: APPLICATION_ROOT_DEFAULT);
137:
138: console
139: .info("JetspeedServlet identifying web application root...");
140: webappRoot = config.getServletContext()
141: .getRealPath("/");
142: console
143: .info("JetspeedServlet identifed web application root as "
144: + webappRoot);
145:
146: if (applicationRoot == null
147: || applicationRoot.equals(WEB_CONTEXT)) {
148: applicationRoot = webappRoot;
149: }
150:
151: Configuration properties = new PropertiesConfiguration(
152: ServletHelper.getRealPath(config,
153: propertiesFilename));
154:
155: properties.setProperty(APPLICATION_ROOT_KEY,
156: applicationRoot);
157: properties.setProperty(WEBAPP_ROOT_KEY, webappRoot);
158:
159: console
160: .info("JetspeedServlet attempting to create the portlet engine...");
161:
162: engine = new JetspeedEngine(properties,
163: applicationRoot, config,
164: initializeComponentManager(config,
165: applicationRoot, properties));
166:
167: console
168: .info("JetspeedServlet attempting to start the Jetspeed Portal Engine...");
169: Jetspeed.setEngine(engine);
170: engine.start();
171: console
172: .info("JetspeedServlet has successfuly started the Jetspeed Portal Engine....");
173: contextComponent = (RequestContextComponent) Jetspeed
174: .getComponentManager().getComponent(
175: RequestContextComponent.class);
176: } catch (Throwable e) {
177: // save the exception to complain loudly later :-)
178: final String msg = "Jetspeed: init() failed: ";
179: initFailure = e;
180: log.fatal(msg, e);
181: console.fatal(msg, e);
182: }
183:
184: console.info(INIT_DONE_MSG);
185: log.info(INIT_DONE_MSG);
186: }
187: }
188:
189: /**
190: * Initializes the services which need <code>RunData</code> to initialize
191: * themselves (post startup).
192: *
193: * @param data
194: * The first <code>GET</code> request.
195: */
196: public final void init(HttpServletRequest request,
197: HttpServletResponse response) {
198: synchronized (JetspeedServlet.class) {
199: if (firstDoGet) {
200: // Mark that we're done.
201: firstDoGet = false;
202: }
203: }
204: }
205:
206: // -------------------------------------------------------------------
207: // R E Q U E S T P R O C E S S I N G
208: // -------------------------------------------------------------------
209:
210: /**
211: * The primary method invoked when the Jetspeed servlet is executed.
212: *
213: * @param req
214: * Servlet request.
215: * @param res
216: * Servlet response.
217: * @exception IOException
218: * a servlet exception.
219: * @exception ServletException
220: * a servlet exception.
221: */
222: public final void doGet(HttpServletRequest req,
223: HttpServletResponse res) throws IOException,
224: ServletException {
225: try {
226: // Check to make sure that we started up properly.
227: if (initFailure != null) {
228: throw new ServletException(
229: "Failed to initalize jetspeed. "
230: + initFailure.toString(), initFailure);
231: }
232:
233: // If this is the first invocation, perform some late
234: // initialization.
235: if (firstDoGet) {
236: init(req, res);
237: }
238:
239: //If we already passed though the content filter DON'T send it to the
240: // engine. This is a crappy hack until we find a better solution.
241: String wasFiltered = (String) req
242: .getAttribute("org.apache.jetspeed.content.filtered");
243: if (wasFiltered == null || !wasFiltered.equals("true")) {
244: // ensure that no proxy or brower caching is performed
245: // on dynamic responses resulting from pipeline execution
246: res.setHeader("Cache-Control",
247: "no-cache,no-store,private"); // HTTP/1.1 modern browser/proxy
248: res.setHeader("Pragma", "no-cache"); // HTTP/1.0 non-standard proxy
249: res.setHeader("Expires", "0"); // HTTP/1.0 browser/proxy
250:
251: // send request through pipeline
252: RequestContext context = contextComponent.create(req,
253: res, getServletConfig());
254: engine.service(context);
255: contextComponent.release(context);
256: }
257:
258: } catch (JetspeedException e) {
259: final String msg = "Fatal error encountered while processing portal request: "
260: + e.toString();
261: log.fatal(msg, e);
262: throw new ServletException(msg, e);
263: }
264: }
265:
266: /**
267: * In this application doGet and doPost are the same thing.
268: *
269: * @param req
270: * Servlet request.
271: * @param res
272: * Servlet response.
273: * @exception IOException
274: * a servlet exception.
275: * @exception ServletException
276: * a servlet exception.
277: */
278: public final void doPost(HttpServletRequest req,
279: HttpServletResponse res) throws IOException,
280: ServletException {
281: doGet(req, res);
282: }
283:
284: // -------------------------------------------------------------------
285: // S E R V L E T S H U T D O W N
286: // -------------------------------------------------------------------
287:
288: /**
289: * The <code>Servlet</code> destroy method. Invokes
290: * <code>ServiceBroker</code> tear down method.
291: */
292: public final void destroy() {
293: try {
294: Jetspeed.shutdown();
295: } catch (JetspeedException e) {
296: log.fatal("Jetspeed: shutdown() failed: ", e);
297: System.err.println(ExceptionUtils.getStackTrace(e));
298: }
299:
300: // Allow turbine to be started back up again.
301: firstInit = true;
302:
303: log.info("Done shutting down!");
304: }
305:
306: /**
307: * If you prefer to use a component manager other than Spring, you
308: * can override this method to do so. Do not explicitly call start()
309: * of the ComponentManager as the JetspeedEngine will do this within its
310: * own start() method.
311: *
312: * @param servletConfig
313: * @param appRoot
314: * @param configuration
315: * @return
316: * @throws IOException
317: */
318: protected ComponentManager initializeComponentManager(
319: ServletConfig servletConfig, String appRoot,
320: Configuration configuration) throws IOException {
321: ServletConfigFactoryBean.setServletConfig(servletConfig);
322: final String assemblyDir = configuration.getString(
323: "assembly.dir", "/WEB-INF/assembly");
324: final String assemblyFileExtension = configuration.getString(
325: "assembly.extension", ".xml");
326:
327: String[] bootConfigs = new String[] { "/WEB-INF/assembly/boot/*.xml" };
328: String[] appConfigs = new String[] {
329: assemblyDir + "/*" + assemblyFileExtension,
330: assemblyDir + "/override/*" + assemblyFileExtension };
331: ServletContext servletContext = servletConfig
332: .getServletContext();
333: SpringComponentManager cm = new SpringComponentManager(
334: bootConfigs, appConfigs, servletContext, appRoot);
335:
336: return cm;
337: }
338:
339: public void sessionCreated(HttpSessionEvent se) {
340: PortletServices services = JetspeedPortletServices
341: .getSingleton();
342: if (services != null) {
343: PortalSessionsManager psm = (PortalSessionsManager) services
344: .getService(PortalSessionsManager.SERVICE_NAME);
345: if (psm != null) {
346: psm.portalSessionCreated(se.getSession());
347: }
348: }
349: }
350:
351: public void sessionDestroyed(HttpSessionEvent se) {
352: Subject subject = (Subject) se.getSession().getAttribute(
353: PortalReservedParameters.SESSION_KEY_SUBJECT);
354: if (subject == null)
355: return;
356: if (firstInit) {
357: // Servlet already destroyed,
358: // Can't reliably access ComponentManager (Spring) anymore
359: // as for instance WAS 6.0.2 has a bug invoking this method with a wrong classLoader (not the one for the WebApp)
360: return;
361: }
362: Principal subjectUserPrincipal = SecurityHelper.getPrincipal(
363: subject, UserPrincipal.class);
364: PortalStatistics statistics = (PortalStatistics) engine
365: .getComponentManager().getComponent("PortalStatistics");
366: long sessionLength = System.currentTimeMillis()
367: - se.getSession().getCreationTime();
368: String ipAddress = (String) se.getSession().getAttribute(
369: SecurityValve.IP_ADDRESS);
370: statistics.logUserLogout(ipAddress, subjectUserPrincipal
371: .getName(), sessionLength);
372: JetspeedCache portletContentCache = (JetspeedCache) engine
373: .getComponentManager().getComponent(
374: "portletContentCache");
375: JetspeedCache decorationContentCache = null;
376:
377: try {
378: decorationContentCache = (JetspeedCache) engine
379: .getComponentManager().getComponent(
380: "decorationContentCache");
381: } catch (Exception e) {
382: }
383:
384: ContentCacheKeyGenerator generator = (ContentCacheKeyGenerator) engine
385: .getComponentManager().getComponent(
386: "ContentCacheKeyGenerator");
387:
388: if (generator.isCacheBySessionId()) {
389: portletContentCache.evictContentForUser(se.getSession()
390: .getId());
391:
392: if (decorationContentCache != null) {
393: decorationContentCache.evictContentForUser(se
394: .getSession().getId());
395: }
396: } else {
397: portletContentCache
398: .evictContentForUser(subjectUserPrincipal.getName());
399:
400: if (decorationContentCache != null) {
401: decorationContentCache
402: .evictContentForUser(subjectUserPrincipal
403: .getName());
404: }
405: }
406: }
407: }
|