package vroom.optimization.online.jmsa.vrp; import java.util.ArrayList; import java.util.Collection; import java.util.ConcurrentModificationException; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.TimeUnit; import vroom.common.modeling.dataModel.Arc; import vroom.common.modeling.dataModel.ListRoute.ArrayListRoute; import vroom.common.modeling.dataModel.Depot; import vroom.common.modeling.dataModel.DynamicInstance; import vroom.common.modeling.dataModel.Fleet; import vroom.common.modeling.dataModel.IArc; import vroom.common.modeling.dataModel.INodeVisit; import vroom.common.modeling.dataModel.IPlanningPeriod; import vroom.common.modeling.dataModel.IVRPInstance; import vroom.common.modeling.dataModel.IVRPRequest; import vroom.common.modeling.dataModel.Node; import vroom.common.modeling.dataModel.NodeVisit; import vroom.common.modeling.dataModel.Solution; import vroom.common.modeling.dataModel.Vehicle; import vroom.common.modeling.dataModel.VehicleRoutingProblemDefinition; import vroom.common.modeling.util.CostCalculationDelegate; import vroom.common.utilities.ExtendedReentrantLock; import vroom.common.utilities.IObservable; import vroom.common.utilities.IObserver; import vroom.common.utilities.ObserverManager; import vroom.common.utilities.Update; import vroom.common.utilities.Utilities; import vroom.optimization.online.jmsa.IActualRequest; import vroom.optimization.online.jmsa.IInstance; import vroom.optimization.online.jmsa.MSAGlobalParameters; import vroom.optimization.online.jmsa.utils.MSALogging; /** * Creation date: Apr 29, 2010 - 10:59:22 AM<br/> * <code>VRPInstance</code> * * @author Victor Pillac, <a href="http://uniandes.edu.co">Universidad de Los Andes</a>-<a * href="http://copa.uniandes.edu.co">Copa</a> <a href="http://www.emn.fr">Ecole des Mines de Nantes</a>-<a * href="http://www.irccyn.ec-nantes.fr/irccyn/d/en/equipes/Slp">SLP</a> * @version 2.0 */ public class MSAVRPInstance implements IInstance, IVRPInstance, IObservable { /** The started state of vehicles */ private final boolean[] mVehicleStartedStates; /** The stopped state of vehicles */ private final boolean[] mVehicleStoppedStates; /** The current cost of each vehicle */ private final double[] mVehicleCosts; /** A mapping between requests and their id */ private final Map<Integer, VRPActualRequest> mAllRequests; /** A per vehicle list of the assigned visits */ private final LinkedList<?>[] mAssignedVisits; /** An overall list of assigned requests */ private final LinkedList<VRPActualRequest> mAllAssignedRequests; /** A per vehicle list of the assigned requests */ private final LinkedList<?>[] mAssignedRequests; /** An array containing the shrunk node associated with each vehicle */ private final VRPShrunkRequest[] mShrunkRequests; /** A list of the pending requests */ private final Set<VRPActualRequest> mPendingRequests; private final Set<IArc> mArcs; /** A mapping of the assigned status of requests */ private final Map<VRPActualRequest, Boolean> mAssignedStatus; /** A mapping of the served status of requests */ private final Map<VRPActualRequest, Boolean> mServedStatus; /** The underlying instance **/ private final DynamicInstance mInstance; /** The global parameters for the msa procedure */ private final MSAGlobalParameters mParameters; /** A cost helper wrapper used to handle shrunk nodes */ @SuppressWarnings("unused") private final MSAVRPCostHelperWrapper mCostHelper; /** * Getter for the underlying instance. * <p> * Should not be modified directly * </p> * * @return the underlying instance. */ public DynamicInstance getInstance() { return mInstance; } /** * @param instance * the wrapped instance */ public MSAVRPInstance(DynamicInstance instance, MSAGlobalParameters parameters) { super(); mObsHandler = new ObserverManager(this); mLock = new ExtendedReentrantLock(); mCostHelper = new MSAVRPCostHelperWrapper(); acquireLock(); mParameters = parameters; mInstance = instance; mVehicleStartedStates = new boolean[instance.getFleet().size()]; mVehicleStoppedStates = new boolean[instance.getFleet().size()]; mVehicleCosts = new double[getFleet().size()]; mAllRequests = new HashMap<Integer, VRPActualRequest>(); mPendingRequests = new HashSet<VRPActualRequest>(); mAllAssignedRequests = new LinkedList<VRPActualRequest>(); mAssignedRequests = new LinkedList<?>[instance.getFleet().size()]; mShrunkRequests = new VRPShrunkRequest[instance.getFleet().size()]; for (int v = 0; v < mShrunkRequests.length; v++) { mShrunkRequests[v] = new VRPShrunkRequest(instance.getFleet().getVehicle(v), this); } mServedStatus = new HashMap<VRPActualRequest, Boolean>(); mAssignedStatus = new HashMap<VRPActualRequest, Boolean>(); mAssignedVisits = new LinkedList<?>[instance.getFleet().size()]; for (int v = 0; v < mAssignedVisits.length; v++) { mAssignedVisits[v] = new LinkedList<NodeVisit>(); mAssignedRequests[v] = new LinkedList<VRPActualRequest>(); } mArcs = new HashSet<IArc>(); updateDepotVisits(); // Add the instance node visits as requests for (INodeVisit visit : getInstance().getNodeVisits()) { addNodeVisitInternal(visit); } // Register the depots as request (used when building a distinguished // plan) for (INodeVisit depot : getDepotsVisits()) { VRPActualRequest depotReq = (VRPActualRequest) depot; VRPActualRequest oldValue = mAllRequests.put(depotReq.getID(), depotReq); if (oldValue != null && !oldValue.equals(depotReq)) { MSALogging.getSetupLogger().warn("MSAVRPInstance.init: request id collision %s - %s", depotReq, oldValue); } } releaseLock(); } @Override public String getName() { return getInstance().getName(); } @Override public boolean isResourceStarted(int resourceId) { return mVehicleStartedStates[resourceId]; } @Override public boolean isResourceStopped(int resourceId) { return mVehicleStoppedStates[resourceId]; } @Override public void setResourceStarted(int resourceId, Object param) { checkLock(); mVehicleStartedStates[resourceId] = true; if (param instanceof INodeVisit && ((INodeVisit) param).isDepot()) { // Add the depot to the vehicle's served requests list VRPActualRequest req = new VRPActualRequest((INodeVisit) param); getAssignedRequestsInternal(resourceId).add(req); // getShrunkRequest(resourceId).shrunkRequest(req); getShrunkRequest(resourceId).markAsServed(); mServedStatus.put(req, true); } } @Override public void setResourceStopped(int resourceId, Object param) { checkLock(); mVehicleStoppedStates[resourceId] = true; if (param instanceof INodeVisit && ((INodeVisit) param).isDepot()) { // Add the depot to the vehicle's served requests list VRPActualRequest prev = getLastAssignedRequest(resourceId); VRPActualRequest req = new VRPActualRequest((INodeVisit) param); getAssignedRequestsInternal(resourceId).add(req); getShrunkRequest(resourceId).shrunkRequest(req); mServedStatus.put(req, true); // Update the cost // Update the vehicle costs if (prev != null) { mVehicleCosts[resourceId] += getCost(prev, ((INodeVisit) param), getFleet().getVehicle(resourceId)); } mObsHandler.notifyObservers(new RequestUpdate(resourceId, req, prev, RequestUpdate.Type.ASSIGNED)); } } @Override public boolean assignRequestToResource(IActualRequest request, int resourceId) { checkLock(); VRPActualRequest vrpReq = (VRPActualRequest) request; // Check if the request has already been assigned if (isRequestAssigned(vrpReq)) { MSALogging .getProcedureLogger() .warn("MSAVRPInstance.assignRequestToResource: Error - the request has already been assigned (req:%s v:%s)", vrpReq, resourceId); return false; } // Check if the last request to which the vehicle was assigned has // actually been served if (!getShrunkRequest(resourceId).isServed()) { MSALogging .getProcedureLogger() .warn("MSAVRPInstance.assignRequestToResource: Error - the vehicle has not served its last request (req:%s v:%s)", vrpReq, resourceId); return false; } if (!vrpReq.isDepot() && !mPendingRequests.contains(vrpReq)) { MSALogging .getProcedureLogger() .warn("MSAVRPInstance.assignRequestToResource: Error - the request doesnt appear in the pending list (req:%s v:%s)", vrpReq, resourceId); return false; } // Set the assigned flag mAssignedStatus.put(vrpReq, Boolean.TRUE); // Add the request to the vehicle's served requests list VRPActualRequest prev = getLastAssignedRequest(resourceId); getAssignedRequestsInternal(resourceId).add(vrpReq); getShrunkRequest(resourceId).shrunkRequest(vrpReq); // Add the request to the global served requests list mAllAssignedRequests.add(vrpReq); // Remove the request from the pending requests list mPendingRequests.remove(vrpReq); // Remove the corresponding node visit from the underlying instance getInstance().nodeVisited(vrpReq.getNodeVisit()); mObsHandler.notifyObservers(new RequestUpdate(resourceId, vrpReq, prev, RequestUpdate.Type.ASSIGNED)); return true; } @Override public VRPActualRequest getNodeVisit(int requestId) { VRPActualRequest req = mAllRequests.get(requestId); return req != null && req.isDepot() ? req.clone() : req; } @Override public List<VRPActualRequest> getPendingRequests() { return new ArrayList<VRPActualRequest>(mPendingRequests); } public Set<VRPActualRequest> getPendingRequestsSet() { return mPendingRequests; } @Override public List<VRPActualRequest> getServedRequests() { return new ArrayList<VRPActualRequest>(mAllAssignedRequests); } @Override public List<VRPActualRequest> getServedRequests(int resourceId) { return new ArrayList<VRPActualRequest>(getAssignedRequestsInternal(resourceId)); } @Override public boolean requestReleased(IActualRequest request) { boolean b = getInstance().addRequest(((VRPActualRequest) request).getParentRequest()); if (b) { addNodeVisitInternal((VRPActualRequest) request); mObsHandler.notifyObservers(new RequestUpdate(-1, (VRPActualRequest) request, null, RequestUpdate.Type.ADDED)); } return b; } /* * (non-Javadoc) * * @see vroom.common.modeling.dataModel.IVRPInstance#addRequests(java.util. * Collection ) */ @Override public boolean addRequests(Collection<IVRPRequest> requests) { boolean b = true; for (IVRPRequest request : requests) { b &= addRequest(request); } return b; } /** * Add a request to the data structures of this instance * * @param request */ protected void addNodeVisitInternal(INodeVisit visit) { checkLock(); VRPActualRequest request; if (visit instanceof VRPActualRequest) { request = (VRPActualRequest) visit; } else { request = mParameters.newInstance(VRPParameterKeys.ACTUAL_REQUEST_CLASS, visit); } // Adding arcs with the depots for (INodeVisit depot : getDepotsVisits()) { addArc(depot, request); } // Adding arcs with other nodes for (INodeVisit node : mAllRequests.values()) { addArc(node, request); } VRPActualRequest oldValue = mAllRequests.put(request.getID(), request); if (oldValue != null && !oldValue.equals(request)) { MSALogging.getSetupLogger().warn("MSAVRPInstance.addNodeVisitInternal: request id collision %s - %s", request, oldValue); } mPendingRequests.add(request); mAssignedStatus.put(request, Boolean.FALSE); mServedStatus.put(request, Boolean.FALSE); } @Override public boolean markRequestAsServed(IActualRequest request, int resourceId) { checkLock(); VRPActualRequest vrpReq = (VRPActualRequest) request; // Check that the request has previously been assigned if (!isRequestAssigned(vrpReq)) { MSALogging .getProcedureLogger() .warn("MSAVRPInstance.markRequestAsServed: Error - the request has not been previously assigned (req:%s v:%s)", vrpReq, resourceId); return false; } // Check that the request has not already been marked as served if (isRequestServed(vrpReq)) { MSALogging .getProcedureLogger() .warn("MSAVRPInstance.markRequestAsServed: Error - the request has already been marked as served (req:%s v:%s)", vrpReq, resourceId); return false; } // Check that the request is the last that was assigned to the resource if (getAssignedRequestsInternal(resourceId).isEmpty() || !getLastAssignedRequest(resourceId).equals(vrpReq)) { MSALogging .getProcedureLogger() .warn("MSAVRPInstance.markRequestAsServed: Error - the request is not the last request assign to the vehicle (req:%s lastReq:%s)", vrpReq, getAssignedRequestsInternal(resourceId) == null ? null : getAssignedRequestsInternal( resourceId).getLast()); return false; } // Update the served status mServedStatus.put(vrpReq, Boolean.TRUE); getShrunkRequest(resourceId).markAsServed(); // Update the vehicle costs int L = getServedRequests(resourceId).size(); if (L > 1) { mVehicleCosts[resourceId] += getCost(getAssignedRequestsInternal(resourceId).get(L - 2), getAssignedRequestsInternal(resourceId).get(L - 1), getFleet().getVehicle(resourceId)); } mObsHandler.notifyObservers(new RequestUpdate(resourceId, vrpReq, null, RequestUpdate.Type.SERVED)); return true; } /** * Getter for the shrunk request associated with a vehicle * * @param resouceId * the id of the vehicle * @return the shrunk request representing the current state of the vehicle */ public VRPShrunkRequest getShrunkRequest(int resouceId) { return mShrunkRequests[resouceId]; } /** * @param resourceId * @return the list containing the requests assigned to the specified resource */ @SuppressWarnings("unchecked") private LinkedList<VRPActualRequest> getAssignedRequestsInternal(int resourceId) { return (LinkedList<VRPActualRequest>) mAssignedRequests[resourceId]; } /** * @param resourceId * @return the last request assigned to the specified resource */ public VRPActualRequest getLastAssignedRequest(int resourceId) { if (getAssignedRequestsInternal(resourceId).isEmpty()) { return null; } else { return getAssignedRequestsInternal(resourceId).getLast(); } } /** * @param request * the considered request * @return <code>true</code> if a resource has been assigned to <code>request</code> */ public boolean isRequestAssigned(VRPActualRequest request) { if (request == null) { return true; } else if (!mAssignedStatus.containsKey(request)) { mAssignedStatus.put(request, Boolean.FALSE); return false; } else { return mAssignedStatus.get(request); } } /** * Served status of a request * * @param request * the considered request * @return <code>true</code> if <code>request</code> has been served by a vehicle */ public boolean isRequestServed(VRPActualRequest request) { if (request == null) { return true; } else if (!mServedStatus.containsKey(request)) { mServedStatus.put(request, Boolean.FALSE); return false; } else { return mServedStatus.get(request); } } /** * Getter for the vehicle load * <p/> * A vehicle compartment load is updated whenever a request is marked as served by this vehicle * * @param vehicleId * the considered vehicle id * @param compartment * the considered compartment * @return the current load of the specified compartment of the given vehicle * @see #markRequestAsServed(IActualRequest, int) * @see #getCurrentLoads(int) */ public double getCurrentLoad(int vehicleId, int compartment) { return getShrunkRequest(vehicleId).getDemand(compartment); } /** * Getter for the vehicle load for all compartments * <p/> * A vehicle compartment load is updated whenever a request is marked as served by this vehicle * * @param vehicleId * the considered vehicle id * @return the current load of the specified vehicle * @see #markRequestAsServed(IActualRequest, int) * @see #getCurrentLoad(int, int) */ public double[] getCurrentLoads(int vehicleId) { return getShrunkRequest(vehicleId).getDemands(); } /** * @param vehicleId * @return */ public double getCurrentCost(int vehicleId) { return mVehicleCosts[vehicleId]; } /** * Getter for the current mSolution. * <p/> * This method will return a {@link Solution} containing the current (or final is the MSA procedure is terminated) * routes associated with each vehicle. * * @return the current mSolution */ @Override public Solution<ArrayListRoute> getCurrentSolution() { Solution<ArrayListRoute> solution = new Solution<ArrayListRoute>(getInstance()); for (int r = 0; r < mAssignedRequests.length; r++) { ArrayListRoute route = new ArrayListRoute(solution, getFleet().getVehicle(r)); for (VRPActualRequest node : getAssignedRequestsInternal(r)) { route.appendNode(node); } solution.addRoute(route); } return solution; } // ------------------------------------ // ILockable interface implementation // ------------------------------------ /** A lock to be used by this instance */ private final ExtendedReentrantLock mLock; @Override public boolean tryLock(long timeout) { try { return getLockInstance().tryLock(timeout, TimeUnit.MILLISECONDS); } catch (InterruptedException e) { return false; } } @Override public void acquireLock() { try { if (!getLockInstance().tryLock(TRY_LOCK_TIMOUT, TRY_LOCK_TIMOUT_UNIT)) { throw new IllegalStateException(String.format( "Unable to acquire lock on this instance of %s (%s) after %s %s, owner: %s", this.getClass() .getSimpleName(), hashCode(), TRY_LOCK_TIMOUT, TRY_LOCK_TIMOUT_UNIT, getLockInstance() .getOwnerName())); } } catch (InterruptedException e) { throw new IllegalStateException(String.format("Unable to acquire lock on this instance of %s (%s)", this .getClass().getSimpleName(), hashCode()), e); } ; } @Override public void releaseLock() { mLock.unlock(); } @Override public boolean isLockOwnedByCurrentThread() { return mLock.isHeldByCurrentThread(); } @Override public ExtendedReentrantLock getLockInstance() { return mLock; } private void checkLock() throws ConcurrentModificationException { if (!isLockOwnedByCurrentThread()) { throw new ConcurrentModificationException(String.format( "The current thread (%s) does not have the lock on this object", Thread.currentThread())); } } // ------------------------------------ // ------------------------------------ // IVRPInstance interface implementation // ------------------------------------ private Set<INodeVisit> mDepotVisits; protected void updateDepotVisits() { mDepotVisits = new HashSet<INodeVisit>(); for (INodeVisit n : getInstance().getDepotsVisits()) { mDepotVisits.add(new VRPActualRequest(n)); } } @Override public boolean addRequest(IVRPRequest request) { boolean b = getInstance().addRequest(request); if (b) { if (request instanceof INodeVisit) { addNodeVisitInternal((INodeVisit) request); } else { for (INodeVisit visit : getInstance().getNodeVisits(request)) { addNodeVisitInternal(visit); } } } return b; } @Override public double getCost(INodeVisit origin, INodeVisit destination) { return getInstance().getCost(origin, destination); } @Override public double getCost(INodeVisit origin, INodeVisit destination, Vehicle vehicle) { return getInstance().getCost(origin, destination, vehicle); } @Override public Depot getDepot(int depotId) { return getInstance().getDepot(depotId); } @Override public int getDepotCount() { return getInstance().getDepotCount(); } @Override public Fleet<?> getFleet() { return getInstance().getFleet(); } @Override public double getInsertionCost(INodeVisit node, INodeVisit pred, INodeVisit succ, Vehicle vehicle) { return getInstance().getInsertionCost(node, pred, succ, vehicle); } @Override public Set<INodeVisit> getNodeVisits() { return Utilities.convertToSet(getPendingRequests()); } @Override public Set<IArc> getArcs() { return mArcs; } @Override public IPlanningPeriod getPlanningPeriod() { return getInstance().getPlanningPeriod(); } @Override public int getRequestCount() { return getInstance().getRequestCount(); } @Override public List<IVRPRequest> getRequests() { ArrayList<IVRPRequest> req = new ArrayList<IVRPRequest>(mPendingRequests.size()); for (VRPRequest r : mPendingRequests) { req.add(r.getParentRequest()); } return req; } @Override public IVRPRequest getRequest(int id) { return mAllRequests.get(id).getParentRequest(); } @Override public VehicleRoutingProblemDefinition getRoutingProblem() { return getInstance().getRoutingProblem(); } @Override public boolean isSymmetric() { return getInstance().isSymmetric(); } @Override public boolean removeRequest(IVRPRequest request) { boolean b = getInstance().removeRequest(request); if (b) { mObsHandler.notifyObservers(new RequestUpdate(-1, (VRPActualRequest) request, null, RequestUpdate.Type.REMOVED)); } return b; } @Override public void setCostHelper(CostCalculationDelegate costHelper) { getInstance().setCostHelper(costHelper); } @Override public void setDepots(List<Depot> depots) { getInstance().setDepots(depots); updateDepotVisits(); } @Override public void setFleet(Fleet<?> fleet) { getInstance().setFleet(fleet); } @Override public void setPlanningPeriod(IPlanningPeriod planningPeriod) { getInstance().setPlanningPeriod(planningPeriod); } @Override public void setSymmetric(boolean symmetric) { getInstance().setSymmetric(symmetric); } @Override public INodeVisit[] getNodeVisits(IVRPRequest request) { return getInstance().getNodeVisits(request); } /* * (non-Javadoc) * * @see vroom.common.modeling.dataModel.IVRPInstance#getDepotsVisits() */ @Override public Set<INodeVisit> getDepotsVisits() { return mDepotVisits; } /* * (non-Javadoc) * * @see vroom.common.modeling.dataModel.IVRPInstance#getCostHelper() */ @Override public CostCalculationDelegate getCostDelegate() { // return mCostHelper; return getInstance().getCostDelegate(); } /** * Add the arc(s) between node1 and node2. If the instance is {@link #isSymmetric() symmetric} then only one arc * (node1,node2) is added, otherwise both are added. * * @param node1 * @param node2 */ private void addArc(INodeVisit node1, INodeVisit node2) { if (node1.compareTo(node2) > 0) { INodeVisit tmp = node1; node1 = node2; node2 = tmp; } if (!Utilities.equal(node1, node2)) { mArcs.add(new Arc(node1, node2, getCostDelegate().getDistance(node1, node2), !isSymmetric())); if (!isSymmetric()) { mArcs.add(new Arc(node2, node1, getCostDelegate().getDistance(node2, node1), !isSymmetric())); } } } /* * (non-Javadoc) * * @see vroom.common.utilities.dataModel.IObjectWithID#getID() */ @Override public int getID() { return getInstance().getID(); } public class MSAVRPCostHelperWrapper extends CostCalculationDelegate { @Override public double getDistance(Node origin, Node destination) { return getDistanceInternal(origin, destination); } @Override public double getDistance(INodeVisit origin, INodeVisit destination) { double cost = 0; if (origin instanceof VRPShrunkRequest) { cost = ((VRPShrunkRequest) origin).getAggregatedCost(); cost /= ((VRPShrunkRequest) origin).getVehicle().getVariableCost(); origin = ((VRPShrunkRequest) origin).getNodeVisit(); } else if (destination instanceof VRPShrunkRequest) { destination = ((VRPShrunkRequest) destination).getFirstNode(); } return cost + super.getDistance(origin, destination); } @Override protected double getDistanceInternal(Node origin, Node destination) { return getInstance().getCostDelegate().getDistance(origin, destination); } @Override public double getCost(INodeVisit origin, INodeVisit destination, Vehicle vehicle) { double cost = 0; if (origin instanceof VRPShrunkRequest) { cost = ((VRPShrunkRequest) origin).getAggregatedCost(); origin = ((VRPShrunkRequest) origin).getNodeVisit(); } else if (destination instanceof VRPShrunkRequest) { destination = ((VRPShrunkRequest) destination).getFirstNode(); } return cost + super.getCost(origin, destination, vehicle); } @Override public double getCost(INodeVisit origin, INodeVisit destination) { double cost = 0; if (origin instanceof VRPShrunkRequest) { cost = ((VRPShrunkRequest) origin).getAggregatedCost(); origin = ((VRPShrunkRequest) origin).getNodeVisit(); } else if (destination instanceof VRPShrunkRequest) { destination = ((VRPShrunkRequest) destination).getFirstNode(); } return cost + super.getCost(origin, destination); } @Override public String getDistanceType() { return getCostDelegate().getDistanceType(); } @Override protected void precisionChanged() { throw new UnsupportedOperationException(); } } private final ObserverManager mObsHandler; @Override public void addObserver(IObserver o) { mObsHandler.addObserver(o); } @Override public void removeObserver(IObserver o) { mObsHandler.removeObserver(o); } @Override public void removeAllObservers() { mObsHandler.removeAllObservers(); } public static class RequestUpdate implements Update { public enum Type { ASSIGNED, SERVED, ADDED, REMOVED }; /** The resource **/ private final int mResource; /** * Getter for The resource * * @return the value of resource */ public int getResource() { return mResource; } /** The request **/ private final VRPActualRequest mRequest; /** * Getter for The request * * @return the value of request */ public VRPActualRequest getRequest() { return mRequest; } /** The previous request **/ private final VRPActualRequest mPrevRequest; /** * Getter for The previous request * * @return the value of prevRequest */ public VRPActualRequest getPrevRequest() { return mPrevRequest; } /** The type of update **/ private final Type mUpdateType; /** * Getter for The type of update * * @return the value of updateType */ public Type getUpdateType() { return mUpdateType; } @Override public String getDescription() { return String.format("%s assigned to %s", mResource, mRequest); } public RequestUpdate(int resource, VRPActualRequest request, VRPActualRequest prevRequest, Type updateType) { super(); mResource = resource; mRequest = request; mPrevRequest = prevRequest; mUpdateType = updateType; } } @Override public List<Depot> getDepots() { return mInstance.getDepots(); } }