Java tutorial
/* * 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.interactions; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.jdom2.Element; import org.jdom2.Namespace; import org.yawlfoundation.yawl.engine.interfce.WorkItemRecord; import org.yawlfoundation.yawl.resourcing.ResourceManager; import org.yawlfoundation.yawl.resourcing.WorkQueue; import org.yawlfoundation.yawl.resourcing.constraints.AbstractConstraint; import org.yawlfoundation.yawl.resourcing.filters.AbstractFilter; import org.yawlfoundation.yawl.resourcing.resource.Participant; import org.yawlfoundation.yawl.resourcing.resource.Role; import org.yawlfoundation.yawl.resourcing.util.PluginFactory; import java.io.IOException; import java.util.*; /** * This class describes the requirements of a task at the offer phase of * allocating resources. * * @author Michael Adams * v0.1, 02/08/2007 */ public class OfferInteraction extends AbstractInteraction { // initial distribution set private HashSet<Participant> _participants = new HashSet<Participant>(); private HashSet<Role> _roles = new HashSet<Role>(); private HashSet<DynParam> _dynParams = new HashSet<DynParam>(); // complete distribution set expanded to a set of participants private HashSet<Participant> _distributionSet = new HashSet<Participant>(); private HashSet<AbstractFilter> _filters = new HashSet<AbstractFilter>(); private HashSet<AbstractConstraint> _constraints = new HashSet<AbstractConstraint>(); private String _familiarParticipantTask; private ResourceManager _rm = ResourceManager.getInstance(); private static final Logger _log = LogManager.getLogger(OfferInteraction.class); // Dynamic Parameter types public static final int USER_PARAM = 0; public static final int ROLE_PARAM = 1; /********************************************************************************/ // CONSTRUCTORS // public OfferInteraction() { super(); } // required for reflection public OfferInteraction(String ownerTaskID) { super(ownerTaskID); } /** * @param initiator - either AbstractInteraction.SYSTEM_INITIATED or * AbstractInteraction.USER_INITIATED */ public OfferInteraction(int initiator) { super(initiator); } /********************************************************************************/ // MEMBER MODIFIERS // /** * Adds a participant to the initial distribution list * @param id - the id of the participant */ public void addParticipant(String id) { Participant p = _rm.getOrgDataSet().getParticipant(id); if (p != null) _participants.add(p); else _log.warn("Unknown Participant ID in Offer spec: {}", id); } public void addParticipantUnchecked(String id) { Participant p = new Participant(id); _participants.add(p); } /** * variation of the above * @param p - the Participant object to add to the initial distribution list */ public void addParticipant(Participant p) { if (_rm.getOrgDataSet().isKnownParticipant(p)) _participants.add(p); else _log.warn("Could not add unknown Participant to Offer: {}", p.getID()); } public void addParticipantsByID(String idList) { String[] ids = idList.split(","); for (String id : ids) addParticipant(id.trim()); } public void addParticipantsByID(Set idSet) { for (Object id : idSet) addParticipant((String) id); } public void addParticipants(Set pSet) { for (Object id : pSet) addParticipant((Participant) id); } public void addRole(String rid) { Role r = _rm.getOrgDataSet().getRole(rid); if (r != null) _roles.add(r); else _log.warn("Unknown Role ID in Offer spec: {}", rid); } public void addRoleUnchecked(String rid) { Role r = new Role(); r.setID(rid); _roles.add(r); } public void addRole(Role r) { if (_rm.getOrgDataSet().isKnownRole(r)) _roles.add(r); else _log.warn("Could not add unknown Role to Offer: {}", r.getID()); } public void addRoles(String roleList) { String[] roles = roleList.split(","); for (String role : roles) addRole(role.trim()); } public void addRoles(Set rSet) { for (Object role : rSet) addRole((Role) role); } public boolean addInputParam(String name, int type) { if ((type == USER_PARAM) || (type == ROLE_PARAM)) { DynParam p = new DynParam(name, type); _dynParams.add(p); return true; } else return false; } public void addInputParams(Map pMap) { for (Object name : pMap.keySet()) { int type = Integer.parseInt((String) pMap.get(name)); addInputParam((String) name, type); } } public void addFilters(Set filters) { _filters.addAll(filters); } public void addFilter(AbstractFilter f) { _filters.add(f); } public void addConstraints(Set constraints) { _constraints.addAll(constraints); } public void addConstraint(AbstractConstraint c) { _constraints.add(c); } public void setFamiliarParticipantTask(String taskid) { _familiarParticipantTask = taskid; } public Set<Participant> getParticipants() { return _participants; } public Set<Role> getRoles() { return _roles; } public Set<AbstractFilter> getFilters() { return _filters; } public Set<AbstractConstraint> getConstraints() { return _constraints; } public Set<Participant> getDistributionSet() { return _distributionSet; } public Set<String> getDynParamNames() { Set<String> names = new HashSet<String>(); for (DynParam param : _dynParams) { names.add(param.getName() + "[" + param.getRefersString() + "]"); } return names; } /********************************************************************************/ /** * Takes the initial distribution set of participants, then expands any roles and/or * dynamic parameters to their 'set of participants' equivalents, then applies the * specified filters and/or constraints, and returns the final distribution set of * participants. * * @param wir the workitem being offered * @return the final distribution set of Participant objects */ public Set<Participant> performOffer(WorkItemRecord wir) { _distributionSet = new HashSet<Participant>(); // if familiar task specified, get the participant(s) who completed that task, // & offer this item to them - no more to do if (_familiarParticipantTask != null) { Set<Participant> pSet = _rm.getWhoCompletedTask(_familiarParticipantTask, wir); if (pSet != null) _distributionSet.addAll(pSet); } else { // make sure each participant is added only once ArrayList<String> uniqueIDs = new ArrayList<String>(); // add Participants for (Participant p : _participants) { uniqueIDs.add(p.getID()); _distributionSet.add(p); } // add roles for (Role role : _roles) { Set<Participant> pSet = _rm.getOrgDataSet().castToParticipantSet(role.getResources()); pSet.addAll(_rm.getOrgDataSet().getParticipantsInDescendantRoles(role)); for (Participant p : pSet) { addParticipantToDistributionSet(_distributionSet, uniqueIDs, p); } } // add dynamic params for (DynParam param : _dynParams) { Set<Participant> pSet = param.evaluate(wir); for (Participant p : pSet) { addParticipantToDistributionSet(_distributionSet, uniqueIDs, p); } } // apply each filter for (AbstractFilter filter : _filters) _distributionSet = (HashSet<Participant>) filter.performFilter(_distributionSet); // apply each constraint for (AbstractConstraint constraint : _constraints) _distributionSet = (HashSet<Participant>) constraint.performConstraint(_distributionSet, wir); } // ok - got our final set return _distributionSet; } public void withdrawOffer(WorkItemRecord wir, Set<Participant> offeredSet) { if (offeredSet != null) { for (Participant p : offeredSet) { p.getWorkQueues().removeFromQueue(wir, WorkQueue.OFFERED); _rm.announceModifiedQueue(p.getID()); } } // a fired instance of a multi-instance workitem on the unoffered queue will // never have been offered, so the warning should be suppressed for those else if (!wir.getStatus().equals(WorkItemRecord.statusFired)) { _log.warn("Workitem '{}' does not have 'Offered' status, " + "or is no longer active", wir.getID()); } } private void addParticipantToDistributionSet(HashSet<Participant> distributionSet, ArrayList<String> uniqueIDs, Participant p) { if (!uniqueIDs.contains(p.getID())) { uniqueIDs.add(p.getID()); distributionSet.add(p); } } /********************************************************************************/ // Resource Specification Offer Parsing Methods // public void parse(Element e, Namespace nsYawl) throws ResourceParseException { parseInitiator(e, nsYawl); // if offer is not system-initiated, there's no more to do if (!isSystemInitiated()) return; parseDistributionSet(e, nsYawl); parseFamiliarTask(e, nsYawl); } private void parseDistributionSet(Element e, Namespace nsYawl) throws ResourceParseException { Element eDistSet = e.getChild("distributionSet", nsYawl); if (eDistSet != null) { parseInitialSet(eDistSet, nsYawl); parseFilters(eDistSet, nsYawl); parseConstraints(eDistSet, nsYawl); } else throw new ResourceParseException("Missing required element in Offer block: distributionSet"); } private void parseInitialSet(Element e, Namespace nsYawl) throws ResourceParseException { Element eInitialSet = e.getChild("initialSet", nsYawl); if (eInitialSet != null) { parseParticipants(eInitialSet, nsYawl); parseRoles(eInitialSet, nsYawl); parseDynParams(eInitialSet, nsYawl); } else throw new ResourceParseException( "Missing required distributionSet child element in Offer block: initialSet"); } private void parseParticipants(Element e, Namespace nsYawl) { // from the specified initial set, add all participants for (Element eParticipant : e.getChildren("participant", nsYawl)) { String participant = eParticipant.getText(); if (participant.indexOf(',') > -1) addParticipantsByID(participant); else addParticipant(participant); } } private void parseRoles(Element e, Namespace nsYawl) { // ... and roles for (Element eRole : e.getChildren("role", nsYawl)) { String role = eRole.getText(); if (role.indexOf(',') > -1) addRoles(role); else addRole(role); } } private void parseDynParams(Element e, Namespace nsYawl) { // ... and input parameters for (Element eParam : e.getChildren("param", nsYawl)) { String name = eParam.getChildText("name", nsYawl); String refers = eParam.getChildText("refers", nsYawl); int pType = refers.equals("role") ? ROLE_PARAM : USER_PARAM; addInputParam(name, pType); } } private void parseFilters(Element e, Namespace nsYawl) throws ResourceParseException { // get the Filters Element eFilters = e.getChild("filters", nsYawl); if (eFilters != null) { List<Element> filters = eFilters.getChildren("filter", nsYawl); if (filters == null) throw new ResourceParseException("No filter elements found in filters element"); for (Element eFilter : filters) { String filterClassName = eFilter.getChildText("name", nsYawl); if (filterClassName != null) { AbstractFilter filter = PluginFactory.newFilterInstance(filterClassName); if (filter != null) { filter.setParams(parseParams(eFilter, nsYawl)); _filters.add(filter); } else throw new ResourceParseException("Unknown filter name: " + filterClassName); } else throw new ResourceParseException("Missing filter element: name"); } } } private void parseConstraints(Element e, Namespace nsYawl) throws ResourceParseException { // get the Constraints Element eConstraints = e.getChild("constraints", nsYawl); if (eConstraints != null) { List<Element> constraints = eConstraints.getChildren("constraint", nsYawl); if (constraints == null) throw new ResourceParseException("No constraint elements found in constraints element"); for (Element eConstraint : constraints) { String constraintClassName = eConstraint.getChildText("name", nsYawl); if (constraintClassName != null) { AbstractConstraint constraint = PluginFactory.newConstraintInstance(constraintClassName); if (constraint != null) { constraint.setParams(parseParams(eConstraint, nsYawl)); _constraints.add(constraint); } else throw new ResourceParseException("Unknown constraint name: " + constraintClassName); } else throw new ResourceParseException("Missing constraint element: name"); } } } private void parseFamiliarTask(Element e, Namespace nsYawl) { // finally, get the familiar participant task Element eFamTask = e.getChild("familiarParticipant", nsYawl); if (eFamTask != null) _familiarParticipantTask = eFamTask.getAttributeValue("taskID"); } /********************************************************************************/ public String toXML() { StringBuilder xml = new StringBuilder("<offer "); xml.append("initiator=\"").append(getInitiatorString()).append("\">"); // the rest of the xml is only needed if it's system initiated if (isSystemInitiated()) { xml.append("<distributionSet>"); xml.append("<initialSet>"); if (_participants != null) { for (Participant p : _participants) { xml.append("<participant>").append(p.getID()).append("</participant>"); } } if (_roles != null) { for (Role r : _roles) { xml.append("<role>").append(r.getID()).append("</role>"); } } if (_dynParams != null) { for (DynParam p : _dynParams) { xml.append(p.toXML()); } } xml.append("</initialSet>"); if ((_filters != null) && (!_filters.isEmpty())) { xml.append("<filters>"); for (AbstractFilter filter : _filters) { xml.append(filter.toXML()); } xml.append("</filters>"); } if ((_constraints != null) && (!_constraints.isEmpty())) { xml.append("<constraints>"); for (AbstractConstraint constraint : _constraints) { xml.append(constraint.toXML()); } xml.append("</constraints>"); } xml.append("</distributionSet>"); if (_familiarParticipantTask != null) { xml.append("<familiarParticipant taskID=\""); xml.append(_familiarParticipantTask).append("\"/>"); } } xml.append("</offer>"); return xml.toString(); } /*******************************************************************************/ /*******************************************************************************/ /** * A class that encapsulates one dynamic parameter - i.e. a data variable that at * runtime will contain a value corresponding to a participant or role that the * task is to be offered to. */ private class DynParam { private String _name; // the name of the data variable private int _refers; // participant or role /** the constructor * * @param name - the name of a data variable of this task that will contain * a runtime value specifying a particular participant or role. * @param refers - either USER_PARAM or ROLE_PARAM */ public DynParam(String name, int refers) { _name = name; _refers = refers; } /*******************************************************************************/ // GETTERS & SETTERS // public String getName() { return _name; } public int getRefers() { return _refers; } public void setName(String name) { _name = name; } public void setRefers(int refers) { _refers = refers; } public String getRefersString() { if (_refers == USER_PARAM) return "participant"; else return "role"; } public Set<Participant> evaluate(WorkItemRecord wir) { HashSet<Participant> result = new HashSet<Participant>(); if (_refers == USER_PARAM) { for (String varID : getVarIDList(wir)) { Participant p = _rm.getParticipantFromUserID(varID); if (p != null) result.add(p); else _log.error("Unknown participant userID '{}'" + " in dynamic parameter: {}", varID, _name); } } else { for (String varID : getVarIDList(wir)) { Role r = _rm.getOrgDataSet().getRoleByName(varID); if (r != null) { Set<Participant> rpSet = _rm.getOrgDataSet().getRoleParticipants(r.getID()); if (rpSet != null) result.addAll(rpSet); } else _log.error("Unknown role '{}'" + " in dynamic parameter: {}", varID, _name); } } return result; } private String getNetParamValue(WorkItemRecord wir, String name) { String result = null; try { result = _rm.getNetParamValue(wir.getCaseID(), _name); if (result == null) _log.error("Unable to retrieve value from net parameter '{}'" + " for deferred allocation of workitem '{}'.", name, wir.getID()); } catch (IOException ioe) { _log.error("Caught exception attempting to retrieve value from net " + "parameter '{}' for deferred allocation of workitem '{}'.", name, wir.getID()); } return result; } private List<String> getVarIDList(WorkItemRecord wir) { List<String> idList = new ArrayList<String>(); String varValue = getNetParamValue(wir, _name); if (varValue != null) { for (String id : varValue.split(",")) { idList.add(id.trim()); } } return idList; } /*******************************************************************************/ /** this is for the spec file */ public String toXML() { StringBuilder xml = new StringBuilder("<param>"); xml.append("<name>").append(_name).append("</name>"); xml.append("<refers>").append(getRefersString()).append("</refers>"); xml.append("</param>"); return xml.toString(); } } // end of private class DynParam /*******************************************************************************/ }