org.yawlfoundation.yawl.resourcing.datastore.eventlog.LogMiner.java Source code

Java tutorial

Introduction

Here is the source code for org.yawlfoundation.yawl.resourcing.datastore.eventlog.LogMiner.java

Source

/*
 * Copyright (c) 2004-2012 The YAWL Foundation. All rights reserved.
 * The YAWL Foundation is a collaboration of individuals and
 * organisations who are committed to improving workflow technology.
 *
 * This file is part of YAWL. YAWL is free software: you can
 * redistribute it and/or modify it under the terms of the GNU Lesser
 * General Public License as published by the Free Software Foundation.
 *
 * YAWL is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
 * Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with YAWL. If not, see <http://www.gnu.org/licenses/>.
 */

package org.yawlfoundation.yawl.resourcing.datastore.eventlog;

import org.jdom2.Element;
import org.yawlfoundation.yawl.engine.YSpecificationID;
import org.yawlfoundation.yawl.resourcing.ResourceManager;
import org.yawlfoundation.yawl.resourcing.datastore.persistence.Persister;
import org.yawlfoundation.yawl.resourcing.resource.Participant;
import org.yawlfoundation.yawl.util.JDOMUtil;
import org.yawlfoundation.yawl.util.StringUtil;
import org.yawlfoundation.yawl.util.XNode;

import java.util.*;

/**
 * An API to retrieve data from the resource service's event logs
 * and pass it back as XML.
 *
 * Create Date: 16/12/2008
 *
 *  @author Michael Adams
 *  @version 2.0
 */

public class LogMiner {

    private static LogMiner _me;
    private Persister _reader;

    // some error messages
    private static final String _exErrStr = "<failure>Unable to retrieve data.</failure>";
    private static final String _pmErrStr = "<failure>Error connecting to database.</failure>";
    private static final String _noRowsStr = "<failure>No rows returned.</failure>";
    private static final String _badKeyStr = "<failure>Invalid specification key.</failure>";

    private static final String _baseQuery = "FROM ResourceEvent AS re";

    // CONSTRUCTOR - called from getInstance() //

    private LogMiner() {
        _reader = Persister.getInstance();
    }

    public static LogMiner getInstance() {
        if (_me == null)
            _me = new LogMiner();
        return _me;
    }

    /*****************************************************************************/

    /**
     * @param specID the specification id to get the case eventids for
     * @return the set of all case ids for the specID passed
     */
    public String getWorkItemDurationsForParticipant(YSpecificationID specID, String taskName,
            String participantID) {
        String result;
        List rows;
        if (_reader != null) {
            long specKey = getSpecificationKey(specID);
            StringBuilder template = new StringBuilder(_baseQuery);
            template.append(" WHERE re._taskID='%s'").append(" AND re._specKey=%d")
                    .append(" AND re._resourceID='%s'").append(" ORDER BY re._itemID, re._timeStamp");

            String query = String.format(template.toString(), taskName, specKey, participantID);

            rows = execQuery(query);
            if ((rows != null) && (!rows.isEmpty())) {
                StringBuilder xml = new StringBuilder();
                String currentItemID = "";
                xml.append(String.format("<workitems specID=\"%s\" taskName=\"%s\" resourceID=\"%s\">",
                        specID.toString(), taskName, participantID));
                for (Object o : rows) {
                    ResourceEvent event = (ResourceEvent) o;
                    if (!event.get_itemID().equals(currentItemID)) {
                        if (!"".equals(currentItemID)) {
                            xml.append("</workitem>");
                        }
                        currentItemID = event.get_itemID();
                        xml.append(String.format("<workitem ID=\"%s\">", currentItemID));
                    }
                    xml.append("<event>");
                    xml.append(StringUtil.wrap(event.get_event(), "type"));
                    xml.append(StringUtil.wrap(String.valueOf(event.get_timeStamp()), "time"));
                    xml.append("</event>");
                }
                xml.append("</workitem></workitems>");
                result = xml.toString();
            } else
                result = _noRowsStr;
        } else
            result = _pmErrStr;

        return result;
    }

    /*****************************************************************************/

    public String getAllResourceEvents() {
        return eventListToXML(getAllEvents());
    }

    public String getCaseEvents(String caseID) {
        List events = getCaseEventsList(caseID);
        return (!events.isEmpty()) ? eventListToXML(events) : _noRowsStr;
    }

    public String getCaseEvents(String caseID, long from, long to) {
        if ((from < 0) && (to < 0))
            return getCaseEvents(caseID);
        List events = getCaseEventsList(caseID, from, to);
        return (!events.isEmpty()) ? eventListToXML(events) : _noRowsStr;
    }

    public String getCaseEvent(String caseID, boolean launch) {
        EventLogger.event eventType = launch ? EventLogger.event.launch_case : EventLogger.event.cancel_case;
        ResourceEvent event = getCaseEvent(caseID, eventType);
        return (event != null) ? event.toXML() : _noRowsStr;
    }

    public String getTaskEvents(long specKey, String taskName, long from, long to) {
        if ((from < 0) && (to < 0))
            return getTaskEvents(specKey, taskName);
        List events = getTaskEventsList(specKey, taskName, from, to);
        return (!events.isEmpty()) ? eventListToXML(events) : _noRowsStr;
    }

    public String getTaskEvents(long specKey, String taskName) {
        List events = getTaskEventsList(specKey, taskName);
        return (!events.isEmpty()) ? eventListToXML(events) : _noRowsStr;
    }

    public String getTaskEvents(YSpecificationID specID, String taskName, long from, long to) {
        return getTaskEvents(getSpecificationKey(specID), taskName, from, to);
    }

    public String getTaskEvents(YSpecificationID specID, String taskName) {
        return getTaskEvents(getSpecificationKey(specID), taskName);
    }

    public String getWorkItemEvents(String itemID, boolean fullName) {
        List events = getWorkItemEventsList(itemID);
        if (events != null) {
            if (containsStartEvent(events)) {
                String parentID = deriveParentID(itemID);
                List parentEvents = getWorkItemEventsList(parentID);
                if (parentEvents != null) {
                    events.addAll(parentEvents);
                }
            }
            if (fullName)
                events = replaceParticipantIDsWithNames(events);
        }
        return (events != null) ? eventListToXML(events) : _noRowsStr;
    }

    public String getWorkItemEvents(String itemID, boolean fullName, long from, long to) {
        if ((from < 0) && (to < 0))
            return getWorkItemEvents(itemID, fullName);
        List events = getWorkItemEventsList(itemID, from, to);
        if (events != null) {
            if (containsStartEvent(events)) {
                String parentID = deriveParentID(itemID);
                List parentEvents = getWorkItemEventsList(parentID, from, to);
                if (parentEvents != null) {
                    events.addAll(parentEvents);
                }
            }
            if (fullName)
                events = replaceParticipantIDsWithNames(events);
        }
        return (events != null) ? eventListToXML(events) : _noRowsStr;
    }

    public String getCaseStartedBy(String caseID) {
        ResourceEvent event = getCaseEvent(caseID, EventLogger.event.launch_case);
        if (event != null) {
            return getParticipantName(getFieldValue(event.toXML(), "resourceid"));
        } else
            return "Unavailable";
    }

    public String getParticipantHistory(String pid) {
        return getResourceHistory(pid);
    }

    public String getParticipantHistory(String pid, long from, long to) {
        return ((from < 0) && (to < 0)) ? getResourceHistory(pid) : getResourceHistory(pid, from, to);
    }

    public String getParticipantHistoryForEvent(String pid, EventLogger.event eventType) {
        return getResourceHistoryForEvent(pid, eventType);
    }

    public String getParticipantHistoryForEvent(String pid, EventLogger.event eventType, long from, long to) {
        return getResourceHistoryForEvent(pid, eventType, from, to);
    }

    public String getResourceHistory(String id) {
        List events = getResourceEventsList(id);
        return (events != null) ? eventListToXML(events) : _noRowsStr;
    }

    public String getResourceHistory(String id, long from, long to) {
        if ((from < 0) && (to < 0))
            return getResourceHistory(id);
        List events = getResourceEventsList(id, from, to);
        return (events != null) ? eventListToXML(events) : _noRowsStr;
    }

    public String getResourceHistoryForEvent(String id, EventLogger.event eventType) {
        List events = getResourceEventsList(id);
        return getExtractedEvents(events, eventType);
    }

    public String getResourceHistoryForEvent(String id, EventLogger.event eventType, long from, long to) {
        List events = getResourceEventsList(id, from, to);
        return getExtractedEvents(events, eventType);
    }

    public String getWorkItemOffered(String itemID) {
        List events = getWorkItemEventsList(itemID);
        if (events != null) {
            List<ResourceEvent> offered = extractEvents(events, EventLogger.event.offer);
            return (offered != null) ? eventListToXML(offered) : _noRowsStr;
        }
        return _noRowsStr;
    }

    public String getWorkItemAllocated(String itemID) {
        ResourceEvent event = getWorkItemEvent(itemID, EventLogger.event.allocate);
        return (event != null) ? event.toXML() : _noRowsStr;
    }

    public String getWorkItemStarted(String itemID) {
        ResourceEvent event = getWorkItemEvent(itemID, EventLogger.event.start);
        return (event != null) ? event.toXML() : _noRowsStr;
    }

    public String getCaseHistoryInvolvingParticipant(String pid) {
        return getCaseHistoryForParticipantEvents(getResourceEventsList(pid));
    }

    public String getCaseHistoryInvolvingParticipant(String pid, long from, long to) {
        return ((from < 0) && (to < 0)) ? getCaseHistoryInvolvingParticipant(pid)
                : getCaseHistoryForParticipantEvents(getResourceEventsList(pid, from, to));
    }

    public String getSpecificationEventsByURI(String uri, long from, long to) {
        return getSpecificationEvents(getSpecIDs(uri, true), from, to);
    }

    public String getSpecificationEventsByID(String id, long from, long to) {
        return getSpecificationEvents(getSpecIDs(id, false), from, to);
    }

    public String getSpecificationEvents(Set<YSpecificationID> specIDs) {
        StringBuilder s = new StringBuilder("<SpecificationEvents>");
        for (YSpecificationID specID : specIDs) {
            List events = getSpecificationEvents(getSpecificationKey(specID));
            if (events != null)
                s.append(formatSpecificationEvents(specID, events));
        }
        s.append("</SpecificationEvents>");
        return s.toString();
    }

    public String getSpecificationEvents(Set<YSpecificationID> specIDs, long from, long to) {
        if ((from < 0) && (to < 0))
            return getSpecificationEvents(specIDs);
        StringBuilder s = new StringBuilder("<SpecificationEvents>");
        for (YSpecificationID specID : specIDs) {
            List events = getSpecificationEvents(getSpecificationKey(specID), from, to);
            if (events != null)
                s.append(formatSpecificationEvents(specID, events));
        }
        s.append("</SpecificationEvents>");
        return s.toString();
    }

    public String getSpecificationEvents(YSpecificationID specID) {
        List events = getSpecificationEvents(getSpecificationKey(specID));
        return (events != null) ? eventListToXML(events) : _noRowsStr;
    }

    public String getSpecificationEvents(YSpecificationID specID, long from, long to) {
        if ((from < 0) && (to < 0))
            return getSpecificationEvents(specID);
        List events = getSpecificationEvents(getSpecificationKey(specID), from, to);
        return (events != null) ? eventListToXML(events) : _noRowsStr;
    }

    public String getSpecificationIdentifiers(String keyStr) {
        try {
            long key = new Long(keyStr);
            SpecLog spec = getSpecLogRecord(key);
            return (spec != null) ? spec.getSpecID().toXML() : _noRowsStr;
        } catch (NumberFormatException nfe) {
            return _badKeyStr;
        }
    }

    public String getSpecificationXESLog(YSpecificationID specid) {
        XNode cases = getXESLog(specid);
        if (cases != null) {
            return new ResourceXESLog().buildLog(specid, cases);
        }
        return "";
    }

    public String getMergedXESLog(YSpecificationID specid) {
        return getMergedXESLog(specid, false);
    }

    public String getMergedXESLog(YSpecificationID specid, boolean withData) {
        XNode rsCases = getXESLog(specid);
        String engCases = ResourceManager.getInstance().getClients().getEngineXESLog(specid, withData);
        if ((rsCases != null) && (engCases != null)) {
            return new ResourceXESLog().mergeLogs(rsCases, engCases);
        }
        return "";
    }

    public String getSpecificationStatistics(YSpecificationID specID) {
        return getSpecificationStatistics(specID, -1, -1);
    }

    public String getSpecificationStatistics(YSpecificationID specID, long from, long to) {
        return ResourceManager.getInstance().getClients().getEngineSpecificationStatistics(specID, from, to);
    }

    public String getTaskStatistics(long specKey, String taskName) {
        return getTaskStatistics(specKey, taskName, -1, -1);
    }

    public String getTaskStatistics(long specKey, String taskName, long from, long to) {
        List taskEvents = getTaskEventsList(specKey, taskName, from, to);
        return (taskEvents != null) ? new TaskStatistics(taskEvents, taskName).generate() : _noRowsStr;
    }

    public String getTaskStatistics(YSpecificationID specID, String taskName) {
        return getTaskStatistics(getSpecificationKey(specID), taskName, -1, -1);
    }

    public String getTaskStatistics(YSpecificationID specID, String taskName, long from, long to) {
        return getTaskStatistics(getSpecificationKey(specID), taskName, from, to);
    }

    public String getTaskStatisticsForCase(String caseID) {
        return getTaskStatisticsForCase(caseID, -1, -1);
    }

    public String getTaskStatisticsForCase(String caseID, long from, long to) {
        List events = getCaseEventsList(caseID, from, to);
        return (events != null) ? getTaskStatisticsForCase(caseID, events) : _noRowsStr;
    }

    public String getTaskStatisticsForSpecification(YSpecificationID specID) {
        return getTaskStatisticsForSpecification(specID, -1, -1);
    }

    public String getTaskStatisticsForSpecification(YSpecificationID specID, long from, long to) {
        long key = getSpecificationKey(specID);
        List events = getSpecificationEvents(key, from, to);
        return (events != null) ? getTaskStatisticsForSpecification(specID, events) : _noRowsStr;
    }

    public String getTaskStatisticsForSpecificationURI(String uri, long from, long to) {
        return getTaskStatisticsForSpecificationSet(getSpecIDs(uri, true), from, to);
    }

    public String getTaskStatisticsForSpecificationUID(String id, long from, long to) {
        return getTaskStatisticsForSpecificationSet(getSpecIDs(id, false), from, to);
    }

    public String getTaskStatisticsForSpecificationSet(Set<YSpecificationID> specIDs, long from, long to) {
        StringBuilder s = new StringBuilder("<taskStatisticsForSpecifications>");
        for (YSpecificationID specID : specIDs) {
            s.append(getTaskStatisticsForSpecification(specID, from, to));
        }
        s.append("</taskStatisticsForSpecifications>");
        return s.toString();
    }

    public String getTaskStatisticsForSpecificationSet(Set<YSpecificationID> specIDs) {
        return getTaskStatisticsForSpecificationSet(specIDs, -1, -1);
    }

    public List getLastBusyOrReleaseEvents(String resourceID) {
        return getLastUseEvents(resourceID);
    }

    public List getBusyResources(String itemID) {
        String query = String.format("%s WHERE re._itemID = '%s' AND re._event='busy' "
                + "AND re._resourceID NOT IN (" + "SELECT rx._resourceID FROM ResourceEvent AS rx "
                + "WHERE rx._itemID = '%s' " + "AND rx._event='released')", _baseQuery, itemID, itemID);
        return execQuery(query);
    }

    public List getBusyResourcesForCase(String caseID) {
        String query = String.format(
                "%s WHERE re._event='busy' " + "AND (re._caseID='%s' OR re._caseID LIKE '%s%s') "
                        + "AND re._resourceID NOT IN (" + "SELECT rx._resourceID FROM ResourceEvent AS rx "
                        + "WHERE rx._event='released' " + "AND (re._caseID='%s' OR re._caseID LIKE '%s%s'))",
                _baseQuery, caseID, caseID, ".%", caseID, caseID, ".%");
        return execQuery(query);
    }

    public Set<String> getBusyItemIDsForCase(String caseID) {
        Set<String> busyItemIDs = new HashSet<String>();
        for (Object o : getBusyResourcesForCase(caseID)) {
            ResourceEvent row = (ResourceEvent) o;
            if (row.get_event().equals("busy")) {
                busyItemIDs.add(row.get_itemID());
            } else if (row.get_event().equals("released")) {
                busyItemIDs.remove(row.get_itemID());
            }
        }
        return busyItemIDs;
    }

    /*****************************************************************************/

    private List execQuery(String query) {
        List rows = null;
        if (_reader != null) {
            rows = _reader.execQuery(query);
            _reader.commit();
        }
        return rows;
    }

    private String getWhereQuery(String field, String value) {
        return String.format("%s WHERE re.%s='%s'", _baseQuery, field, value);
    }

    private String getWhereQuery(String field, long value) {
        return String.format("%s WHERE re.%s=%d", _baseQuery, field, value);
    }

    private List getWorkItemEventsList(String itemID) {
        return execQuery(getWhereQuery("_itemID", itemID));
    }

    private List getWorkItemEventsList(String itemID, long from, long to) {
        String query = getWhereQuery("_itemID", itemID) + getTimeRangeSubclause(from, to);
        return execQuery(query);
    }

    private List getTaskEventsList(long specKey, String taskName) {
        String query = getWhereQuery("_taskID", massageTaskName(taskName)) + " AND _specKey=" + specKey;
        return execQuery(query);
    }

    private List getTaskEventsList(long specKey, String taskName, long from, long to) {
        String query = getWhereQuery("_taskID", massageTaskName(taskName)) + " AND _specKey=" + specKey
                + getTimeRangeSubclause(from, to);
        return execQuery(query);
    }

    private List getSpecificationEvents(long specKey) {
        return (specKey == -1) ? null : execQuery(getWhereQuery("_specKey", specKey));
    }

    private List getSpecificationEvents(long specKey, long from, long to) {
        return (specKey == -1) ? null
                : execQuery(getWhereQuery("_specKey", specKey) + getTimeRangeSubclause(from, to));
    }

    private List getCaseEventsList(String caseID) {
        String query = String.format("%s WHERE re._caseID='%s' OR re._caseID LIKE '%s%s'", _baseQuery, caseID,
                caseID, ".%");
        return execQuery(query);
    }

    private List getAllEvents() {
        return execQuery(_baseQuery + " ORDER BY re._timeStamp");
    }

    private List getCaseEventsList(String caseID, long from, long to) {
        String query = String.format("%s WHERE re._caseID='%s' OR re._caseID LIKE '%s%s'", _baseQuery, caseID,
                caseID, ".%") + getTimeRangeSubclause(from, to);
        return execQuery(query);
    }

    private List getResourceEventsList(String resourceID) {
        return execQuery(getWhereQuery("_resourceID", resourceID));
    }

    private List getResourceEventsList(String resourceID, long from, long to) {
        String query = getWhereQuery("_resourceID", resourceID) + getTimeRangeSubclause(from, to);
        return execQuery(query);
    }

    private SpecLog getSpecLogRecord(long key) {
        SpecLog specLog = null;
        if (_reader != null) {
            String query = String.format("FROM SpecLog AS sl WHERE sl.logID=%d", key);
            List rows = _reader.execQuery(query);
            if ((rows != null) && (!rows.isEmpty())) {
                specLog = (SpecLog) rows.get(0);
            }
            _reader.commit();
        }
        return specLog;
    }

    private String getTimeRangeSubclause(long from, long to) {
        String subclause = "";
        if (from > 0) {
            subclause = " AND re._timeStamp >= " + from;
        }
        if (to > 0) {
            subclause = " AND re._timeStamp <= " + to;
        }
        return subclause;
    }

    private boolean containsStartEvent(List events) {
        return containsEvent(events, EventLogger.event.start);
    }

    private boolean containsEvent(List events, EventLogger.event eventType) {
        for (Object o : events) {
            ResourceEvent event = (ResourceEvent) o;
            if (event.get_event().equals(eventType.name())) {
                return true;
            }
        }
        return false;
    }

    private List<ResourceEvent> extractEvents(List events, EventLogger.event eventType) {
        List<ResourceEvent> extracted = new ArrayList<ResourceEvent>();
        for (Object o : events) {
            ResourceEvent event = (ResourceEvent) o;
            if (event.get_event().equals(eventType.name())) {
                extracted.add(event);
            }
        }
        return extracted;
    }

    private String getCaseHistoryForParticipantEvents(List participantEvents) {
        List allEvents = new ArrayList();
        if (participantEvents != null) {

            // get set of cases involving this participant
            Set<String> caseIDs = new TreeSet<String>();
            for (Object o : participantEvents) {
                ResourceEvent event = (ResourceEvent) o;
                caseIDs.add(getRootCaseID(event.get_caseID()));
            }

            for (String caseID : caseIDs) {
                allEvents.addAll(getCaseEventsList(caseID));
            }
        }
        return (!allEvents.isEmpty()) ? eventListToXML(allEvents) : _noRowsStr;
    }

    private String formatSpecificationEvents(YSpecificationID specID, List events) {
        StringBuilder s = new StringBuilder("<specification id=\"");
        s.append(specID.toString()).append("\">");
        if (events != null)
            s.append(eventListToXML(events));
        s.append("</specification>");
        return s.toString();
    }

    private String getExtractedEvents(List events, EventLogger.event eventType) {
        if (events != null) {
            List<ResourceEvent> extracted = extractEvents(events, eventType);
            return (extracted != null) ? eventListToXML(extracted) : _noRowsStr;
        }
        return _noRowsStr;

    }

    private String getTaskStatisticsForCase(String caseID, List events) {
        Map<String, List<ResourceEvent>> taskLists = collateTaskEvents(events);
        if (taskLists != null) {
            XNode node = new XNode("taskStatisticsForCase");
            node.addAttribute("case", caseID);
            node.addChildren(getTaskStatisticsSet(taskLists));
            return node.toString();
        } else
            return _noRowsStr;
    }

    private String getTaskStatisticsForSpecification(YSpecificationID specID, List events) {
        Map<String, List<ResourceEvent>> taskLists = collateTaskEvents(events);
        if (taskLists != null) {
            XNode node = new XNode("taskStatisticsForSpecification");
            node.addAttribute("id", specID.toString());
            node.addChildren(getTaskStatisticsSet(taskLists));
            return node.toString();
        } else
            return _noRowsStr;
    }

    private List<XNode> getTaskStatisticsSet(Map<String, List<ResourceEvent>> taskLists) {
        XNode node = new XNode("tasks");
        for (String taskName : taskLists.keySet()) {
            if (taskName != null) {
                node.addChild(new TaskStatistics(taskLists.get(taskName), taskName).generateXNode());
            }
        }
        return node.getChildren();
    }

    private Map<String, List<ResourceEvent>> collateTaskEvents(List events) {
        Map<String, List<ResourceEvent>> collated = null;
        if (events != null) {
            collated = new LinkedHashMap<String, List<ResourceEvent>>();
            for (Object o : events) {
                ResourceEvent event = (ResourceEvent) o;
                String taskName = event.get_taskID();
                List<ResourceEvent> subList = collated.get(taskName);
                if (subList == null) {
                    subList = new ArrayList<ResourceEvent>();
                    collated.put(taskName, subList);
                }
                subList.add(event);
            }
        }
        return collated;
    }

    /**
     * @param caseID the case id to get the event for
     * @param eventType which event to get
     * @return the case event
     */
    private ResourceEvent getCaseEvent(String caseID, EventLogger.event eventType) {
        String query = String.format("%s WHERE re._caseID='%s' AND re._event='%s'", _baseQuery, caseID,
                eventType.name());
        return execScalarQuery(query);
    }

    private ResourceEvent getWorkItemEvent(String itemID, EventLogger.event eventType) {
        String query = String.format("%s WHERE re._itemID='%s' AND re._event='%s'", _baseQuery, itemID,
                eventType.name());
        return execScalarQuery(query);
    }

    private List getLastUseEvents(String resourceID) {
        String query = "SELECT re._event, MAX(re._timeStamp) " + "FROM ResourceEvent AS re "
                + "WHERE re._resourceID = '" + resourceID + "' AND (re._event='busy' OR re._event='released') "
                + "GROUP BY re._event";
        return execQuery(query); // returns 0-2 rows of Object[2]
    }

    private ResourceEvent execScalarQuery(String query) {
        ResourceEvent event = null;
        if (_reader != null) {
            List rows = _reader.execQuery(query);
            if ((rows != null) && (!rows.isEmpty())) {
                event = (ResourceEvent) rows.get(0);
            }
            _reader.commit();
        }
        return event;
    }

    private String deriveParentID(String itemID) {
        String[] parts = itemID.split(":");
        String caseID = parts[0].substring(0, parts[0].lastIndexOf("."));
        return caseID + ":" + parts[1];
    }

    private List<BaseEvent> replaceParticipantIDsWithNames(List events) {
        List<BaseEvent> cloneList = new ArrayList<BaseEvent>();
        for (Object o : events) {
            ResourceEvent event = ((ResourceEvent) o).clone();
            event.set_resourceID(getParticipantName(event.get_resourceID()));
            cloneList.add(event);
        }
        return cloneList;
    }

    private String getParticipantName(String pid) {
        String name = "Unavailable";
        if (pid != null) {
            if (!pid.equals("admin")) {
                Participant p = ResourceManager.getInstance().getOrgDataSet().getParticipant(pid);
                if (p != null)
                    name = p.getFullName();
            } else
                name = "admin";
        }
        return name;
    }

    private String eventListToXML(List rows) {
        StringBuilder xml = new StringBuilder("<events>");
        for (Object o : rows) {
            BaseEvent event = (BaseEvent) o;
            xml.append(event.toXML());
        }
        xml.append("</events>");
        return xml.toString();
    }

    private String getFieldValue(String caseEventXML, String fieldname) {
        Element eventElem = JDOMUtil.stringToElement(caseEventXML);
        if (eventElem != null) {
            Element firstEvent = eventElem.getChild("event");
            if (firstEvent != null) {
                return firstEvent.getChildText(fieldname);
            }
        }
        return null;
    }

    private long getSpecificationKey(YSpecificationID specID) {
        return EventLogger.getSpecificationKey(specID);
    }

    private Set<YSpecificationID> getSpecIDs(String s, boolean uri) {
        if (s == null)
            return null;
        Set<YSpecificationID> specSet = new HashSet<YSpecificationID>();
        String query = String.format("FROM SpecLog as sl WHERE sl.specID.%s='%s'", uri ? "uri" : "identifier", s);
        List rows = _reader.execQuery(query);
        for (Object row : rows) {
            SpecLog spec = (SpecLog) row;
            specSet.add(spec.getSpecID());
        }
        _reader.commit();
        return specSet;
    }

    private XNode getXESLog(YSpecificationID specID) {
        XNode cases = new XNode("cases");
        XNode caseNode = null;
        long specKey = getSpecificationKey(specID);
        if (specKey > -1) {
            String query = String.format("%s WHERE re._specKey=%d ORDER BY re._caseID, re._timeStamp", _baseQuery,
                    specKey);

            List rows = _reader.execQuery(query);
            String caseID = "-1";
            for (Object row : rows) {
                ResourceEvent event = (ResourceEvent) row;
                if (!sameCase(event.get_caseID(), caseID)) {
                    caseID = event.get_caseID();
                    caseNode = cases.addChild("case");
                    caseNode.addAttribute("id", caseID);
                }

                // only want task events
                if ((caseNode != null) && (event.get_taskID() != null)) {
                    XNode eventNode = caseNode.addChild("event");
                    eventNode.addChild("taskname", event.get_taskID());
                    eventNode.addChild("instanceid", event.get_caseID());
                    eventNode.addChild("descriptor", event.get_event());
                    eventNode.addChild("timestamp", event.getTimeStampString());
                    eventNode.addChild("resource", event.get_resourceID());
                }
            }
            _reader.commit();
        }
        return cases;
    }

    private String massageTaskName(String taskName) {
        if ((taskName == null) || (!taskName.contains("_")))
            return taskName;
        char firstChar = taskName.charAt(0);
        char lastChar = taskName.charAt(taskName.length() - 1);
        if ((firstChar >= '0') && (firstChar <= '9')) { // pre-beta 7
            return taskName.substring(taskName.indexOf('_') + 1);
        } else if ((lastChar >= '0') && (lastChar <= '9')) { // post-beta 7
            taskName = taskName.substring(0, taskName.lastIndexOf('_'));
        }
        return taskName.replace('_', ' ');
    }

    private boolean sameCase(String eventCaseID, String currentCaseID) {
        return eventCaseID.equals(currentCaseID) || eventCaseID.startsWith(currentCaseID + ".");
    }

    private String getRootCaseID(String caseID) {
        return caseID.contains(".") ? caseID.substring(0, caseID.indexOf('.')) : caseID;
    }

    private boolean successful(String s) {
        return (s != null) && (!s.startsWith("<fail"));
    }

}