/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.cocoon.generation; import org.apache.avalon.framework.parameters.Parameters; import org.apache.avalon.framework.service.ServiceException; import org.apache.avalon.framework.service.ServiceManager; import org.apache.cocoon.ProcessingException; import org.apache.cocoon.components.profiler.EnvironmentInfo; import org.apache.cocoon.components.profiler.Profiler; import org.apache.cocoon.components.profiler.ProfilerResult; import org.apache.cocoon.components.sax.XMLDeserializer; import org.apache.cocoon.environment.ObjectModelHelper; import org.apache.cocoon.environment.Request; import org.apache.cocoon.environment.SourceResolver; import org.apache.cocoon.xml.IncludeXMLConsumer; import org.apache.cocoon.xml.XMLUtils; import org.xml.sax.SAXException; import org.xml.sax.helpers.AttributesImpl; import java.io.IOException; import java.text.DateFormat; import java.util.Collection; import java.util.Date; import java.util.Iterator; import java.util.Map; import java.util.Set; /** * Generates an XML representation of the current status of Profiler. * * @author <a href="mailto:vgritsenko@apache.org">Vadim Gritsenko</a> * @author <a href="mailto:bruno@outerthought.org">Bruno Dumon</a> * @author <a href="mailto:stephan@apache.org">Stephan Michels</a> * @version $Id$ */ public class ProfilerGenerator extends ServiceableGenerator { /** * The XML PROFILER_NS for the output document. */ private static final String PROFILER_NS = "http://apache.org/cocoon/profiler/1.0"; private static final String PROFILERINFO_ELEMENT = "profilerinfo"; private static final String RESULTS_ELEMENT = "pipeline"; private static final String RESULT_ELEMENT = "result"; private static final String AVERAGERESULT_ELEMENT = "average"; private static final String ENVIROMENTINFO_ELEMENT = "environmentinfo"; private static final String REQUESTPARAMETERS_ELEMENT = "request-parameters"; private static final String REQUESTPARAMETER_ELEMENT = "parameter"; private static final String SESSIONATTRIBUTES_ELEMENT = "session-attributes"; private static final String SESSIONATTRIBUTE_ELEMENT = "attribute"; private static final String COMPONENT_ELEMENT = "component"; private static final String FRAGMENT_ELEMENT = "fragment"; private static final String PREFIX = "profiler"; private static final String PREFIX_COLON = "profiler:"; private Profiler profiler; // the key identifying the ProfilerResult private Long key = null; // Index of the result of latest results private int resultIndex = -1; // Index of the componen of the latest results private int componentIndex = -1; // Indicates if the fragment only, and not the profiler metadata around it, should be generated private boolean fragmentOnly; /** * Serviceable */ public void service(ServiceManager manager) throws ServiceException { super.service(manager); this.profiler = (Profiler) super.manager.lookup(Profiler.ROLE); } /** * Setup of the profiler generator. */ public void setup(SourceResolver resolver, Map objectModel, String soure, Parameters parameters) throws ProcessingException, SAXException, IOException { super.setup(resolver, objectModel, source, parameters); Request request = ObjectModelHelper.getRequest(objectModel); if (request.getParameter("key")!=null) { this.key = new Long(Long.parseLong(request.getParameter("key"))); } else { this.key = null; } if ((request.getParameter("result")!=null) && (this.key!=null)) { this.resultIndex = Integer.parseInt(request.getParameter("result")); } else { this.resultIndex = -1; } if ((request.getParameter("component")!=null) && (this.resultIndex!=-1)) { this.componentIndex = Integer.parseInt(request.getParameter("component")); } else { this.componentIndex = -1; } if (request.getParameter("fragmentonly") != null && request.getParameter("fragmentonly").equals("true")) { fragmentOnly = true; } else { fragmentOnly = false; } } /** * Disposable */ public void dispose() { if (this.profiler!=null) { super.manager.release(this.profiler); this.profiler = null; } super.dispose(); } /** * Generate the status information in XML format. * @throws SAXException * when there is a problem creating the output SAX events. */ public void generate() throws SAXException { // check if only the stored XML data is requested if (fragmentOnly && key != null && resultIndex != -1 && componentIndex != -1) { // find the fragment Object fragment = null; try { ProfilerResult result = profiler.getResult(key); fragment = result.getSAXFragments()[resultIndex][componentIndex]; } catch (Exception e) { // fragment will be null } if (fragment != null) { generateSAXFragment(fragment, false); } else { this.contentHandler.startDocument(); this.contentHandler.startPrefixMapping(PREFIX, PROFILER_NS); this.contentHandler.startElement(PROFILER_NS, "fragment-error", PREFIX_COLON + "fragment-error", XMLUtils.EMPTY_ATTRIBUTES); char[] message = "Fragment is not available.".toCharArray(); this.contentHandler.characters(message, 0, message.length); this.contentHandler.endElement(PROFILER_NS, "fragment-error", PREFIX_COLON + "fragment-error"); this.contentHandler.endPrefixMapping(PREFIX); this.contentHandler.endDocument(); } } else { // Start the document and set the PROFILER_NS. this.contentHandler.startDocument(); this.contentHandler.startPrefixMapping(PREFIX, PROFILER_NS); generateProfilerInfo(); // End the document. this.contentHandler.endPrefixMapping(PREFIX); this.contentHandler.endDocument(); } } /** * Generate the main status document. */ private void generateProfilerInfo() throws SAXException { // Root element. // The current date and processingTime. String dateTime = DateFormat.getDateTimeInstance().format(new Date()); AttributesImpl atts = new AttributesImpl(); atts.addAttribute("", "date", "date", "CDATA", dateTime); this.contentHandler.startElement(PROFILER_NS, PROFILERINFO_ELEMENT, PREFIX_COLON + PROFILERINFO_ELEMENT, atts); Collection resultsKeys = profiler.getResultKeys(); for (Iterator i = resultsKeys.iterator(); i.hasNext(); ) { Long key = (Long) i.next(); if ((this.key==null) || (this.key.equals(key))) { generateResults(key, profiler.getResult(key)); } } // End root element. this.contentHandler.endElement(PROFILER_NS, PROFILERINFO_ELEMENT, PREFIX_COLON + PROFILERINFO_ELEMENT); } /** * * * @param key * @param result */ private void generateResults(Long key, ProfilerResult result) throws SAXException { AttributesImpl atts = new AttributesImpl(); int count = result.getCount(); String[] roles = result.getRoles(); // Roles of the components String[] sources = result.getSources(); // Source of the components EnvironmentInfo[] environmentInfos = result.getLatestEnvironmentInfos(); long[] totalTime = result.getTotalTime(); // Total time of the requests long[][] setupTimes = result.getSetupTimes(); // Setup time of each component long[][] processingTimes = result.getProcessingTimes(); // Processing time of each component Object[][] fragments = result.getSAXFragments(); // SAX Fragments of each component // Total time of all requests long totalTimeSum = 0; for (int i = 0; i<count; i++) { totalTimeSum += totalTime[i]; } atts.addAttribute("", "uri", "uri", "CDATA", result.getURI()); atts.addAttribute("", "count", "count", "CDATA", Integer.toString(result.getCount())); atts.addAttribute("", "processingTime", "processingTime", "CDATA", Long.toString(totalTimeSum)); atts.addAttribute("", "key", "key", "CDATA", key.toString()); this.contentHandler.startElement(PROFILER_NS, RESULTS_ELEMENT, PREFIX_COLON + RESULTS_ELEMENT, atts); atts.clear(); // Generate average result if ((count>0) && (this.resultIndex==-1)) { atts.addAttribute("", "time", "time", "CDATA", Long.toString(totalTimeSum/count)); this.contentHandler.startElement(PROFILER_NS, AVERAGERESULT_ELEMENT, PREFIX_COLON + AVERAGERESULT_ELEMENT, atts); atts.clear(); // Total time of each component for all requests long[] totalTimeOfComponents = new long[roles.length]; for (int i = 0; i<roles.length; i++) { totalTimeOfComponents[i] = 0; for (int j = 0; j<count; j++) { totalTimeOfComponents[i] += setupTimes[j][i]+ processingTimes[j][i]; } } for (int i = 0; i<roles.length; i++) { atts.addAttribute("", "offset", "offset", "CDATA", String.valueOf(i)); if (roles[i]!=null) { atts.addAttribute("", "role", "role", "CDATA", roles[i]); } if (sources[i]!=null) { atts.addAttribute("", "source", "source", "CDATA", sources[i]); } atts.addAttribute("", "time", "time", "CDATA", Long.toString(totalTimeOfComponents[i]/ count)); this.contentHandler.startElement(PROFILER_NS, COMPONENT_ELEMENT, PREFIX_COLON + COMPONENT_ELEMENT, atts); atts.clear(); this.contentHandler.endElement(PROFILER_NS, COMPONENT_ELEMENT, PREFIX_COLON + COMPONENT_ELEMENT); } this.contentHandler.endElement(PROFILER_NS, AVERAGERESULT_ELEMENT, PREFIX_COLON + AVERAGERESULT_ELEMENT); } for (int j = 0; j<count; j++) { if ((this.resultIndex==-1) || (this.resultIndex==j)) { generateResult(j, roles, sources, environmentInfos[j], totalTime[j], setupTimes[j], processingTimes[j], fragments[j]); } } this.contentHandler.endElement(PROFILER_NS, RESULTS_ELEMENT, PREFIX_COLON + RESULTS_ELEMENT); } private void generateResult(int resultIndex, String[] roles, String[] sources, EnvironmentInfo environmentInfo, long totalTime, long[] setupTimes, long[] processingTimes, Object[] fragments) throws SAXException { AttributesImpl atts = new AttributesImpl(); atts.addAttribute("", "time", "time", "CDATA", Long.toString(totalTime)); atts.addAttribute("", "index", "index", "CDATA", String.valueOf(resultIndex)); this.contentHandler.startElement(PROFILER_NS, RESULT_ELEMENT, PREFIX_COLON + RESULT_ELEMENT, atts); atts.clear(); if (this.resultIndex!=-1) { generateEnvironmentInfo(environmentInfo); } for (int i = 0; i<roles.length; i++) { generateComponent(i, roles[i], sources[i], setupTimes[i], processingTimes[i], fragments[i]); } this.contentHandler.endElement(PROFILER_NS, RESULT_ELEMENT, PREFIX_COLON + RESULT_ELEMENT); } private void generateComponent(int componentIndex, String role, String source, long setupTime, long processingTime, Object fragment) throws SAXException { AttributesImpl atts = new AttributesImpl(); atts.addAttribute("", "index", "index", "CDATA", String.valueOf(componentIndex)); if (role!=null) { atts.addAttribute("", "role", "role", "CDATA", role); } if (source!=null) { atts.addAttribute("", "source", "source", "CDATA", source); } atts.addAttribute("", "setup", "setup", "CDATA", Long.toString(setupTime)); atts.addAttribute("", "processing", "processing", "CDATA", Long.toString(processingTime)); atts.addAttribute("", "time", "time", "CDATA", Long.toString(setupTime+processingTime)); this.contentHandler.startElement(PROFILER_NS, COMPONENT_ELEMENT, PREFIX_COLON + COMPONENT_ELEMENT, atts); atts.clear(); if (this.componentIndex==componentIndex) { this.contentHandler.startElement(PROFILER_NS, FRAGMENT_ELEMENT, PREFIX_COLON + FRAGMENT_ELEMENT, XMLUtils.EMPTY_ATTRIBUTES); generateSAXFragment(fragment, true); this.contentHandler.endElement(PROFILER_NS, FRAGMENT_ELEMENT, PREFIX_COLON + FRAGMENT_ELEMENT); } this.contentHandler.endElement(PROFILER_NS, COMPONENT_ELEMENT, PREFIX_COLON + COMPONENT_ELEMENT); } private void generateEnvironmentInfo(EnvironmentInfo environmentInfo) throws SAXException { this.contentHandler.startElement(PROFILER_NS, ENVIROMENTINFO_ELEMENT, PREFIX_COLON + ENVIROMENTINFO_ELEMENT, XMLUtils.EMPTY_ATTRIBUTES); if (environmentInfo!=null) { // Generate SAX events for the request parameters this.contentHandler.startElement(PROFILER_NS, REQUESTPARAMETERS_ELEMENT, PREFIX_COLON + REQUESTPARAMETERS_ELEMENT, XMLUtils.EMPTY_ATTRIBUTES); Map requestParameters = environmentInfo.getRequestParameters(); Set requestParamEntries = requestParameters.entrySet(); Iterator requestParamEntriesIt = requestParamEntries.iterator(); while (requestParamEntriesIt.hasNext()) { AttributesImpl atts = new AttributesImpl(); Map.Entry entry = (Map.Entry) requestParamEntriesIt.next(); atts.addAttribute("", "name", "name", "CDATA", (String) entry.getKey()); atts.addAttribute("", "value", "value", "CDATA", (String) entry.getValue()); this.contentHandler.startElement(PROFILER_NS, REQUESTPARAMETER_ELEMENT, PREFIX_COLON + REQUESTPARAMETER_ELEMENT, atts); this.contentHandler.endElement(PROFILER_NS, REQUESTPARAMETER_ELEMENT, PREFIX_COLON + REQUESTPARAMETER_ELEMENT); } this.contentHandler.endElement(PROFILER_NS, REQUESTPARAMETERS_ELEMENT, PREFIX_COLON + REQUESTPARAMETERS_ELEMENT); // Generate SAX events for the session attributes this.contentHandler.startElement(PROFILER_NS, SESSIONATTRIBUTES_ELEMENT, PREFIX_COLON + SESSIONATTRIBUTES_ELEMENT, XMLUtils.EMPTY_ATTRIBUTES); Map sessionAttributes = environmentInfo.getSessionAttributes(); Set sessionAttrEntries = sessionAttributes.entrySet(); Iterator sessionAttrEntriesIt = sessionAttrEntries.iterator(); while (sessionAttrEntriesIt.hasNext()) { AttributesImpl atts = new AttributesImpl(); Map.Entry entry = (Map.Entry) sessionAttrEntriesIt.next(); atts.addAttribute("", "name", "name", "CDATA", (String) entry.getKey()); atts.addAttribute("", "value", "value", "CDATA", (String) entry.getValue()); this.contentHandler.startElement(PROFILER_NS, SESSIONATTRIBUTE_ELEMENT, PREFIX_COLON + SESSIONATTRIBUTE_ELEMENT, atts); this.contentHandler.endElement(PROFILER_NS, SESSIONATTRIBUTE_ELEMENT, PREFIX_COLON + SESSIONATTRIBUTE_ELEMENT); } this.contentHandler.endElement(PROFILER_NS, SESSIONATTRIBUTES_ELEMENT, PREFIX_COLON + SESSIONATTRIBUTES_ELEMENT); // And the rest this.contentHandler.startElement(PROFILER_NS, "uri", PREFIX_COLON + "uri", XMLUtils.EMPTY_ATTRIBUTES); this.contentHandler.characters(environmentInfo.getURI().toCharArray(), 0, environmentInfo.getURI().length()); this.contentHandler.endElement(PROFILER_NS, "uri", PREFIX_COLON + "uri"); } this.contentHandler.endElement(PROFILER_NS, ENVIROMENTINFO_ELEMENT, PREFIX_COLON + ENVIROMENTINFO_ELEMENT); } public void generateSAXFragment(Object fragment, boolean embed) throws SAXException { if (fragment!=null) { XMLDeserializer deserializer = null; try { deserializer = (XMLDeserializer) this.manager.lookup(XMLDeserializer.ROLE); if (embed) deserializer.setConsumer(new IncludeXMLConsumer(this.xmlConsumer)); else deserializer.setConsumer(this.xmlConsumer); deserializer.deserialize(fragment); } catch (ServiceException ce) { getLogger().debug("Could not retrieve XMLDeserializer component", ce); throw new SAXException("Could not retrieve XMLDeserializer component", ce); } catch (Exception e) { getLogger().debug("Could not serialize SAX fragment", e); throw new SAXException("Could not serialize SAX fragment", e); } finally { if (deserializer!=null) { this.manager.release(deserializer); } } } } }