001: package clime.messadmin.filter;
002:
003: import java.io.IOException;
004: import java.util.ArrayList;
005: import java.util.Collections;
006: import java.util.Iterator;
007: import java.util.List;
008:
009: import javax.servlet.Filter;
010: import javax.servlet.FilterChain;
011: import javax.servlet.FilterConfig;
012: import javax.servlet.ServletContext;
013: import javax.servlet.ServletException;
014: import javax.servlet.ServletRequest;
015: import javax.servlet.ServletResponse;
016: import javax.servlet.http.HttpServletRequest;
017: import javax.servlet.http.HttpServletResponse;
018: import javax.servlet.http.HttpSession;
019:
020: import clime.messadmin.core.Constants;
021: import clime.messadmin.model.Server;
022: import clime.messadmin.providers.ProviderUtils;
023: import clime.messadmin.providers.spi.RequestExceptionProvider;
024: import clime.messadmin.providers.spi.RequestLifeCycleProvider;
025:
026: /**
027: * Servlet Filter which logs request stats and injects a message in the output html stream
028: * @author Cédrik LIME
029: */
030: public class MessAdminFilter implements Filter {
031: private static boolean DEBUG = false;
032: private FilterConfig config;
033:
034: private void log(final String message) {
035: if (DEBUG) {
036: config.getServletContext().log(message);
037: }
038: }
039:
040: private void log(final String message, final Throwable t) {
041: if (DEBUG) {
042: config.getServletContext().log(message, t);
043: }
044: }
045:
046: /**
047: *
048: */
049: public MessAdminFilter() {
050: super ();
051: }
052:
053: /**
054: * {@inheritDoc}
055: */
056: public void init(final FilterConfig filterConfig)
057: throws ServletException {
058: this .config = filterConfig;
059: }
060:
061: /**
062: * {@inheritDoc}
063: */
064: public void destroy() {
065: config = null;
066: }
067:
068: /**
069: * {@inheritDoc}
070: */
071: public void doFilter(final ServletRequest request,
072: final ServletResponse response, final FilterChain chain)
073: throws IOException, ServletException {
074: if (!(request instanceof HttpServletRequest && response instanceof HttpServletResponse)) {
075: // not http, don't do anything
076: chain.doFilter(request, response);
077: return;
078: }
079: // final long before0 = System.nanoTime();
080: final HttpServletRequest httpRequest = (HttpServletRequest) request;
081: final HttpSession session = httpRequest.getSession(false);
082: final MessAdminRequestWrapper wrappedRequest = new MessAdminRequestWrapper(
083: httpRequest);
084: final MessAdminResponseWrapper wrappedResponse = new MessAdminResponseWrapper(
085: (HttpServletResponse) response);
086:
087: //assert session == null || session.getServletContext() == config.getServletContext();
088:
089: // See if there is a message to inject in this request/response, and if so record it
090: boolean messageFromSession = fetchDisplayMessage(session,
091: config.getServletContext(), wrappedResponse);
092:
093: MessAdminThreadLocal.start();
094:
095: // Sniff request infos for future usage
096: Server.getInstance().requestInitialized(httpRequest,
097: config.getServletContext());
098:
099: try {
100: // pre-request plugin
101: List requestProviders = ProviderUtils
102: .getProviders(RequestLifeCycleProvider.class);
103: Iterator iter = requestProviders.iterator();
104: while (iter.hasNext()) {
105: RequestLifeCycleProvider lc = (RequestLifeCycleProvider) iter
106: .next();
107: try {
108: lc
109: .requestInitialized(wrappedRequest,
110: wrappedResponse, config
111: .getServletContext());
112: } catch (RuntimeException rte) {
113: }
114: }
115:
116: // final long before1 = System.nanoTime();
117: chain.doFilter(wrappedRequest, wrappedResponse);
118: wrappedResponse.flushBuffer();
119: // final long after0 = System.nanoTime();
120:
121: MessAdminThreadLocal.stop();
122:
123: wrappedResponse.finish();
124:
125: HttpSession sessionAfter = httpRequest.getSession(false);
126: // If injected message came from session and was not injected, put it back in session
127: if (messageFromSession) {
128: restoreDisplayMessage(session, wrappedResponse);
129: } else if (sessionAfter != null
130: && wrappedResponse.isMessageInjected()) {
131: // message is application-level and has been injected: record timestamp
132: try {
133: sessionAfter.setAttribute(
134: Constants.GLOBAL_MESSAGE_TIMESTAMP_KEY,
135: new Long(System.currentTimeMillis()));
136: } catch (IllegalStateException ise) {
137: // session is invalidated: do nothing
138: }
139: }
140:
141: if (session == null && sessionAfter != null) {
142: // Session was created
143: Server.getInstance().requestInitialized(httpRequest,
144: config.getServletContext());
145: }
146: Server.getInstance().requestDestroyed(wrappedRequest,
147: wrappedResponse, config.getServletContext());
148:
149: // post-request plugin
150: requestProviders = new ArrayList(requestProviders);
151: Collections.reverse(requestProviders);
152: iter = requestProviders.iterator();
153: while (iter.hasNext()) {
154: RequestLifeCycleProvider lc = (RequestLifeCycleProvider) iter
155: .next();
156: try {
157: lc
158: .requestDestroyed(wrappedRequest,
159: wrappedResponse, config
160: .getServletContext());
161: } catch (RuntimeException rte) {
162: }
163: }
164:
165: // final long after1 = System.nanoTime();
166:
167: // long before = before1 - before0;
168: // long after = after1 - after0;
169: // System.out.println("Before: " + before/1000000.0 + " ms\tAfter: " + after/1000000.0 + " ms\tTotal: " + (before+after)/1000000.0 + " ms.");
170: } catch (IOException ioe) {
171: reportException(wrappedRequest, wrappedResponse, ioe);
172: throw ioe;
173: } catch (ServletException se) {
174: reportException(wrappedRequest, wrappedResponse, se);
175: throw se;
176: } catch (RuntimeException rte) {
177: reportException(wrappedRequest, wrappedResponse, rte);
178: throw rte;
179: } finally {
180: MessAdminThreadLocal.remove();
181: }
182: }
183:
184: private void reportException(MessAdminRequestWrapper request,
185: MessAdminResponseWrapper response, Exception e) {
186: MessAdminThreadLocal.stop();
187: Server.getInstance().requestException(e, request, response,
188: config.getServletContext());
189: Iterator iter = ProviderUtils.getProviders(
190: RequestExceptionProvider.class).iterator();
191: while (iter.hasNext()) {
192: RequestExceptionProvider lc = (RequestExceptionProvider) iter
193: .next();
194: try {
195: lc.requestException(e, request, response, config
196: .getServletContext());
197: } catch (RuntimeException rte) {
198: }
199: }
200: }
201:
202: /**
203: * Get the session-specific message to display, or the application-specific one if no session-message exist.
204: * @param wrappedResponse
205: * @param session
206: * @return <code>true</code> if message was from user session, <code>false</code>otherwise
207: */
208: private boolean fetchDisplayMessage(final HttpSession session,
209: final ServletContext servletContext,
210: final MessAdminResponseWrapper wrappedResponse) {
211: String message = null;
212: boolean fromSession = false;
213: // try session-level message
214: if (session != null) {
215: try {
216: message = (String) session
217: .getAttribute(Constants.SESSION_MESSAGE_KEY);
218: if (message != null) {
219: // display session messages only once
220: log("Removing session message for session id " + session.getId());//$NON-NLS-1$
221: session
222: .removeAttribute(Constants.SESSION_MESSAGE_KEY);
223: fromSession = true;
224: }
225: } catch (IllegalStateException ise) {
226: // invalidated session: don't do anything
227: }
228: }
229: // try application-level message
230: if (message == null) {
231: message = (String) servletContext
232: .getAttribute(Constants.GLOBAL_MESSAGE_KEY);
233: // only display application-level message if not displayed "too" recently
234: if (message != null && session != null) {
235: Long lastTimeStamp = (Long) session
236: .getAttribute(Constants.GLOBAL_MESSAGE_TIMESTAMP_KEY);
237: if (lastTimeStamp != null) {
238: if (System.currentTimeMillis()
239: - lastTimeStamp.longValue() < Constants.GLOBAL_MESSAGE_DELTA_TIME_MIN) {
240: message = null;
241: }
242: }
243: }
244: }
245: //TODO try server-level message
246: if (message != null) {
247: wrappedResponse.setInjectedMessageHTML(message);
248: }
249: return fromSession;
250: }
251:
252: private void restoreDisplayMessage(final HttpSession session,
253: final MessAdminResponseWrapper wrappedResponse) {
254: String message = wrappedResponse.getInjectedMessageHTML();
255: if (session != null && message != null) {
256: try {
257: String newMessage = (String) session
258: .getAttribute(Constants.SESSION_MESSAGE_KEY);
259: if (newMessage == null) {
260: // only put back message if there isn't a new one
261: log("Putting back session message for session id " + session.getId());//$NON-NLS-1$
262: session.setAttribute(Constants.SESSION_MESSAGE_KEY,
263: message);
264: }
265: } catch (IllegalStateException ise) {
266: // invalidated session: don't do anything
267: }
268: }
269: }
270: }
|