blob: f9ba289881cce4574cfa1b2ca6f25ccc90e54d22 [file] [log] [blame]
/*
* 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.uima.util.impl;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import java.util.Stack;
import org.apache.uima.UIMAFramework;
import org.apache.uima.UIMA_IllegalStateException;
import org.apache.uima.util.ProcessTrace;
import org.apache.uima.util.ProcessTraceEvent;
import org.apache.uima.util.UimaTimer;
/**
* Reference implementation of {@link ProcessTrace}.
*
*
*/
public class ProcessTrace_impl implements ProcessTrace {
private static final long serialVersionUID = 7566277176545062757L;
/**
* List of closed events.
*/
private List mEventList = new ArrayList();
/**
* Stack of open events.
*/
private Stack mOpenEvents = new Stack();
/**
* Timer class used to get timing information.
*/
private UimaTimer mTimer;
/**
* Indicates whether process trace is enabled.
*/
private boolean mEnabled;
/**
* Create a ProcessTrace_impl using the framework's default timer.
*/
public ProcessTrace_impl() {
this(UIMAFramework.getDefaultPerformanceTuningProperties());
}
/**
* Create a ProcessTrace_impl using the framework's default timer.
*
* @param aPerformanceTuningSettings
* performance tuning settings. One of the settings allows the ProcessTrace to be
* disabled.
*/
public ProcessTrace_impl(Properties aPerformanceTuningSettings) {
if (aPerformanceTuningSettings == null) {
aPerformanceTuningSettings = UIMAFramework.getDefaultPerformanceTuningProperties();
}
mEnabled = "true".equalsIgnoreCase(aPerformanceTuningSettings
.getProperty(UIMAFramework.PROCESS_TRACE_ENABLED));
if (mEnabled) {
mTimer = UIMAFramework.newTimer();
}
}
/**
* Create a ProcessTrace_impl with a custom timer.
*
* @param aTimer
* the timer to use for collecting performance stats
*/
public ProcessTrace_impl(UimaTimer aTimer) {
this(aTimer, UIMAFramework.getDefaultPerformanceTuningProperties());
}
/**
* Create a ProcessTrace_impl with a custom timer.
*
* @param aTimer
* the timer to use for collecting performance stats
* @param aPerformanceTuningSettings
* performance tuning settings. One of the settings allows the ProcessTrace to be
* disabled.
*/
public ProcessTrace_impl(UimaTimer aTimer, Properties aPerformanceTuningSettings) {
mTimer = aTimer;
if (aPerformanceTuningSettings == null) {
aPerformanceTuningSettings = UIMAFramework.getDefaultPerformanceTuningProperties();
}
mEnabled = "true".equalsIgnoreCase(aPerformanceTuningSettings
.getProperty(UIMAFramework.PROCESS_TRACE_ENABLED));
}
/**
* @see org.apache.uima.util.ProcessTrace#startEvent(java.lang.String, java.lang.String,
* java.lang.String)
*/
public void startEvent(String aComponentName, String aEventType, String aDescription) {
if (mEnabled) {
// DEBUG System.out.println("startEvent(" + aComponentName + "," + aEventType + ")");
ProcessTraceEvent_impl evt = new ProcessTraceEvent_impl(aComponentName, aEventType,
aDescription);
evt.setStartTime(mTimer.getTimeInMillis());
mOpenEvents.push(evt);
}
}
/**
* @see org.apache.uima.util.ProcessTrace#endEvent(java.lang.String, java.lang.String,
* java.lang.String)
*/
public void endEvent(String aComponentName, String aEventType, String aResultMessage) {
if (mEnabled) {
// DEBUG System.out.println("endEvent(" + aComponentName + "," + aEventType + ")");
// look for matching event on mOpenEvents stack. If found, close it and
// all its open sub-events. If not found, throw exception.
ArrayList eventsToClose = new ArrayList();
boolean foundEvent = false;
while (!mOpenEvents.isEmpty()) {
ProcessTraceEvent_impl evt = (ProcessTraceEvent_impl) mOpenEvents.pop();
eventsToClose.add(evt);
if (aComponentName.equals(evt.getComponentName()) && aEventType.equals(evt.getType())) {
foundEvent = true;
break;
}
}
if (foundEvent) // found matching event
{
// close all open sub-events
long currentTime = mTimer.getTimeInMillis();
for (int i = 0; i < eventsToClose.size(); i++) {
ProcessTraceEvent_impl subEvt = (ProcessTraceEvent_impl) eventsToClose.get(i);
subEvt.setResultMessage(aResultMessage);
subEvt.setDuration((int) (currentTime - subEvt.getStartTime()));
ProcessTraceEvent_impl owner = null;
if (i < eventsToClose.size() - 1) {
owner = (ProcessTraceEvent_impl) eventsToClose.get(i + 1);
} else if (!mOpenEvents.isEmpty()) {
owner = (ProcessTraceEvent_impl) mOpenEvents.peek();
}
if (owner != null) {
owner.addSubEvent(subEvt);
} else // top-level event has closed, add to the Event List
{
mEventList.add(subEvt);
}
}
} else // no matching event
{
// restore stack
for (int i = 0; i < eventsToClose.size(); i++) {
mOpenEvents.push(eventsToClose.get(i));
}
// throw exception
throw new UIMA_IllegalStateException(UIMA_IllegalStateException.REQUIRED_METHOD_CALL,
new Object[] { "startEvent", "endEvent" });
}
}
}
/**
* @see org.apache.uima.util.ProcessTrace#addEvent(String, String, String, int, String)
*/
public void addEvent(String aComponentName, String aType, String aDescription, int aDuration,
String aResultMsg) {
if (mEnabled) {
// create event
ProcessTraceEvent_impl evt = new ProcessTraceEvent_impl(aComponentName, aType, aDescription);
evt.setDuration(aDuration);
evt.setResultMessage(aResultMsg);
// add
addEvent(evt);
}
}
/**
* @see org.apache.uima.util.ProcessTrace#addEvent(org.apache.uima.util.ProcessTraceEvent)
*/
public void addEvent(ProcessTraceEvent aEvent) {
if (mEnabled) {
if (!mOpenEvents.isEmpty()) {
ProcessTraceEvent_impl owner = (ProcessTraceEvent_impl) mOpenEvents.peek();
owner.addSubEvent(aEvent);
} else // top-level event has closed, add to the Event List
{
mEventList.add(aEvent);
}
}
}
/**
* @see org.apache.uima.util.ProcessTrace#addAll(java.util.List)
*/
public void addAll(List aEventList) {
Iterator it = aEventList.iterator();
while (it.hasNext()) {
ProcessTraceEvent evt = (ProcessTraceEvent) it.next();
addEvent(evt);
}
}
/**
* @see org.apache.uima.util.ProcessTrace#getEvents()
*/
public List getEvents() {
return mEventList;
}
/**
* @see org.apache.uima.util.ProcessTrace#getEventsByComponentName(String)
*/
public List getEventsByComponentName(String aComponentName, boolean aRecurseAfterMatch) {
List result = new ArrayList();
Iterator it = getEvents().iterator();
while (it.hasNext()) {
ProcessTraceEvent event = (ProcessTraceEvent) it.next();
getEventsByComponentName(event, aComponentName, aRecurseAfterMatch, result);
}
return result;
}
/**
* @see org.apache.uima.util.ProcessTrace#getEventsByType(String)
*/
public List getEventsByType(String aType, boolean aRecurseAfterMatch) {
List result = new ArrayList();
Iterator it = getEvents().iterator();
while (it.hasNext()) {
ProcessTraceEvent event = (ProcessTraceEvent) it.next();
getEventsByType(event, aType, aRecurseAfterMatch, result);
}
return result;
}
/**
* @see org.apache.uima.util.ProcessTrace#getEvent(String, String)
*/
public ProcessTraceEvent getEvent(String aComponentName, String aType) {
List events = getEvents();
return getEvent(events, aComponentName, aType);
}
protected ProcessTraceEvent getEvent(List aEvents, String aComponentName, String aType) {
Iterator it = aEvents.iterator();
while (it.hasNext()) {
ProcessTraceEvent event = (ProcessTraceEvent) it.next();
if (aComponentName.equals(event.getComponentName()) && aType.equals(event.getType())) {
return event;
} else {
ProcessTraceEvent matchingSubEvt = getEvent(event.getSubEvents(), aComponentName, aType);
if (matchingSubEvt != null) {
return matchingSubEvt;
}
}
}
return null;
}
/**
* @see org.apache.uima.util.ProcessTrace#clear()
*/
public void clear() {
mEventList.clear();
}
/**
* @see org.apache.uima.util.ProcessTrace#aggregate(org.apache.uima.util.ProcessTrace)
*/
public void aggregate(ProcessTrace aProcessTrace) {
if (mEnabled) {
List newEventList = aProcessTrace.getEvents();
// iterate over new events
Iterator newEventIter = newEventList.iterator();
while (newEventIter.hasNext()) {
ProcessTraceEvent_impl newEvt = (ProcessTraceEvent_impl) newEventIter.next();
// find corresponding event in thisEventList
ProcessTraceEvent_impl correspondingEvt = findCorrespondingEvent(mEventList, newEvt);
if (correspondingEvt != null) {
aggregateEvent(correspondingEvt, newEvt);
} else {
// no corresponding event - add newEvt to list of events to be added
mEventList.add(newEvt);
}
}
}
}
/**
* @see org.apache.uima.util.ProcessTrace#toString()
*/
public String toString() {
// count total time so we can do percentages
int totalTime = 0;
Iterator it = mEventList.iterator();
while (it.hasNext()) {
ProcessTraceEvent event = (ProcessTraceEvent) it.next();
totalTime += event.getDuration();
}
// go back through and generate string
StringBuffer buf = new StringBuffer();
it = mEventList.iterator();
while (it.hasNext()) {
ProcessTraceEvent event = (ProcessTraceEvent) it.next();
event.toString(buf, 0, totalTime);
}
return buf.toString();
}
/**
* Utility method used by getEventsByComponentName(String)
*/
protected void getEventsByComponentName(ProcessTraceEvent aEvent, String aComponentName,
boolean aRecurseAfterMatch, List aResultList) {
if (aComponentName.equals(aEvent.getComponentName())) {
aResultList.add(aEvent);
if (!aRecurseAfterMatch) {
return;
}
}
// recurse into child events
Iterator it = aEvent.getSubEvents().iterator();
while (it.hasNext()) {
ProcessTraceEvent event = (ProcessTraceEvent) it.next();
getEventsByComponentName(event, aComponentName, aRecurseAfterMatch, aResultList);
}
}
/**
* Utility method used by getEventsByType(String)
*/
protected void getEventsByType(ProcessTraceEvent aEvent, String aType,
boolean aRecurseAfterMatch, List aResultList) {
if (aType.equals(aEvent.getType())) {
aResultList.add(aEvent);
if (!aRecurseAfterMatch) {
return;
}
}
// recurse into child events
Iterator it = aEvent.getSubEvents().iterator();
while (it.hasNext()) {
ProcessTraceEvent event = (ProcessTraceEvent) it.next();
getEventsByType(event, aType, aRecurseAfterMatch, aResultList);
}
}
/**
* Utility method used by aggregate(ProcessTrace)
*/
protected ProcessTraceEvent_impl findCorrespondingEvent(List aEventList,
ProcessTraceEvent_impl aEvent) {
Iterator it = aEventList.iterator();
while (it.hasNext()) {
ProcessTraceEvent_impl evt = (ProcessTraceEvent_impl) it.next();
if (evt.getComponentName().equals(aEvent.getComponentName())
&& evt.getType().equals(aEvent.getType())) {
return evt;
}
}
return null;
}
/**
* Utility method used by aggregate(ProcessTrace)
*/
protected void aggregateEvent(ProcessTraceEvent_impl aDest, ProcessTraceEvent_impl aSrc) {
// sum durations
aDest.addToDuration(aSrc.getDuration());
// update result msg
aDest.setResultMessage(aSrc.getResultMessage());
// aggregate sub-events
List destEventList = aDest.getSubEvents();
List srcEventList = aSrc.getSubEvents();
List eventsToAdd = null; // lazy init
// iterate over src events
Iterator srcEventIter = srcEventList.iterator();
while (srcEventIter.hasNext()) {
ProcessTraceEvent_impl srcEvt = (ProcessTraceEvent_impl) srcEventIter.next();
// find corresponding event in destEventList
ProcessTraceEvent_impl correspondingEvt = findCorrespondingEvent(destEventList, srcEvt);
if (correspondingEvt != null) {
aggregateEvent(correspondingEvt, srcEvt);
} else {
// no corresponding event - add srcEvt to list of events to be added
if (eventsToAdd == null) {
eventsToAdd = new ArrayList();
}
eventsToAdd.add(srcEvt);
}
}
// add all from events eventsToAdd
if (eventsToAdd != null) {
Iterator it = eventsToAdd.iterator();
while (it.hasNext()) {
aDest.addSubEvent((ProcessTraceEvent) it.next());
}
}
}
}