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.io.BufferedReader;
030: import java.io.IOException;
031: import java.io.InputStreamReader;
032: import java.io.Reader;
033: import java.io.StreamTokenizer;
034:
035: import org.cougaar.planning.ldm.asset.NewPropertyGroup;
036: import org.cougaar.util.log.Logger;
037: import org.cougaar.util.log.Logging;
038:
039: /**
040: * Parses local asset prototype-ini.dat to create local asset and the
041: * Report tasks associated with all the local asset's relationships.
042: * Local asset must have ClusterPG and RelationshipPG, Presumption is
043: * that the 'other' assets in all the relationships have both Cluster
044: * and Relationship PGs. Currently assumes that each Agent has
045: * exactly 1 local asset.
046: *
047: * Format:
048: * <xxx> - parameter
049: * # - comment character - rest of line ignored
050: *
051: * Skeleton form:
052: * [Prototype]
053: * <asset_class_name> # asset class must have both a ClusterPG and a RelationshipPG
054: *
055: * [Relationship]
056: * # <role> specifies Role played by this asset for another asset.
057: * # If start/end be specified as "", they default to
058: * # TimeSpan.MIN_VALUE/TimeSpan.MAX_VALUE
059: * <role> <other asset item id> <other asset type id> <other asset agent id> <relationship start time> <relationship end time>
060: *
061: * [<PG name>]
062: * # <slot type> - one of Collection<data type>, List<data type>, String, Integer, Double, Boolean,
063: * # Float, Long, Short, Byte, Character
064: *
065: * <slot name> <slot type> <slot values>
066: *
067: * Sample:
068: * [Prototype]
069: * Entity
070: *
071: * [Relationship]
072: * "Subordinate" "Headquarters" "Management" "HQ" "01/01/2001 12:00 am" "01/01/2010 11:59 pm"
073: * "PaperProvider" "Beth's Day Care" "Day Care Ctr" "Beth's Home" "02/13/2001 9:00 am" ""
074: *
075: * [ItemIdentificationPG]
076: * ItemIdentification String "Staples, Inc"
077: * Nomenclature String "Staples"
078: * AlternateItemIdentification String "SPLS"
079: *
080: * [TypeIdentificationPG]
081: * TypeIdentification String "Office Goods Supplier"
082: * Nomenclature String "Big Box"
083: * AlternateTypeIdentification String "Stationer"
084: *
085: * [ClusterPG]
086: * MessageAddress MessageAddress "Staples"
087: *
088: * [EntityPG]
089: * Roles Collection<Role> "Subordinate, PaperProvider, CrayonProvider, PaintProvider"
090: *
091: **/
092: public class AssetDataFileReader implements AssetDataReader {
093: private AssetDataCallback cb;
094: private String agentId;
095: private static Logger logger = Logging
096: .getLogger(AssetDataFileReader.class);
097:
098: public String getFileName() {
099: return agentId + "-prototype-ini.dat";
100: }
101:
102: /**
103: *
104: */
105: public void readAsset(String aId, AssetDataCallback cb) {
106: this .cb = cb;
107: agentId = aId;
108: String dataItem = "";
109: int newVal;
110:
111: String filename = getFileName();
112: BufferedReader input = null;
113: Reader fileStream = null;
114:
115: try {
116: fileStream = new InputStreamReader(cb.getConfigFinder()
117: .open(filename));
118: input = new BufferedReader(fileStream);
119: StreamTokenizer tokens = new StreamTokenizer(input);
120: tokens.commentChar('#');
121: tokens.wordChars('[', ']');
122: tokens.wordChars('_', '_');
123: tokens.wordChars('<', '>');
124: tokens.wordChars('/', '/');
125: tokens.ordinaryChars('0', '9');
126: tokens.wordChars('0', '9');
127:
128: newVal = tokens.nextToken();
129: // Parse the prototype-ini file
130: while (newVal != StreamTokenizer.TT_EOF) {
131: if (tokens.ttype != StreamTokenizer.TT_WORD)
132: formatError("ttype: " + tokens.ttype + " sval: "
133: + tokens.sval);
134: dataItem = tokens.sval;
135: if (dataItem.equals("[Prototype]")) {
136: newVal = tokens.nextToken();
137: String assetClassName = tokens.sval;
138: cb.createMyLocalAsset(assetClassName);
139: newVal = tokens.nextToken();
140: continue;
141: }
142: if (!cb.hasMyLocalAsset())
143: formatError("Missing [Prototype] section");
144: if (dataItem.equals("[Relationship]")) {
145: newVal = fillRelationships(newVal, tokens);
146: continue;
147: }
148: if (dataItem.equals("[LocationSchedulePG]")) {
149: // parser language is currently incapable of expressing a
150: // complex schedule, so here we hack in some minimal support.
151: newVal = setLocationSchedulePG(dataItem, newVal,
152: tokens);
153: continue;
154: }
155: if (dataItem.startsWith("[")) {
156: // We've got a property or capability
157: newVal = setPropertyForAsset(dataItem, newVal,
158: tokens);
159: continue;
160: }
161: // if The token you read is not one of the valid
162: // choices from above
163: formatError("Incorrect token: " + dataItem);
164: }
165:
166: // Closing BufferedReader
167: if (input != null)
168: input.close();
169:
170: // Only generates a NoSuchMethodException for AssetSkeleton
171: // because of a coding error. If we are successul in creating it
172: // here it then the AssetSkeleton will end up with two copies
173: // the add/search criteria in AssetSkeleton is for a Vector and
174: // does not gurantee only one instance of each class. Thus the
175: // Org allocator plugin fails to recognize the correct set of
176: // capabilities.
177:
178: } catch (Exception e) {
179: e.printStackTrace();
180: }
181: }
182:
183: private void formatError(String msg) {
184: throw new RuntimeException("Error parsing " + getFileName()
185: + ": " + msg);
186: }
187:
188: /**
189: * Creates the property, fills in the slots based on what's in the
190: * prototype-ini file and then sets it for (or adds it to) the asset
191: **/
192: protected int setPropertyForAsset(String prop, int newVal,
193: StreamTokenizer tokens) throws IOException {
194: String propertyName = prop.substring(1, prop.length() - 1)
195: .trim();
196: NewPropertyGroup propertyGroup = null;
197: try {
198: propertyGroup = cb.createPropertyGroup(propertyName);
199: } catch (Exception e) {
200: formatError("Unrecognized keyword for a prototype-ini file: ["
201: + propertyName + "]");
202: return StreamTokenizer.TT_EOF;
203: }
204: try {
205: newVal = tokens.nextToken();
206: String member = tokens.sval;
207: // Parse through the property section of the file
208: while (newVal != StreamTokenizer.TT_EOF) {
209: if ((tokens.ttype == StreamTokenizer.TT_WORD)
210: && !(tokens.sval.substring(0, 1).equals("["))) {
211: newVal = tokens.nextToken();
212: String dataType = tokens.sval;
213: newVal = tokens.nextToken();
214: // Call appropriate setters for the slots of the property
215: Object[] args = new Object[] { cb.parseExpr(
216: dataType, tokens.sval) };
217: cb.callSetter(propertyGroup, "set" + member, cb
218: .getType(dataType), args);
219: newVal = tokens.nextToken();
220: member = tokens.sval;
221: } else {
222: // Reached a left bracket "[", want to exit block
223: break;
224: }
225: } //while
226:
227: // Add the property to the asset
228: cb.addPropertyToAsset(propertyGroup);
229: } catch (IOException e) {
230: throw e;
231: } catch (Exception e) {
232: e.printStackTrace();
233: formatError("Exception during parse");
234: }
235: return newVal;
236: }
237:
238: /**
239: * Hack to attach a LocationSchedulePG to an Asset.
240: * <pre>
241: * For now we only support a single LocationScheduleElementImpl
242: * which has a LatLonPointImpl as it's Location. The TimeSpan
243: * is hard-coded to TimeSpan.MIN_VALUE .. TimeSpan.MAX_VALUE.
244: * In the future this can be enhanced to support full location
245: * schedules, but that would likely require a new file format.
246: *
247: * The format is:
248: * "FixedLocation \"(" + LATITUDE + ", " + LONGITUDE + ")\""
249: *
250: * For example, all of time at latitude 12.3 longitude -45.6:
251: * FixedLocation "(12.3, -45.6)"
252: * </pre>
253: */
254: protected int setLocationSchedulePG(String prop, int newVal,
255: StreamTokenizer tokens) throws IOException {
256: // read two strings
257: String firstStr;
258: String secondStr;
259: newVal = tokens.nextToken();
260: if ((newVal == StreamTokenizer.TT_EOF)
261: || (tokens.sval.substring(0, 1).equals("["))) {
262: // Reached a left bracket "[", want to exit block
263: return newVal;
264: }
265: firstStr = tokens.sval;
266:
267: newVal = tokens.nextToken();
268: if ((newVal == StreamTokenizer.TT_EOF)
269: || (tokens.sval.substring(0, 1).equals("["))) {
270: // Reached a left bracket "[", want to exit block
271: return newVal;
272: }
273: secondStr = tokens.sval;
274:
275: newVal = tokens.nextToken();
276:
277: // skip "FixedLocation " string
278: if (!(firstStr.equals("FixedLocation"))) {
279: logger.error("Expecting: FixedLocation \"(LAT, LON)\"\n"
280: + "Not: " + firstStr + " .. ");
281: return newVal;
282: }
283:
284: // parse single Location
285: if ((!(secondStr.startsWith("(")))
286: || (!(secondStr.endsWith(")")))) {
287: logger.error("Expecting: FixedLocation \"(LAT, LON)\"\n"
288: + "Not: FixedLocation " + secondStr + " ..");
289: logger.error("SWith(: " + secondStr.startsWith("("));
290: logger.error("EWith): " + secondStr.endsWith(")"));
291: return newVal;
292: }
293: String locStr = secondStr.substring(1, secondStr.length() - 1);
294: int sepIdx = locStr.indexOf(",");
295: if (sepIdx < 0)
296: formatError("Bad Location syntax: " + locStr);
297: String latStr = locStr.substring(0, sepIdx).trim();
298: String lonStr = locStr.substring(sepIdx + 1).trim();
299: cb.setLocationSchedule(latStr, lonStr);
300: // done
301: return newVal;
302: }
303:
304: /**
305: * Fills in myRelationships with arrays of relationship, agentName and capableroles triples.
306: */
307: protected int fillRelationships(int newVal, StreamTokenizer tokens)
308: throws IOException {
309: newVal = tokens.nextToken();
310: while ((newVal != StreamTokenizer.TT_EOF)
311: && (!tokens.sval.substring(0, 1).equals("["))) {
312:
313: String roleName = "";
314: String itemId = "";
315: String typeId = "";
316: String otherAgentId = "";
317: long start = cb.getDefaultStartTime();
318: long end = cb.getDefaultEndTime();
319:
320: for (int i = 0; i < 6; i++) {
321: if ((tokens.sval.length()) > 0
322: && (tokens.sval.substring(0, 1).equals("["))) {
323: throw new RuntimeException("Unexpected character: "
324: + tokens.sval);
325: }
326:
327: switch (i) {
328: case 0:
329: roleName = tokens.sval.trim();
330: break;
331:
332: case 1:
333: itemId = tokens.sval.trim();
334: break;
335:
336: case 2:
337: typeId = tokens.sval.trim();
338: break;
339:
340: case 3:
341: otherAgentId = tokens.sval.trim();
342: break;
343:
344: case 4:
345: if (!tokens.sval.equals("")) {
346: try {
347: start = cb.parseDate(tokens.sval);
348: } catch (java.text.ParseException pe) {
349: logger.error("Unable to parse: "
350: + tokens.sval
351: + ". Start time defaulting to "
352: + cb.getDefaultStartTime());
353: }
354: }
355: break;
356:
357: case 5:
358: if (!tokens.sval.equals("")) {
359: try {
360: end = cb.parseDate(tokens.sval);
361: } catch (java.text.ParseException pe) {
362: logger.error("Unable to parse: "
363: + tokens.sval
364: + ". End time defaulting to "
365: + cb.getDefaultEndTime());
366: }
367: }
368: break;
369: }
370: newVal = tokens.nextToken();
371: }
372: cb.addRelationship(typeId, itemId, otherAgentId, roleName,
373: start, end);
374: } //while
375: return newVal;
376: }
377: }
|