001: package com.jamonapi.http;
002:
003: /**
004: * Generic HttpMon object that monitors http request, and http response objects.
005: * Includes any dynamic data needed by HttpMonItem such as url, request and response. This allows HttpMonItems to not be
006: * created with each request. This object is constructed via HttpMonFactory and represents
007: * all monitors for one page request.
008: */
009: import java.util.Iterator;
010:
011: import javax.servlet.ServletException;
012: import java.io.IOException;
013: import javax.servlet.http.HttpServletRequest;
014:
015: import com.jamonapi.MonKeyImp;
016: import com.jamonapi.Monitor;
017: import com.jamonapi.MonitorFactory;
018: import com.jamonapi.utils.Misc;
019:
020: final class HttpMonRequest implements HttpMon {
021: private static final String EXCEPTION_ATTR = "javax.servlet.error.exception";// seems to be standarad exception property for tocmat, and jetty
022: // request.getAttribute("javax.servlet.error.exception")
023: private final Object request;//HttpServletRequest or child of it
024: private final Object response;//HttpServletResponse or a child of it
025: private final HttpMonFactory httpMonFactory;
026: private Monitor[] timeMons;// an array that is created for each time monitor
027: private int timeMonIndex = 0;// index used in start/stop methods to keep track of the current time monitor
028: private String keyReadyURI;// uri that has params removed such as jsessionid. This can be used as a jamon key.
029: private String[] details = new String[] { null, "" };// URI,EXCEPTION
030: private static final int URI = 0;
031: private static final int EXCEPTION = 1;
032: private Throwable requestException;
033:
034: HttpMonRequest(Object request, Object response,
035: HttpMonFactory httpMonFactory) {
036: this .request = request;
037: this .response = response;
038: this .httpMonFactory = httpMonFactory;
039: this .timeMons = (httpMonFactory.getNumTimeMons() > 0) ? new Monitor[httpMonFactory
040: .getNumTimeMons()]
041: : null;
042: details[URI] = getRequestURI();
043: }
044:
045: /*
046: * Method called to start monitoring http requests, and responses. Loop through all
047: * HttpMonItems starting each of them. Note state is passed into the stateless HttpMonItem
048: * instances via 'this' instance.
049: */
050: public HttpMon start() {
051: timeMonIndex = 0;// Index that is incremented for time monitors only
052: Iterator iter = iter();
053:
054: while (iter.hasNext()) {
055: HttpMonItem monItem = (HttpMonItem) iter.next();
056: monItem.start(this );
057: }
058:
059: return this ;
060: }
061:
062: /** Method called to stop any active http monitoring requests, and responses */
063: public void stop() {
064: timeMonIndex = 0;
065: setException();
066: Iterator iter = iter();
067:
068: while (iter.hasNext()) {
069: HttpMonItem monItem = (HttpMonItem) iter.next();
070: monItem.stop(this );
071: }
072:
073: // page hits do a stop
074: }
075:
076: // Iterator over httpMonItems owned by the httpMonFactory
077: private Iterator iter() {
078: return httpMonFactory.iter();
079: }
080:
081: public Object[] getDetails() {
082: return details;
083: }
084:
085: /** Detail label used in jamon. It will always include the requestURI, and will also include
086: * a stack trace if one occurred.
087: */
088: public String getDetailLabel() {
089: if ("".equalsIgnoreCase(details[EXCEPTION]))
090: return getRequestURI();
091: else
092: return new StringBuffer(getRequestURI()).append("\n")
093: .append(details[EXCEPTION]).toString();
094: }
095:
096: public Throwable getException() {
097: return requestException;
098: }
099:
100: public void setException(Throwable t) {
101: this .requestException = t;
102: }
103:
104: private void setException() {
105: if (requestException == null
106: && request instanceof HttpServletRequest) {
107: Object exc = ((HttpServletRequest) request)
108: .getAttribute(EXCEPTION_ATTR);// defined by all containers
109: if (exc instanceof Throwable)
110: setException((Throwable) exc);//sets requestException
111: }
112: // if an exception has occurred make neccesarry jamon records.
113: if (requestException != null) {
114: StringBuffer trace = new StringBuffer("stackTrace=")
115: .append(Misc.getExceptionTrace(requestException));
116: if (requestException instanceof ServletException
117: && ((ServletException) requestException)
118: .getRootCause() != null)
119: trace
120: .append("\nrootCause=")
121: .append(
122: Misc
123: .getExceptionTrace(((ServletException) requestException)
124: .getRootCause()));
125:
126: setStackTrace(trace.toString());
127: String label = getLabelPrefix() + ".ServletException";
128: MonitorFactory.add(new MonKeyImp(label, getDetails(),
129: "Exception"), 1);
130: MonitorFactory.add(new MonKeyImp(
131: MonitorFactory.EXCEPTIONS_LABEL, getDetails(),
132: "Exception"), 1);
133: }
134: }
135:
136: public void throwException(Throwable t) throws IOException,
137: ServletException {
138: setException();
139:
140: if (t instanceof ServletException)
141: throw (ServletException) t;
142: else if (t instanceof IOException)
143: throw (IOException) t;
144: else
145: throw new ServletException(t);
146:
147: }
148:
149: // Return the URI/URL of this request. As this is called often enough it is cached after the first call.
150: String getRequestURI() {
151: if (details[URI] != null)
152: return details[URI];
153: else if (request instanceof HttpServletRequest) {
154: return ((HttpServletRequest) request).getRequestURI();
155: } else
156: return "";
157: }
158:
159: // remove httpPrams from requestURI so it can be used as a jamon key without worry
160: // of creating too many keys.
161: String getKeyReadyURI() {
162: if (keyReadyURI == null)
163: keyReadyURI = removeHttpParams(getRequestURI());
164:
165: return keyReadyURI;
166:
167: }
168:
169: String getContextPath() {
170: if (request instanceof HttpServletRequest) {
171: return ((HttpServletRequest) request).getContextPath();
172: } else
173: return "";
174: }
175:
176: // used to cache Exception string as it would have to be generated once per monitor if it wasn't cached, and would also consume memory
177: // for each creation.
178: void setStackTrace(String stackTrace) {
179: details[EXCEPTION] = stackTrace;
180: }
181:
182: // Get the prefix used in the monitor label such as: com.jamonapi.http
183: String getLabelPrefix() {
184: return httpMonFactory.getLabelPrefix();
185:
186: }
187:
188: // Ignore jsessionid's and other prams as part of the request. This is done to make requests more unique (i.e. /jamon/mypage.jsp?jessionid=ls883dds)
189: // gets converted to /jamon/mypage.jsp
190: boolean getIgnoreHttpParams() {
191: return httpMonFactory.getIgnoreHttpParams();
192: }
193:
194: // Is monitoring enabled?
195: boolean isEnabled() {
196: return httpMonFactory.getEnabled();
197: }
198:
199: // Get the max possible size of the buffer before it fills. This is to avoid buffer overflow problems.
200: int getSize() {
201: return httpMonFactory.getSize();
202: }
203:
204: // httpservletrequest
205: Object getRequest() {
206: return request;
207: }
208:
209: // httpservletresponse
210: Object getResponse() {
211: return response;
212: }
213:
214: // If it is a timeMonitor then set the current monitor into the time array. This is called from httpMonItem
215: // i.e. it is a callback method called from httpMonItem start at the appropriate time and it is a time monitor
216: // Note strictly speaking the 'if' checks aren't required. However, my thought is that no app should ever
217: // risk an exception being thrown due to monitoring
218: void setTimeMon(Monitor mon) {
219: if (timeMons != null && timeMonIndex < timeMons.length)
220: timeMons[timeMonIndex++] = mon;
221: }
222:
223: // Stop the time monitoring. Note this is a call back method called from httpMonItem when stop is called on it
224: // and it is a time monitor
225: // Note strictly speaking the 'if' checks aren't required. However, my thought is that no app should ever
226: // risk an exception being thrown due to monitoring
227: void stopTimeMon() {
228: if (timeMons != null && timeMonIndex < timeMons.length)
229: timeMons[timeMonIndex++].stop();
230: }
231:
232: Monitor getNextTimeMon() {
233: if (timeMons != null && timeMonIndex < timeMons.length)
234: return timeMons[timeMonIndex++];
235: else
236: return null;
237: }
238:
239: private static String removeHttpParams(Object url) {
240: if (url == null)
241: return null;
242:
243: String urlStr = url.toString();
244: int paramIndex = urlStr.indexOf(";");
245: if (paramIndex == -1)// ; isn't in string
246: return urlStr;
247: else
248: return urlStr.substring(0, paramIndex);
249:
250: }
251:
252: }
|