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.cocoon.generation;
018:
019: import org.apache.avalon.framework.parameters.Parameters;
020: import org.apache.avalon.framework.service.ServiceException;
021: import org.apache.avalon.framework.service.ServiceManager;
022: import org.apache.cocoon.ProcessingException;
023: import org.apache.cocoon.components.profiler.EnvironmentInfo;
024: import org.apache.cocoon.components.profiler.Profiler;
025: import org.apache.cocoon.components.profiler.ProfilerResult;
026: import org.apache.cocoon.components.sax.XMLDeserializer;
027: import org.apache.cocoon.environment.ObjectModelHelper;
028: import org.apache.cocoon.environment.Request;
029: import org.apache.cocoon.environment.SourceResolver;
030: import org.apache.cocoon.xml.IncludeXMLConsumer;
031: import org.apache.cocoon.xml.XMLUtils;
032:
033: import org.xml.sax.SAXException;
034: import org.xml.sax.helpers.AttributesImpl;
035:
036: import java.io.IOException;
037: import java.text.DateFormat;
038: import java.util.Collection;
039: import java.util.Date;
040: import java.util.Iterator;
041: import java.util.Map;
042: import java.util.Set;
043:
044: /**
045: * Generates an XML representation of the current status of Profiler.
046: *
047: * @author <a href="mailto:vgritsenko@apache.org">Vadim Gritsenko</a>
048: * @author <a href="mailto:bruno@outerthought.org">Bruno Dumon</a>
049: * @author <a href="mailto:stephan@apache.org">Stephan Michels</a>
050: * @version $Id: ProfilerGenerator.java 433543 2006-08-22 06:22:54Z crossley $
051: */
052: public class ProfilerGenerator extends ServiceableGenerator {
053:
054: /**
055: * The XML PROFILER_NS for the output document.
056: */
057: private static final String PROFILER_NS = "http://apache.org/cocoon/profiler/1.0";
058:
059: private static final String PROFILERINFO_ELEMENT = "profilerinfo";
060: private static final String RESULTS_ELEMENT = "pipeline";
061: private static final String RESULT_ELEMENT = "result";
062: private static final String AVERAGERESULT_ELEMENT = "average";
063: private static final String ENVIROMENTINFO_ELEMENT = "environmentinfo";
064: private static final String REQUESTPARAMETERS_ELEMENT = "request-parameters";
065: private static final String REQUESTPARAMETER_ELEMENT = "parameter";
066: private static final String SESSIONATTRIBUTES_ELEMENT = "session-attributes";
067: private static final String SESSIONATTRIBUTE_ELEMENT = "attribute";
068: private static final String COMPONENT_ELEMENT = "component";
069: private static final String FRAGMENT_ELEMENT = "fragment";
070: private static final String PREFIX = "profiler";
071: private static final String PREFIX_COLON = "profiler:";
072:
073: private Profiler profiler;
074:
075: // the key identifying the ProfilerResult
076: private Long key = null;
077:
078: // Index of the result of latest results
079: private int resultIndex = -1;
080:
081: // Index of the componen of the latest results
082: private int componentIndex = -1;
083:
084: // Indicates if the fragment only, and not the profiler metadata around it, should be generated
085: private boolean fragmentOnly;
086:
087: /**
088: * Serviceable
089: */
090: public void service(ServiceManager manager) throws ServiceException {
091: super .service(manager);
092: this .profiler = (Profiler) super .manager.lookup(Profiler.ROLE);
093: }
094:
095: /**
096: * Setup of the profiler generator.
097: */
098: public void setup(SourceResolver resolver, Map objectModel,
099: String soure, Parameters parameters)
100: throws ProcessingException, SAXException, IOException {
101:
102: super .setup(resolver, objectModel, source, parameters);
103: Request request = ObjectModelHelper.getRequest(objectModel);
104:
105: if (request.getParameter("key") != null) {
106: this .key = new Long(Long.parseLong(request
107: .getParameter("key")));
108: } else {
109: this .key = null;
110: }
111:
112: if ((request.getParameter("result") != null)
113: && (this .key != null)) {
114: this .resultIndex = Integer.parseInt(request
115: .getParameter("result"));
116: } else {
117: this .resultIndex = -1;
118: }
119:
120: if ((request.getParameter("component") != null)
121: && (this .resultIndex != -1)) {
122: this .componentIndex = Integer.parseInt(request
123: .getParameter("component"));
124: } else {
125: this .componentIndex = -1;
126: }
127:
128: if (request.getParameter("fragmentonly") != null
129: && request.getParameter("fragmentonly").equals("true")) {
130: fragmentOnly = true;
131: } else {
132: fragmentOnly = false;
133: }
134: }
135:
136: /**
137: * Disposable
138: */
139: public void dispose() {
140: if (this .profiler != null) {
141: super .manager.release(this .profiler);
142: this .profiler = null;
143: }
144: super .dispose();
145: }
146:
147: /**
148: * Generate the status information in XML format.
149: * @throws SAXException
150: * when there is a problem creating the output SAX events.
151: */
152: public void generate() throws SAXException {
153: // check if only the stored XML data is requested
154: if (fragmentOnly && key != null && resultIndex != -1
155: && componentIndex != -1) {
156: // find the fragment
157: Object fragment = null;
158: try {
159: ProfilerResult result = profiler.getResult(key);
160: fragment = result.getSAXFragments()[resultIndex][componentIndex];
161: } catch (Exception e) {
162: // fragment will be null
163: }
164: if (fragment != null) {
165: generateSAXFragment(fragment, false);
166: } else {
167: this .contentHandler.startDocument();
168: this .contentHandler.startPrefixMapping(PREFIX,
169: PROFILER_NS);
170: this .contentHandler.startElement(PROFILER_NS,
171: "fragment-error", PREFIX_COLON
172: + "fragment-error",
173: XMLUtils.EMPTY_ATTRIBUTES);
174: char[] message = "Fragment is not available."
175: .toCharArray();
176: this .contentHandler.characters(message, 0,
177: message.length);
178: this .contentHandler.endElement(PROFILER_NS,
179: "fragment-error", PREFIX_COLON
180: + "fragment-error");
181: this .contentHandler.endPrefixMapping(PREFIX);
182: this .contentHandler.endDocument();
183: }
184: } else {
185: // Start the document and set the PROFILER_NS.
186: this .contentHandler.startDocument();
187: this .contentHandler.startPrefixMapping(PREFIX, PROFILER_NS);
188:
189: generateProfilerInfo();
190:
191: // End the document.
192: this .contentHandler.endPrefixMapping(PREFIX);
193: this .contentHandler.endDocument();
194: }
195: }
196:
197: /**
198: * Generate the main status document.
199: */
200: private void generateProfilerInfo() throws SAXException {
201: // Root element.
202:
203: // The current date and processingTime.
204: String dateTime = DateFormat.getDateTimeInstance().format(
205: new Date());
206:
207: AttributesImpl atts = new AttributesImpl();
208: atts.addAttribute("", "date", "date", "CDATA", dateTime);
209: this .contentHandler.startElement(PROFILER_NS,
210: PROFILERINFO_ELEMENT, PREFIX_COLON
211: + PROFILERINFO_ELEMENT, atts);
212:
213: Collection resultsKeys = profiler.getResultKeys();
214:
215: for (Iterator i = resultsKeys.iterator(); i.hasNext();) {
216: Long key = (Long) i.next();
217:
218: if ((this .key == null) || (this .key.equals(key))) {
219: generateResults(key, profiler.getResult(key));
220: }
221: }
222:
223: // End root element.
224: this .contentHandler.endElement(PROFILER_NS,
225: PROFILERINFO_ELEMENT, PREFIX_COLON
226: + PROFILERINFO_ELEMENT);
227: }
228:
229: /**
230: *
231: *
232: * @param key
233: * @param result
234: */
235: private void generateResults(Long key, ProfilerResult result)
236: throws SAXException {
237: AttributesImpl atts = new AttributesImpl();
238:
239: int count = result.getCount();
240: String[] roles = result.getRoles(); // Roles of the components
241: String[] sources = result.getSources(); // Source of the components
242:
243: EnvironmentInfo[] environmentInfos = result
244: .getLatestEnvironmentInfos();
245: long[] totalTime = result.getTotalTime(); // Total time of the requests
246: long[][] setupTimes = result.getSetupTimes(); // Setup time of each component
247: long[][] processingTimes = result.getProcessingTimes(); // Processing time of each component
248: Object[][] fragments = result.getSAXFragments(); // SAX Fragments of each component
249:
250: // Total time of all requests
251: long totalTimeSum = 0;
252:
253: for (int i = 0; i < count; i++) {
254: totalTimeSum += totalTime[i];
255: }
256:
257: atts.addAttribute("", "uri", "uri", "CDATA", result.getURI());
258: atts.addAttribute("", "count", "count", "CDATA", Integer
259: .toString(result.getCount()));
260: atts.addAttribute("", "processingTime", "processingTime",
261: "CDATA", Long.toString(totalTimeSum));
262: atts.addAttribute("", "key", "key", "CDATA", key.toString());
263: this .contentHandler.startElement(PROFILER_NS, RESULTS_ELEMENT,
264: PREFIX_COLON + RESULTS_ELEMENT, atts);
265: atts.clear();
266:
267: // Generate average result
268: if ((count > 0) && (this .resultIndex == -1)) {
269: atts.addAttribute("", "time", "time", "CDATA", Long
270: .toString(totalTimeSum / count));
271: this .contentHandler.startElement(PROFILER_NS,
272: AVERAGERESULT_ELEMENT, PREFIX_COLON
273: + AVERAGERESULT_ELEMENT, atts);
274: atts.clear();
275:
276: // Total time of each component for all requests
277: long[] totalTimeOfComponents = new long[roles.length];
278:
279: for (int i = 0; i < roles.length; i++) {
280: totalTimeOfComponents[i] = 0;
281: for (int j = 0; j < count; j++) {
282: totalTimeOfComponents[i] += setupTimes[j][i]
283: + processingTimes[j][i];
284: }
285: }
286:
287: for (int i = 0; i < roles.length; i++) {
288: atts.addAttribute("", "offset", "offset", "CDATA",
289: String.valueOf(i));
290:
291: if (roles[i] != null) {
292: atts.addAttribute("", "role", "role", "CDATA",
293: roles[i]);
294: }
295:
296: if (sources[i] != null) {
297: atts.addAttribute("", "source", "source", "CDATA",
298: sources[i]);
299: }
300:
301: atts.addAttribute("", "time", "time", "CDATA", Long
302: .toString(totalTimeOfComponents[i] / count));
303:
304: this .contentHandler.startElement(PROFILER_NS,
305: COMPONENT_ELEMENT, PREFIX_COLON
306: + COMPONENT_ELEMENT, atts);
307: atts.clear();
308: this .contentHandler.endElement(PROFILER_NS,
309: COMPONENT_ELEMENT, PREFIX_COLON
310: + COMPONENT_ELEMENT);
311: }
312: this .contentHandler.endElement(PROFILER_NS,
313: AVERAGERESULT_ELEMENT, PREFIX_COLON
314: + AVERAGERESULT_ELEMENT);
315: }
316:
317: for (int j = 0; j < count; j++) {
318: if ((this .resultIndex == -1) || (this .resultIndex == j)) {
319: generateResult(j, roles, sources, environmentInfos[j],
320: totalTime[j], setupTimes[j],
321: processingTimes[j], fragments[j]);
322: }
323: }
324:
325: this .contentHandler.endElement(PROFILER_NS, RESULTS_ELEMENT,
326: PREFIX_COLON + RESULTS_ELEMENT);
327: }
328:
329: private void generateResult(int resultIndex, String[] roles,
330: String[] sources, EnvironmentInfo environmentInfo,
331: long totalTime, long[] setupTimes, long[] processingTimes,
332: Object[] fragments) throws SAXException {
333:
334: AttributesImpl atts = new AttributesImpl();
335: atts.addAttribute("", "time", "time", "CDATA", Long
336: .toString(totalTime));
337: atts.addAttribute("", "index", "index", "CDATA", String
338: .valueOf(resultIndex));
339: this .contentHandler.startElement(PROFILER_NS, RESULT_ELEMENT,
340: PREFIX_COLON + RESULT_ELEMENT, atts);
341: atts.clear();
342:
343: if (this .resultIndex != -1) {
344: generateEnvironmentInfo(environmentInfo);
345: }
346:
347: for (int i = 0; i < roles.length; i++) {
348: generateComponent(i, roles[i], sources[i], setupTimes[i],
349: processingTimes[i], fragments[i]);
350: }
351: this .contentHandler.endElement(PROFILER_NS, RESULT_ELEMENT,
352: PREFIX_COLON + RESULT_ELEMENT);
353: }
354:
355: private void generateComponent(int componentIndex, String role,
356: String source, long setupTime, long processingTime,
357: Object fragment) throws SAXException {
358:
359: AttributesImpl atts = new AttributesImpl();
360: atts.addAttribute("", "index", "index", "CDATA", String
361: .valueOf(componentIndex));
362:
363: if (role != null) {
364: atts.addAttribute("", "role", "role", "CDATA", role);
365: }
366:
367: if (source != null) {
368: atts.addAttribute("", "source", "source", "CDATA", source);
369: }
370:
371: atts.addAttribute("", "setup", "setup", "CDATA", Long
372: .toString(setupTime));
373:
374: atts.addAttribute("", "processing", "processing", "CDATA", Long
375: .toString(processingTime));
376:
377: atts.addAttribute("", "time", "time", "CDATA", Long
378: .toString(setupTime + processingTime));
379:
380: this .contentHandler.startElement(PROFILER_NS,
381: COMPONENT_ELEMENT, PREFIX_COLON + COMPONENT_ELEMENT,
382: atts);
383: atts.clear();
384:
385: if (this .componentIndex == componentIndex) {
386: this .contentHandler.startElement(PROFILER_NS,
387: FRAGMENT_ELEMENT, PREFIX_COLON + FRAGMENT_ELEMENT,
388: XMLUtils.EMPTY_ATTRIBUTES);
389: generateSAXFragment(fragment, true);
390: this .contentHandler.endElement(PROFILER_NS,
391: FRAGMENT_ELEMENT, PREFIX_COLON + FRAGMENT_ELEMENT);
392: }
393:
394: this .contentHandler.endElement(PROFILER_NS, COMPONENT_ELEMENT,
395: PREFIX_COLON + COMPONENT_ELEMENT);
396: }
397:
398: private void generateEnvironmentInfo(EnvironmentInfo environmentInfo)
399: throws SAXException {
400: this .contentHandler.startElement(PROFILER_NS,
401: ENVIROMENTINFO_ELEMENT, PREFIX_COLON
402: + ENVIROMENTINFO_ELEMENT,
403: XMLUtils.EMPTY_ATTRIBUTES);
404:
405: if (environmentInfo != null) {
406: // Generate SAX events for the request parameters
407: this .contentHandler.startElement(PROFILER_NS,
408: REQUESTPARAMETERS_ELEMENT, PREFIX_COLON
409: + REQUESTPARAMETERS_ELEMENT,
410: XMLUtils.EMPTY_ATTRIBUTES);
411:
412: Map requestParameters = environmentInfo
413: .getRequestParameters();
414: Set requestParamEntries = requestParameters.entrySet();
415: Iterator requestParamEntriesIt = requestParamEntries
416: .iterator();
417:
418: while (requestParamEntriesIt.hasNext()) {
419: AttributesImpl atts = new AttributesImpl();
420: Map.Entry entry = (Map.Entry) requestParamEntriesIt
421: .next();
422:
423: atts.addAttribute("", "name", "name", "CDATA",
424: (String) entry.getKey());
425: atts.addAttribute("", "value", "value", "CDATA",
426: (String) entry.getValue());
427: this .contentHandler.startElement(PROFILER_NS,
428: REQUESTPARAMETER_ELEMENT, PREFIX_COLON
429: + REQUESTPARAMETER_ELEMENT, atts);
430: this .contentHandler.endElement(PROFILER_NS,
431: REQUESTPARAMETER_ELEMENT, PREFIX_COLON
432: + REQUESTPARAMETER_ELEMENT);
433: }
434: this .contentHandler.endElement(PROFILER_NS,
435: REQUESTPARAMETERS_ELEMENT, PREFIX_COLON
436: + REQUESTPARAMETERS_ELEMENT);
437:
438: // Generate SAX events for the session attributes
439: this .contentHandler.startElement(PROFILER_NS,
440: SESSIONATTRIBUTES_ELEMENT, PREFIX_COLON
441: + SESSIONATTRIBUTES_ELEMENT,
442: XMLUtils.EMPTY_ATTRIBUTES);
443:
444: Map sessionAttributes = environmentInfo
445: .getSessionAttributes();
446: Set sessionAttrEntries = sessionAttributes.entrySet();
447: Iterator sessionAttrEntriesIt = sessionAttrEntries
448: .iterator();
449:
450: while (sessionAttrEntriesIt.hasNext()) {
451: AttributesImpl atts = new AttributesImpl();
452: Map.Entry entry = (Map.Entry) sessionAttrEntriesIt
453: .next();
454:
455: atts.addAttribute("", "name", "name", "CDATA",
456: (String) entry.getKey());
457: atts.addAttribute("", "value", "value", "CDATA",
458: (String) entry.getValue());
459: this .contentHandler.startElement(PROFILER_NS,
460: SESSIONATTRIBUTE_ELEMENT, PREFIX_COLON
461: + SESSIONATTRIBUTE_ELEMENT, atts);
462: this .contentHandler.endElement(PROFILER_NS,
463: SESSIONATTRIBUTE_ELEMENT, PREFIX_COLON
464: + SESSIONATTRIBUTE_ELEMENT);
465: }
466: this .contentHandler.endElement(PROFILER_NS,
467: SESSIONATTRIBUTES_ELEMENT, PREFIX_COLON
468: + SESSIONATTRIBUTES_ELEMENT);
469:
470: // And the rest
471: this .contentHandler.startElement(PROFILER_NS, "uri",
472: PREFIX_COLON + "uri", XMLUtils.EMPTY_ATTRIBUTES);
473: this .contentHandler.characters(environmentInfo.getURI()
474: .toCharArray(), 0, environmentInfo.getURI()
475: .length());
476: this .contentHandler.endElement(PROFILER_NS, "uri",
477: PREFIX_COLON + "uri");
478: }
479:
480: this .contentHandler.endElement(PROFILER_NS,
481: ENVIROMENTINFO_ELEMENT, PREFIX_COLON
482: + ENVIROMENTINFO_ELEMENT);
483: }
484:
485: public void generateSAXFragment(Object fragment, boolean embed)
486: throws SAXException {
487:
488: if (fragment != null) {
489: XMLDeserializer deserializer = null;
490:
491: try {
492: deserializer = (XMLDeserializer) this .manager
493: .lookup(XMLDeserializer.ROLE);
494: if (embed)
495: deserializer.setConsumer(new IncludeXMLConsumer(
496: this .xmlConsumer));
497: else
498: deserializer.setConsumer(this .xmlConsumer);
499: deserializer.deserialize(fragment);
500: } catch (ServiceException ce) {
501: getLogger().debug(
502: "Could not retrieve XMLDeserializer component",
503: ce);
504: throw new SAXException(
505: "Could not retrieve XMLDeserializer component",
506: ce);
507: } catch (Exception e) {
508: getLogger()
509: .debug("Could not serialize SAX fragment", e);
510: throw new SAXException(
511: "Could not serialize SAX fragment", e);
512: } finally {
513: if (deserializer != null) {
514: this.manager.release(deserializer);
515: }
516: }
517: }
518: }
519: }
|