org.yawlfoundation.yawl.scheduling.lanes.LaneProducer.java Source code

Java tutorial

Introduction

Here is the source code for org.yawlfoundation.yawl.scheduling.lanes.LaneProducer.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.scheduling.lanes;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.jdom2.Element;
import org.yawlfoundation.yawl.resourcing.resource.Participant;
import org.yawlfoundation.yawl.resourcing.resource.Role;
import org.yawlfoundation.yawl.resourcing.resource.nonhuman.NonHumanCategory;
import org.yawlfoundation.yawl.resourcing.resource.nonhuman.NonHumanResource;
import org.yawlfoundation.yawl.resourcing.rsInterface.ResourceGatewayException;
import org.yawlfoundation.yawl.scheduling.*;
import org.yawlfoundation.yawl.scheduling.persistence.DataMapper;
import org.yawlfoundation.yawl.scheduling.resource.ResourceServiceInterface;
import org.yawlfoundation.yawl.scheduling.util.PropertyReader;
import org.yawlfoundation.yawl.scheduling.util.Utils;
import org.yawlfoundation.yawl.scheduling.util.XMLUtils;

import java.util.*;

public class LaneProducer implements Constants {
    private static Logger logger = LogManager.getLogger(LaneProducer.class);

    private DataMapper dataMapper;
    private ConfigManager config;
    private Scheduler scheduler;
    private String categoryId;
    private String roleId;
    private List<Map<String, Object>> lanes = new ArrayList<Map<String, Object>>();
    private final int titleShortLength = 3;
    private final boolean debug = true; // show debug output in process units

    public LaneProducer(String categoryOrRoleId, ConfigManager config) throws Exception {
        this.config = config;
        ResourceServiceInterface rs = ResourceServiceInterface.getInstance();
        scheduler = new Scheduler();
        dataMapper = new DataMapper();

        NonHumanCategory category = null;
        Role role = null;
        try {
            category = rs.getNonHumanCategory(categoryOrRoleId);
        } catch (ResourceGatewayException e) {
            // NonHumanCategory not found
        }
        if (category == null) {
            try {
                role = rs.getRole(categoryOrRoleId);
            } catch (ResourceGatewayException e) {
                // Role not found
            }
        }

        if (category != null) {
            categoryId = category.getID();
            for (NonHumanResource nhr : rs.getNonHumanResources()) {
                if (nhr.getCategory() != null && categoryId.equals(nhr.getCategory().getID())) {
                    Map<String, Object> lane = new HashMap<String, Object>();
                    put(lane, "id", nhr.getID());
                    put(lane, "title", nhr.getName() + (debug ? " (" + nhr.getID() + ")" : ""));
                    int idx = nhr.getName().lastIndexOf("#") + 1;
                    put(lane, "titleShort",
                            idx < nhr.getName().length() ? nhr.getName().substring(idx) : nhr.getName());
                    lanes.add(lane);
                }
            }
        } else if (role != null) {
            roleId = role.getID();
            for (Participant participant : rs.getParticipants()) {
                Collection<Role> roles = rs.getParticipantRoles(participant.getID());
                if (roles != null)
                    participant.setRoles(new HashSet<Role>(roles));
                if (participant.hasRole(role)) {
                    Map<String, Object> lane = new HashMap<String, Object>();
                    put(lane, "id", participant.getID());
                    put(lane, "title", participant.getFullName());
                    put(lane, "titleShort", getInitials(participant));
                    lanes.add(lane);
                }
            }
        } else {
            throw new SchedulingException("lane group id not found: " + categoryOrRoleId);
        }

        // sort lanes by title, then add virtualLane at end
        Collections.sort(lanes, new Comparator<Map<String, Object>>() {
            public int compare(Map<String, Object> m1, Map<String, Object> m2) {
                return ((String) m1.get("title")).compareTo((String) m2.get("title"));
            }
        });

        Map<String, Object> virtualLane = new HashMap<String, Object>();
        put(virtualLane, "id", "virtual");
        put(virtualLane, "title", config.getLocalizedString("virtual"));
        put(virtualLane, "titleShort", config.getLocalizedString("virtual").substring(0, titleShortLength));
        lanes.add(virtualLane);
        logger.debug("categoryId=" + categoryId + ", roleId=" + roleId + ", lanes " + Utils.toString(lanes));
    }

    public List<List<Map<String, Object>>> getLanes(String... dates) throws Exception {
        Date from, to;
        int count = 0;

        // show intraoperative activities only
        String possibleActivitiesSorted = PropertyReader.getInstance()
                .getSchedulingProperty("possibleActivitiesSorted");
        String[] possibleActivities = Utils.parseCSV(possibleActivitiesSorted).toArray(new String[0]);

        // return dates in same order as given
        List<List<Map<String, Object>>> allLanes4AllDates = new ArrayList<List<Map<String, Object>>>();
        for (String date : dates) {
            List<Map<String, Object>> allLanes4Date = (List<Map<String, Object>>) Utils.deepCopy(lanes);
            //logger.debug("date="+date+", allLanes4Date "+Utils.toString(allLanes4Date));

            // lane goes from 00:00:00.001 bis 23:59:59.999
            long tmp = Utils.string2Date(date, Utils.DATE_PATTERN_XML).getTime();
            from = new Date(tmp - 1);
            to = new Date(tmp + 24 * 60 * 60 * 1000);
            List<Case> cases = dataMapper.getRupsByInterval(from, to, null, false);
            logger.debug("found " + cases.size() + " cases for date " + date);

            for (Case cas : cases) {
                try {
                    String xpath = XMLUtils.getXPATH_Activities(possibleActivities);
                    List<Element> activities = XMLUtils.getXMLObjects(cas.getRUP(), xpath);
                    if (activities.isEmpty()) {
                        continue;
                    }

                    // get original FROM and TO date
                    Date originalEarlFrom = XMLUtils.getDateValue(activities.get(0).getChild(XML_FROM), false);
                    Date originalLatestTo = XMLUtils
                            .getDateValue(activities.get(activities.size() - 1).getChild(XML_TO), false);

                    // set times for showable in OP plan, if no duration given, set 5 min as default
                    Element earlFrom = XMLUtils.getEarliestBeginElement(cas.getRUP(), possibleActivities);
                    Element latestTo = XMLUtils.getLatestEndElement(cas.getRUP(), possibleActivities);
                    scheduler.setTimes(cas.getRUP(),
                            earlFrom == null ? latestTo.getParentElement() : earlFrom.getParentElement(), false,
                            false, Utils.stringXML2Duration("PT5M"));
                    earlFrom = XMLUtils.getEarliestBeginElement(cas.getRUP(), possibleActivities);
                    latestTo = XMLUtils.getLatestEndElement(cas.getRUP(), possibleActivities);

                    Map<String, Object> processUnit = new HashMap<String, Object>();
                    put(processUnit, "caseId", cas.getCaseId());
                    put(processUnit, "title", cas.getCaseName());
                    put(processUnit, "start",
                            Utils.date2String(XMLUtils.getDateValue(earlFrom, false), "yyyy-MM-dd HH:mm:ss"));
                    put(processUnit, "end",
                            Utils.date2String(XMLUtils.getDateValue(latestTo, false), "yyyy-MM-dd HH:mm:ss"));
                    put(processUnit, "hasConflicts", false); // TODO@tbe: has rup conflicts ?
                    put(processUnit, "hasErrors", XMLUtils.hasErrors(cas.getRUP().getRootElement()));
                    put(processUnit, "hasWarnings", XMLUtils.hasWarnings(cas.getRUP().getRootElement()));
                    //put(processUnit, "canBeEdited", true); // TODO@tbe: false wenn schon gestartet oder kein YAWL-Case mehr vorhanden, noch im OP-Plan erweitern

                    Map<String, Object> data = new HashMap<String, Object>();
                    //put(data, "description", cas.getId() + ": " + cas.getPatientFullName() + (cas.getPatientSex()==null ? "" : " (" + cas.getPatientSex() + ")"));
                    put(data, "description", "" + ": " + cas.getCaseDescription());
                    put(data, "note0", "xxx");
                    if (debug)
                        put(data, "note1", originalEarlFrom == null ? "???"
                                : Utils.date2String(originalEarlFrom, "HH:mm dd.MM.yyyy") + " - ");
                    if (debug)
                        put(data, "note2", originalLatestTo == null ? "???"
                                : Utils.date2String(originalLatestTo, "HH:mm dd.MM.yyyy"));
                    put(data, "note3", cas.getCaseId()); // YAWL-CaseId
                    put(data, "note4", ""); // reserved for title
                    put(data, "note5", ""); // reserved for activityNames
                    put(data, "note6", ""); // reserved for activityNames
                    put(data, "note7", ""); // reserved for activityNames
                    put(data, "note8", ""); // reserved for activityNames
                    put(data, "note9", ""); // reserved for activityNames

                    put(processUnit, "data", data);

                    List<Map<String, Object>> stages = new ArrayList<Map<String, Object>>();
                    Long firstActFrom = null;
                    int note = 0;
                    for (Element activity : activities) {
                        String activityName = activity.getChildText(XML_ACTIVITYNAME);
                        Date actFrom = XMLUtils.getDateValue(activity.getChild(XML_FROM), true);
                        if (firstActFrom == null) {
                            firstActFrom = actFrom.getTime();
                        }

                        if (debug) {
                            put(data, "note" + (note + 5), activityName);
                            note++;
                        }

                        Map<String, Object> stage = new HashMap<String, Object>();
                        put(stage, "id", "stage-" + activityName);
                        put(stage, "title", config.getLocalizedString(activityName));
                        put(stage, "start", Utils.date2String(actFrom, Utils.DATETIME_PATTERN));
                        put(stage, "offset", (actFrom.getTime() - firstActFrom) / 1000 / 60);
                        put(stage, "running",
                                UTILISATION_TYPE_BEGIN.equals(activity.getChildText(XML_REQUESTTYPE)));
                        stages.add(stage);
                    }

                    put(processUnit, "stages", stages);

                    // find matching lanes
                    xpath = XMLUtils.getXPATH_ActivitiesElement(possibleActivities, XML_RESERVATION, null);
                    List<Element> reservations = XMLUtils.getXMLObjects(cas.getRUP(), xpath);
                    List<Map<String, Object>> lanes4Date = getMatchingLanes(reservations, allLanes4Date);
                    logger.debug(lanes4Date.size() + " lanes found for caseId: " + cas.getCaseId());

                    for (Map<String, Object> lane4Date : lanes4Date) {
                        List<Map<String, Object>> processUnits = (List) lane4Date.get("processUnits");
                        if (processUnits == null) {
                            processUnits = new ArrayList<Map<String, Object>>();
                        }
                        if (debug)
                            put(data, "note4", lane4Date.get("title"));
                        Map<String, Object> processUnitCopy = (Map<String, Object>) Utils.deepCopy(processUnit);
                        put(processUnitCopy, "id", "id" + processUnitCopy.get("caseId") + "-" + count++);
                        processUnits.add(processUnitCopy);
                        put(lane4Date, "processUnits", processUnits);
                    }
                } catch (Throwable e) {
                    logger.error("cannot show case: " + cas.getCaseId(), e);
                }
            }
            allLanes4AllDates.add(allLanes4Date);
        }
        return allLanes4AllDates;
    }

    /**
     * lanes finden durch prfen von rolle bzw. category 
     */
    private List<Map<String, Object>> getMatchingLanes(List<Element> reservations,
            List<Map<String, Object>> allLanes4Date) {
        List<Map<String, Object>> lanes4Date = new ArrayList<Map<String, Object>>();
        for (Map<String, Object> lane4Date : allLanes4Date) {
            for (Element reservation : reservations) {
                try {
                    String statusToBe = reservation.getChildText(XML_STATUSTOBE);
                    if (!statusToBe.equals(RESOURCE_STATUS_REQUESTED)
                            && !statusToBe.equals(RESOURCE_STATUS_RESERVED)) {
                        continue;
                    }

                    int workload = Integer.parseInt(reservation.getChildText(XML_WORKLOAD));
                    if (workload == 0) {
                        continue;
                    }

                    Element resource = reservation.getChild(XML_RESOURCE);
                    String resourceId = resource.getChildText(XML_ID);
                    String categoryId = resource.getChildText(XML_CATEGORY);
                    String roleId = resource.getChildText(XML_ROLE);
                    Object laneId = lane4Date.get("id");
                    //logger.debug("resourceId="+resourceId+", categoryId="+categoryId+", roleId="+roleId+", laneId="+laneId);
                    if (!"virtual".equals(laneId) && resourceId.equals(laneId)) { // match by Id
                        lanes4Date.add(lane4Date);
                        //logger.debug("match by Id, resourceId="+resourceId+", laneId="+lane4Date.get("id"));
                        break;
                    } else if (resourceId.isEmpty() && "virtual".equals(laneId)) {
                        if (categoryId.equals(this.categoryId)) { // match by category
                            lanes4Date.add(lane4Date);
                            //logger.debug("match by category, categoryId="+categoryId);
                            break;
                        } else if (roleId.equals(this.roleId)) { // match by role
                            lanes4Date.add(lane4Date);
                            //logger.debug("match by role, roleId="+roleId);
                            break;
                        }
                    }
                } catch (Exception e) {
                    logger.error("cannot search for matching lane", e);
                }
            }
        }

        // if no lane found (means that no matching resource was defined in rup) then add to virtualLane 
        if (lanes4Date.isEmpty()) {
            Map<String, Object> virtualLane4Date = allLanes4Date.get(allLanes4Date.size() - 1);
            lanes4Date.add(virtualLane4Date);
        }

        return lanes4Date;
    }

    /**
     * replace null values by ""
     */
    private void put(Map<String, Object> map, String key, Object value) {
        map.put(key, value == null ? "" : value);
    }

    private String getInitials(Participant participant) {
        return (participant.getFirstName().substring(0, 1) + participant.getLastName()).substring(0,
                titleShortLength);
    }
}