001: /*
002: * <copyright>
003: *
004: * Copyright 2001-2004 BBNT Solutions, LLC
005: * under sponsorship of the Defense Advanced Research Projects
006: * Agency (DARPA).
007: *
008: * You can redistribute this software and/or modify it under the
009: * terms of the Cougaar Open Source License as published on the
010: * Cougaar Open Source Website (www.cougaar.org).
011: *
012: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
013: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
014: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
015: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
016: * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
017: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
018: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
019: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
020: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
021: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
022: * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
023: *
024: * </copyright>
025: */
026: package org.cougaar.logistics.plugin.trans;
027:
028: import org.cougaar.glm.ldm.asset.Organization;
029: import org.cougaar.glm.ldm.asset.GLMAsset;
030: import org.cougaar.glm.ldm.asset.TransportationRoute;
031: import org.cougaar.glm.ldm.plan.GeolocLocation;
032: import org.cougaar.planning.ldm.measure.Distance;
033: import org.cougaar.planning.ldm.asset.Asset;
034: import org.cougaar.planning.ldm.plan.Task;
035: import org.cougaar.planning.ldm.plan.Location;
036:
037: import org.cougaar.glm.ldm.asset.Container;
038: import org.cougaar.logistics.plugin.trans.GLMTransConst;
039:
040: import java.util.Date;
041: import java.util.Enumeration;
042: import java.util.HashSet;
043: import java.util.HashMap;
044: import java.util.Iterator;
045: import java.util.Map;
046: import java.util.Set;
047: import java.util.Vector;
048:
049: import org.cougaar.logistics.plugin.trans.tools.LocatorImpl;
050: import org.cougaar.logistics.plugin.trans.tools.PortLocatorImpl;
051:
052: /**
053: * <pre>
054: * Specific logic for dealing with backwards sea planning.
055: *
056: * Mainly involves worrying about POE and POD choice.
057: * </pre>
058: */
059: public class SequentialGlobalSeaPlugin extends
060: SequentialGlobalAirPlugin {
061: protected transient Set exceptions = new HashSet();
062: boolean useSeaRoutes = false;
063: protected transient Map routeCache = new HashMap();
064:
065: public void localSetup() {
066: super .localSetup();
067:
068: try {
069: useSeaRoutes = (getMyParams().hasParam("useSeaRoutes")) ? getMyParams()
070: .getBooleanParam("useSeaRoutes")
071: : true;
072: } catch (Exception e) {
073: warn("got really unexpected exception " + e);
074: }
075:
076: if (useSeaRoutes)
077: locator.setFactory(ldmf); // tell route finder the ldm factory to use
078:
079: if (isDebugEnabled())
080: debug("localSetup - this " + this + " prep helper "
081: + glmPrepHelper);
082: }
083:
084: protected String type() {
085: return "seaport";
086: }
087:
088: public Organization findOrgForMiddleStep(Task task) {
089: Organization org = null;
090: if (isAmmo((GLMAsset) task.getDirectObject())) {
091: org = findOrgWithRole(GLMTransConst.AMMO_SHIP_PACKER_ROLE);
092: if (org == null) {
093: org = findOrgWithRole(GLMTransConst.SHIP_PACKER_ROLE);
094: }
095: } else
096: org = findOrgWithRole(GLMTransConst.SHIP_PACKER_ROLE);
097:
098: if (org == null) {
099: error(getName()
100: + "findOrgForMiddleStep - No subordinate with role "
101: + GLMTransConst.SHIP_PACKER_ROLE);
102: return null;
103: }
104: return org;
105: }
106:
107: /**
108: * overridden from sequentialglobalairplugin
109: */
110: protected boolean allNecessaryAssetsReportedMiddleStep() {
111: Object org = findOrgWithRole(GLMTransConst.SHIP_PACKER_ROLE);
112: if (org == null) {
113: org = findOrgWithRole(GLMTransConst.AMMO_SHIP_PACKER_ROLE);
114: }
115:
116: return (org != null);
117: }
118:
119: /**
120: * An asset is an ammo container if it has a contents pg, since
121: * only the Ammo Packer put a contents pg on a container.
122: *
123: * NOTE : should call isContainer first!
124: */
125: protected boolean isAmmo(GLMAsset asset) {
126: return asset.hasContentsPG();
127: }
128:
129: /** don't include destination ports as POEs */
130: boolean startsAtPOE(Task task) {
131: String origin = glmPrepHelper.getFromLocation(task)
132: .getGeolocCode();
133: Object airport = locator.getAssetAtGeolocCode(origin);
134:
135: return (airport != null)
136: && !((PortLocatorImpl) locator)
137: .isKnownException((Asset) airport);
138: }
139:
140: /**
141: * <pre>
142: * Given a task, find the POE and POD for the task
143: * This will be a search among possible POEs and PODs for those that
144: * are closest to the FROM-TO pair on the parent task.
145: *
146: * The choice will be affected by the how long it takes
147: * to get from POE to POD.
148: * </pre>
149: * @param ignoredTask is ignored in this method
150: */
151: protected Location[] getPOEandPOD(Task parentTask, Task ignoredTask) {
152: Location[] locs = new Location[2];
153:
154: if (useSeaRoutes) {
155: TransportationRoute route = (TransportationRoute) glmPrepHelper
156: .getIndirectObject(parentTask,
157: GLMTransConst.SEAROUTE);
158:
159: locs[0] = route.getSource().getGeolocLocation();
160: locs[1] = route.getDestination().getGeolocLocation();
161:
162: if (isInfoEnabled()) {
163: info(getName()
164: + ".getPOEandPOD - getting route from "
165: + parentTask.getUID()
166: + " it starts at "
167: + locs[0]
168: + " and ends at "
169: + locs[1]
170: + " isAmmo "
171: + isAmmo((GLMAsset) parentTask
172: .getDirectObject()));
173: }
174: } else { // just use great circle calcs
175: warn("not using searoutes?");
176: locs[0] = getPOENearestToFromLocMiddleStep(parentTask);
177: locs[1] = getPOD(parentTask);
178: }
179:
180: return locs;
181: }
182:
183: Location getPOENearestToFromLocMiddleStep(Task parentTask) {
184: return ((PortLocatorImpl) locator)
185: .getPortNearestToFromLoc(parentTask);
186: }
187:
188: /** don't remove SEAROUTE prep -- need it for datagrabber output! */
189: protected void removePrepsFromMiddleStep(Task new_task) {
190: glmPrepHelper.removePrepNamed(new_task,
191: GLMTransConst.SEAROUTE_DISTANCE);
192: }
193:
194: /** Instantiate the Locator, which adds a LocationCallback */
195: protected void makeLocator() {
196: locator = new PortLocatorImpl(this , logger);
197: }
198:
199: private static final double MAX_SHIP_SPEED_KNOTS = 20.0;
200: private static final long MILLIS_PER_HOUR = 60 * 60 * 1000;
201: private static final long CONUS_PLANNING_FACTOR = 12 * MILLIS_PER_HOUR;
202:
203: protected Date getEarlyArrivalMiddleStep(Task task, Date best) {
204: Date mostEarly = prefHelper.getReadyAt(task);
205: Distance distance = (Distance) glmPrepHelper.getIndirectObject(
206: task, GLMTransConst.SEAROUTE_DISTANCE);
207: long approxSeaDur = (long) (distance.getNauticalMiles() / MAX_SHIP_SPEED_KNOTS); // in hours
208: long possibleEarly = best.getTime() - approxSeaDur
209: * MILLIS_PER_HOUR;
210:
211: // if the travel time is already probably too little to do the job,
212: // just try for the original early date
213: if (possibleEarly < mostEarly.getTime())
214: possibleEarly = mostEarly.getTime();
215: else
216: // otherwise, let's give CONUS a couple of days to do it
217: possibleEarly = mostEarly.getTime() + CONUS_PLANNING_FACTOR;
218:
219: return new Date(possibleEarly);
220: }
221: }
|