| /* |
| * Copyright 1999-2004 The Apache Software Foundation. |
| * |
| * Licensed 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.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 CVS $Id: ProfilerGenerator.java,v 1.6 2004/03/05 13:02:20 bdelacretaz Exp $ |
| */ |
| 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", new AttributesImpl()); |
| 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, |
| new AttributesImpl()); |
| 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, |
| new AttributesImpl()); |
| |
| if (environmentInfo!=null) { |
| // Generate SAX events for the request parameters |
| this.contentHandler.startElement(PROFILER_NS, |
| REQUESTPARAMETERS_ELEMENT, |
| PREFIX_COLON + REQUESTPARAMETERS_ELEMENT, |
| new AttributesImpl()); |
| |
| 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, |
| new AttributesImpl()); |
| |
| 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", |
| new AttributesImpl()); |
| 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); |
| } |
| } |
| } |
| } |
| } |
| |