001: /*
002: * <copyright>
003: *
004: * Copyright 1997-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:
027: package org.cougaar.planning.plugin.asset;
028:
029: import java.util.Collection;
030: import java.util.HashMap;
031: import java.util.Iterator;
032: import java.util.NoSuchElementException;
033: import java.util.StringTokenizer;
034:
035: import org.cougaar.planning.ldm.asset.NewPropertyGroup;
036: import org.cougaar.planning.service.AssetInitializerService;
037: import org.cougaar.util.log.Logger;
038: import org.cougaar.util.log.Logging;
039:
040: /**
041: * Parses a set of parameters to create local asset.
042: * Relationships must also be passed as parameters but will be handled by the
043: * AssetDataPlugin. See AssetDataPlugin for format of Relationship parameters.
044: *
045: * Recognized Parameter Formats:
046: * Prototype:<self org asset class> # Must be the first parameter
047: * Prototype parameter used to create the self org asse
048: *
049: * LocationSchedulePG:FixedLocation:(<lat>, <lon>)
050: * Very specific to LocationSchedulePG, creates a single
051: * LocationScheduleElementImpl which has a LatLonImpl as its Location. The
052: * TimeSpan to hardcoded to run from TimeSpan.MIN_VALUE to TimeSpan.MAX_VALUE
053: *
054: * <property group name>:<slot name>:<data type>:<data value>
055: * General format for setting a slot on one of the self orgs property groups. Must
056: * have a parameter for each slot on each property group.
057: *
058: * Sample:
059: * Prototype:Organization
060: * ItemIdentificationPG:ItemIdentification:String:Staples, Inc
061: * ItemIdentificationPG:Nomenclature:String:Staples
062: * ItemIdentificationPG:AlternateItemIdentification:String:SPLS
063: * TypeIdentificationPG:TypeIdentification:String:Office Goods Supplier
064: * TypeIdentificationPG:Nomenclature String:Big Box
065: * TypeIdentificationPG:AlternateTypeIdentification:String:Stationer
066: * ClusterPG:MessageAddress:MessageAddress:Staples
067: * OrganizationPG:Roles:Collection<Role>:Subordinate, PaperProvider, CrayonProvider, PaintProvider
068: * LocationSchedulePG:FixedLocation:(31.8500, -81.6000)
069: *
070: * <em>Note that when using XSLNode, instead of < and >, use < and ></em>
071: *
072: **/
073: public class AssetDataParamReader implements AssetDataReader {
074: private AssetDataCallback cb;
075: private String agentId;
076: private static Logger logger = Logging
077: .getLogger(AssetDataParamReader.class);
078: private Collection myParams;
079: private HashMap myPropertyGroups = new HashMap();
080: AssetInitializerService assetInitService = null;
081:
082: public AssetDataParamReader(Collection params,
083: AssetInitializerService ais) {
084: myParams = params;
085: assetInitService = ais;
086: }
087:
088: public static final String ATTRIBUTE_DELIMITER = ":";
089: public static final String PROTOTYPE_KEY = "Prototype";
090: public static final String RELATIONSHIP_KEY = "Relationship";
091:
092: /**
093: *
094: */
095: public void readAsset(String aId, AssetDataCallback cb) {
096: this .cb = cb;
097: agentId = aId;
098:
099: for (Iterator iterator = myParams.iterator(); iterator
100: .hasNext();) {
101: String param = (String) iterator.next();
102: StringTokenizer tokenizer = new StringTokenizer(param,
103: ATTRIBUTE_DELIMITER);
104:
105: if (logger.isDebugEnabled()) {
106: logger.debug("Parameter: " + param + " token count: "
107: + tokenizer.countTokens());
108: }
109:
110: String nextAttribute = tokenizer.nextToken();
111:
112: if (logger.isDebugEnabled()) {
113: logger.debug("Attribute: " + nextAttribute);
114: }
115:
116: if (nextAttribute == null) {
117: logger.error("Unable to parse parameter: " + param);
118: continue;
119: }
120:
121: if (nextAttribute.equals(PROTOTYPE_KEY)) {
122: nextAttribute = tokenizer.nextToken();
123: if (logger.isDebugEnabled()) {
124: logger.debug("Prototype: " + nextAttribute);
125: }
126: cb.createMyLocalAsset(nextAttribute);
127: continue;
128: }
129:
130: if (!cb.hasMyLocalAsset()) {
131: logger
132: .error("Prototype parameter must be first. Parameter "
133: + param + " will be ignored.");
134: continue;
135: }
136:
137: if (nextAttribute.equals(AssetDataPlugin.RELATIONSHIP_KEY)) {
138: if (logger.isDebugEnabled()) {
139: logger
140: .debug("AssetDataParamReader: Skipping relationship: "
141: + param);
142: }
143: continue;
144: }
145:
146: if (nextAttribute.equals("LocationSchedulePG")) {
147: // parser language is currently incapable of expressing a
148: // complex schedule, so here we hack in some minimal support.
149: setLocationSchedulePG(param, tokenizer);
150: continue;
151: }
152:
153: // Must be a PG
154: if (logger.isDebugEnabled()) {
155: logger.debug("Property group: " + param
156: + " nextAttribute " + nextAttribute);
157: }
158: setPropertyForAsset(param, nextAttribute, tokenizer);
159: }
160:
161: //Add all property groups
162: for (Iterator iterator = myPropertyGroups.values().iterator(); iterator
163: .hasNext();) {
164: cb.addPropertyToAsset((NewPropertyGroup) iterator.next());
165: }
166: }
167:
168: /**
169: * Creates the property, fills in the slots based on what's in the
170: * prototype-ini file and then sets it for (or adds it to) the asset
171: **/
172: protected void setPropertyForAsset(String param, String pgName,
173: StringTokenizer tokenizer) {
174: NewPropertyGroup propertyGroup = (NewPropertyGroup) myPropertyGroups
175: .get(pgName);
176:
177: if (propertyGroup == null) {
178: try {
179: propertyGroup = cb.createPropertyGroup(pgName);
180: myPropertyGroups.put(pgName, propertyGroup);
181: } catch (Exception e) {
182: logger.error("Unrecognized property group name "
183: + pgName + ". Parameter - " + param
184: + " will be ignored.");
185: return;
186: }
187: }
188:
189: try {
190: String slotName = tokenizer.nextToken();
191:
192: String dataType = tokenizer.nextToken();
193:
194: String val = ((String) tokenizer.nextToken()).trim();
195:
196: // For the MilitaryOrgPG:HomeLocation we want the ability to look up
197: // the geoloc and get the various detailed attributes.
198: // So lets hope this assetInitService if available can do that
199: if (dataType.startsWith("query")
200: && assetInitService != null) {
201: try {
202: Object[] r = assetInitService
203: .translateAttributeValue(dataType, val);
204: if (r[0] instanceof String)
205: dataType = (String) r[0];
206: val = (String) r[1];
207: } catch (Exception sqe) {
208: logger
209: .error(
210: agentId
211: + ": Unable to query init service for item of type "
212: + dataType
213: + ", with input value "
214: + val, sqe);
215: }
216: }
217:
218: Object[] args = new Object[] { cb.parseExpr(dataType, val) };
219:
220: // Call appropriate setters for the slots of the property
221: cb.callSetter(propertyGroup, "set" + slotName, cb
222: .getType(dataType), args);
223:
224: } catch (NoSuchElementException nsee) {
225: logger
226: .error("Unable to parse property group setting. Parameter "
227: + " will be ignored.");
228: }
229: return;
230: }
231:
232: public static final String FIXEDLOCATION = "FixedLocation";
233:
234: /**
235: * Hack to attach a LocationSchedulePG to an Asset.
236: * <pre>
237: * For now we only support a single LocationScheduleElementImpl
238: * which has a LatLonPointImpl as it's Location. The TimeSpan
239: * is hard-coded to TimeSpan.MIN_VALUE .. TimeSpan.MAX_VALUE.
240: * In the future this can be enhanced to support full location
241: * schedules, but that would likely require a new file format.
242: *
243: * The format is:
244: * "FixedLocation:\"(" + LATITUDE + ", " + LONGITUDE + ")\""
245: *
246: * For example, all of time at latitude 12.3 longitude -45.6:
247: * FixedLocation:"(12.3, -45.6)"
248: * </pre>
249: */
250: protected void setLocationSchedulePG(String param,
251: StringTokenizer tokenizer) {
252: try {
253: String nextToken = tokenizer.nextToken();
254:
255: // skip "FixedLocation " string
256: if (!(nextToken.equals(FIXEDLOCATION))) {
257: logger.error("Expecting: " + FIXEDLOCATION
258: + ATTRIBUTE_DELIMITER + "\"(LAT, LON)\"\n"
259: + "Not: " + nextToken + " .. ");
260: return;
261: }
262:
263: nextToken = tokenizer.nextToken();
264:
265: // parse single Location
266: if ((!(nextToken.startsWith("(")))
267: || (!(nextToken.endsWith(")")))) {
268: logger.error("Expecting: " + FIXEDLOCATION
269: + ATTRIBUTE_DELIMITER + "\"(LAT, LON)\"\n"
270: + "Not: " + FIXEDLOCATION + nextToken + " ..");
271: return;
272: }
273:
274: String locationStr = nextToken.substring(1, nextToken
275: .length() - 1);
276:
277: int commaIndex = locationStr.indexOf(",");
278: if (commaIndex < 0) {
279: // formatError throws a RuntimeException
280: logger.error("Expecting: " + FIXEDLOCATION
281: + ATTRIBUTE_DELIMITER + "\"(LAT, LON)\"\n"
282: + "Not: " + FIXEDLOCATION + nextToken + " ..");
283: }
284:
285: String latStr = locationStr.substring(0, commaIndex).trim();
286: String lonStr = locationStr.substring(commaIndex + 1)
287: .trim();
288: cb.setLocationSchedule(latStr, lonStr);
289:
290: } catch (NoSuchElementException nsee) {
291: logger
292: .error("Unable to parse LocationSchedulePG parameter."
293: + "Expecting: "
294: + FIXEDLOCATION
295: + ATTRIBUTE_DELIMITER
296: + "\"(LAT, LON)\"\n"
297: + "Not: " + param);
298: }
299:
300: // done
301: return;
302: }
303: }
|