001: /**
002: * <copyright>
003: *
004: * Copyright 2002-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: */package org.cougaar.tools.csmart.util;
026:
027: import org.cougaar.core.mts.MessageAddress;
028: import org.cougaar.tools.csmart.core.cdata.AgentAssetData;
029: import org.cougaar.tools.csmart.core.cdata.PGPropData;
030: import org.cougaar.tools.csmart.core.cdata.PGPropMultiVal;
031: import org.cougaar.tools.csmart.core.cdata.PropGroupData;
032: import org.cougaar.tools.csmart.core.cdata.RelationshipData;
033: import org.cougaar.tools.csmart.ui.viewer.CSMART;
034: import org.cougaar.tools.csmart.ui.viewer.SocietyFinder;
035: import org.cougaar.util.ConfigFinder;
036: import org.cougaar.util.Reflect;
037: import org.cougaar.util.TimeSpan;
038: import org.cougaar.util.log.Logger;
039:
040: import java.io.BufferedReader;
041: import java.io.File;
042: import java.io.FileReader;
043: import java.io.IOException;
044: import java.io.InputStreamReader;
045: import java.io.Reader;
046: import java.io.StreamTokenizer;
047: import java.text.DateFormat;
048: import java.text.ParseException;
049: import java.util.ArrayList;
050: import java.util.Collection;
051: import java.util.Iterator;
052: import java.util.Vector;
053:
054: /**
055: * PrototypeParser: Parse Agent AssetData files
056: *
057: *
058: * Created: Thu Feb 21 13:36:49 2002
059: *
060: */
061: public class PrototypeParser {
062:
063: private Logger log;
064: private String agentId;
065: private DateFormat myDateFormat = DateFormat.getInstance();
066: private boolean haveItemId = false;
067:
068: private static TrivialTimeSpan ETERNITY = new TrivialTimeSpan(
069: TimeSpan.MIN_VALUE, TimeSpan.MAX_VALUE);
070:
071: public PrototypeParser() {
072: log = CSMART.createLogger(this .getClass().getName());
073: }
074:
075: /**
076: * @param agentName name of agent to get data for
077: */
078: public static AgentAssetData parse(String agentName) {
079: PrototypeParser pp = new PrototypeParser();
080: return pp.parsePrototypeFile(agentName);
081: }
082:
083: public String getFileName() {
084: return agentId + "-prototype-ini.dat";
085: }
086:
087: public long parseDate(String dateString) throws ParseException {
088: return myDateFormat.parse(dateString).getTime();
089: }
090:
091: public long getDefaultStartTime() {
092: return TimeSpan.MIN_VALUE;
093: }
094:
095: public long getDefaultEndTime() {
096: return TimeSpan.MAX_VALUE;
097: }
098:
099: public AgentAssetData parsePrototypeFile(String aId) {
100: agentId = aId;
101: String dataItem = "";
102: int newVal;
103:
104: String filename = getFileName();
105: BufferedReader input = null;
106: Reader fileStream = null;
107: AgentAssetData aad = new AgentAssetData(null);
108: if (log.isDebugEnabled()) {
109: log.debug("Setting INI Format to: OLD_FORMAT");
110: }
111: aad.setIniFormat(AgentAssetData.OLD_FORMAT);
112:
113: try {
114: File tryfile = new File(filename);
115: if (!tryfile.exists()) {
116: fileStream =
117: // new InputStreamReader(ConfigFinder.getInstance().open(filename));
118: new InputStreamReader(SocietyFinder.getInstance().open(
119: filename));
120: } else {
121: fileStream = new FileReader(tryfile);
122: }
123: input = new BufferedReader(fileStream);
124: StreamTokenizer tokens = new StreamTokenizer(input);
125: tokens.commentChar('#');
126: tokens.wordChars('[', ']');
127: tokens.wordChars('_', '_');
128: tokens.wordChars('<', '>');
129: tokens.wordChars('/', '/');
130: tokens.ordinaryChars('0', '9');
131: tokens.wordChars('0', '9');
132:
133: newVal = tokens.nextToken();
134: // Parse the prototype-ini file
135: while (newVal != StreamTokenizer.TT_EOF) {
136: if (tokens.ttype != StreamTokenizer.TT_WORD)
137: formatError("ttype: " + tokens.ttype + " sval: "
138: + tokens.sval);
139: dataItem = tokens.sval;
140: if (dataItem.equals("[Prototype]")) {
141: newVal = tokens.nextToken();
142: // String assetClassName = tokens.sval;
143: // aad.setAssetClass(assetClassName);
144: aad.setAssetClass("Organization");
145: if (log.isInfoEnabled()) {
146: log
147: .info("Switching AgentAssetData Class from: "
148: + tokens.sval
149: + " to: "
150: + aad.getAssetClass());
151: }
152: // if(assetClassName.equals("Entity")) {
153: // aad.setType(AgentAssetData.ENTITY);
154: // }
155: newVal = tokens.nextToken();
156: continue;
157: }
158: if (dataItem.equals("[Relationship]")) {
159: newVal = fillRelationships(newVal, tokens, aad);
160: continue;
161: }
162: if (dataItem.equals("[LocationSchedulePG]")) {
163: if (log.isDebugEnabled()) {
164: log.debug("Parsing LocationSchedulePG");
165: }
166: // parser language is currently incapable of expressing a
167: // complex schedule, so here we hack in some minimal support.
168: // newVal = setLocationSchedulePG(dataItem, newVal, tokens);
169: continue;
170: }
171: if (dataItem.equals("[UniqueId]")) {
172: newVal = tokens.nextToken();
173: aad.setUniqueID(tokens.sval);
174: if (log.isDebugEnabled()) {
175: log.debug("Parsing UniqueId: "
176: + aad.getUniqueID());
177: }
178: newVal = tokens.nextToken();
179: continue;
180: }
181: if (dataItem.equals("[UIC]")) {
182: newVal = tokens.nextToken();
183: aad.setUIC(tokens.sval);
184: if (log.isDebugEnabled()) {
185: log.debug("Parsing UIC: " + aad.getUIC());
186: }
187: newVal = tokens.nextToken();
188: continue;
189: }
190: if (dataItem.startsWith("[")) {
191: // We've got a property or capability
192: newVal = setPropertyForAsset(dataItem, newVal,
193: tokens, aad);
194: continue;
195: }
196: // if The token you read is not one of the valid
197: // choices from above
198: formatError("Incorrect token: " + dataItem);
199: }
200:
201: // Closing BufferedReader
202: if (input != null)
203: input.close();
204:
205: // Only generates a NoSuchMethodException for AssetSkeleton
206: // because of a coding error. If we are successul in creating it
207: // here it then the AssetSkeleton will end up with two copies
208: // the add/search criteria in AssetSkeleton is for a Vector and
209: // does not gurantee only one instance of each class. Thus the
210: // Org allocator plugin fails to recognize the correct set of
211: // capabilities.
212:
213: } catch (Exception e) {
214: if (log.isErrorEnabled()) {
215: log.error("Exception", e);
216: }
217: }
218: if (haveItemId == false) {
219: String name = agentId.substring(agentId
220: .lastIndexOf(File.separatorChar) + 1);
221: aad
222: .addPropertyGroup(setItemIdentificationPG(name,
223: name, ""));
224: }
225:
226: return aad;
227: }
228:
229: private void formatError(String msg) {
230: throw new RuntimeException("Error parsing " + getFileName()
231: + ": " + msg);
232: }
233:
234: /**
235: * Fills in myRelationships with arrays of relationship,
236: * agentName and capableroles triples.
237: */
238: protected int fillRelationships(int newVal, StreamTokenizer tokens,
239: AgentAssetData aad) throws IOException {
240:
241: RelationshipData rd = null;
242:
243: newVal = tokens.nextToken();
244: while ((newVal != StreamTokenizer.TT_EOF)
245: && (!tokens.sval.substring(0, 1).equals("["))) {
246:
247: String type = "";
248: String supportedAgent = "";
249: String role = "";
250:
251: for (int i = 0; i < 3; i++) {
252: if ((tokens.sval.length()) > 0
253: && (tokens.sval.substring(0, 1).equals("["))) {
254: throw new RuntimeException("Unexpected character: "
255: + tokens.sval);
256: }
257:
258: switch (i) {
259: case 0:
260: type = tokens.sval.trim();
261: break;
262:
263: case 1:
264: supportedAgent = tokens.sval.trim();
265: break;
266:
267: case 2:
268: role = tokens.sval.trim();
269: break;
270: }
271: newVal = tokens.nextToken();
272: }
273: // This attempts to fix a problem with the
274: // ini files.
275: if (type.equalsIgnoreCase("Superior")) {
276: role = "Subordinate";
277: }
278: rd = new RelationshipData();
279: rd.setType(type);
280: rd.setRole(role);
281: rd.setSupported(supportedAgent);
282: if (log.isDebugEnabled()) {
283: log.debug("New Relationship: type: \"" + type
284: + "\" Role: \"" + role + "\" Supported: \""
285: + supportedAgent + "\"");
286: }
287: aad.addRelationship(rd);
288: } //while
289: return newVal;
290: }
291:
292: /**
293: * Creates the property, fills in the slots based on what's in the
294: * prototype-ini file and then sets it for (or adds it to) the asset
295: **/
296: protected int setPropertyForAsset(String prop, int newVal,
297: StreamTokenizer tokens, AgentAssetData aad)
298: throws IOException {
299: String propertyName = prop.substring(1, prop.length() - 1)
300: .trim();
301: if (log.isDebugEnabled()) {
302: log.debug("Creating PropGroupData: " + propertyName);
303: }
304: if (propertyName.indexOf("ItemIdentification") != -1) {
305: haveItemId = true;
306: }
307: PropGroupData pgData = new PropGroupData(propertyName);
308: PGPropData propData = null;
309: try {
310: newVal = tokens.nextToken();
311: String member = tokens.sval;
312: // Parse through the property section of the file
313: while (newVal != StreamTokenizer.TT_EOF) {
314: if ((tokens.ttype == StreamTokenizer.TT_WORD)
315: && !(tokens.sval.substring(0, 1).equals("["))) {
316: propData = new PGPropData();
317: propData.setName(member);
318: newVal = tokens.nextToken();
319: String dataType = tokens.sval;
320: newVal = tokens.nextToken();
321: propData.setType(getType(dataType));
322: String subType = getSubType(dataType);
323: if (subType != null) {
324: propData.setSubType(subType);
325: }
326: if (propData.getName().equals("HomeLocation")) {
327: propData
328: .setValue(parseHomeLocation(tokens.sval));
329: } else {
330: propData.setValue(getValue(parseArgs(dataType,
331: tokens.sval)));
332: }
333:
334: newVal = tokens.nextToken();
335: member = tokens.sval;
336:
337: // HACK for 10.0 ClusterIdentifier->MessageAddress
338: if (propData.getName().equals("ClusterIdentifier")) {
339: if (log.isWarnEnabled()) {
340: log
341: .warn("ClusterIdentifier obsolete. Replacing with MessageAddress.");
342: }
343: propData.setName("MessageAddress");
344: propData.setType("MessageAddress");
345: }
346:
347: pgData.addProperty(propData);
348: } else {
349: // Reached a left bracket "[", want to exit block
350: break;
351: }
352: } //while
353:
354: // Add the property to the asset
355: aad.addPropertyGroup(pgData);
356: } catch (IOException e) {
357: throw e;
358: } catch (Exception e) {
359: if (log.isErrorEnabled()) {
360: log.error("Exception during parse", e);
361: }
362: }
363: return newVal;
364: }
365:
366: // Grab only the GeolocCode= piece, not any other fields. All those must be looked
367: // up in the GEOLOC table anyhow.
368: private String parseHomeLocation(String argument) {
369: int ind = argument.indexOf("GeolocCode=");
370: if (ind == -1) {
371: if (log.isWarnEnabled())
372: log.warn("Found no GeolocCode in HomeLocation");
373: return "";
374: }
375: String narg = argument.substring(ind);
376: if (narg.indexOf(",") != -1)
377: return narg.substring(0, narg.indexOf(","));
378: else
379: return narg;
380: }
381:
382: private Object getValue(Object arg) {
383: if (arg instanceof Collection) {
384: Iterator iter = ((Collection) arg).iterator();
385: PGPropMultiVal multi = new PGPropMultiVal();
386: while (iter.hasNext()) {
387: multi.addValue((String) iter.next());
388: }
389: return multi;
390: } else {
391: return arg;
392: }
393: }
394:
395: private PropGroupData setTypeIdentificationPG() {
396: PropGroupData pgData = new PropGroupData(
397: PropGroupData.TYPE_IDENTIFICATION);
398: PGPropData propData = new PGPropData();
399: propData.setName("TypeIdentification");
400: propData.setType("String");
401: propData.setValue("UTC/RTOrg");
402: pgData.addProperty(propData);
403:
404: return pgData;
405: }
406:
407: private PropGroupData setItemIdentificationPG(String id,
408: String nomenclature, String altid) {
409:
410: if (log.isDebugEnabled()) {
411: log.debug("In setItemIdentificationPG(" + id + ", "
412: + nomenclature + ", " + altid + ")");
413: }
414:
415: PropGroupData pgData = new PropGroupData(
416: PropGroupData.ITEM_IDENTIFICATION);
417: PGPropData propData = new PGPropData();
418: propData.setName("ItemIdentification");
419: propData.setType("String");
420: propData.setValue(id);
421: pgData.addProperty(propData);
422:
423: propData = new PGPropData();
424: propData.setName("Nomenclature");
425: propData.setType("String");
426: propData.setValue(nomenclature);
427: pgData.addProperty(propData);
428:
429: // Note: Currently the database doesn't support an AltId for Item.
430: // why is this?
431: // propData = new PGPropData();
432: // propData.setName("AlternateItemIdentification");
433: // propData.setType("String");
434: // propData.setValue(altid);
435: // pgData.addProperty(propData);
436:
437: return pgData;
438: }
439:
440: private PropGroupData setClusterPG(String name) {
441: if (log.isDebugEnabled()) {
442: log.debug("Added ClusterPG: " + name);
443: }
444:
445: PropGroupData pgData = new PropGroupData(PropGroupData.CLUSTER);
446: PGPropData propData = new PGPropData();
447: propData.setName("MessageAddress");
448: propData.setType("MessageAddress");
449: propData.setValue(name);
450: pgData.addProperty(propData);
451:
452: return pgData;
453: }
454:
455: private PropGroupData setCommunityPG() {
456: PropGroupData pgData = new PropGroupData(
457: PropGroupData.COMMUNITY);
458: PGPropData propData = new PGPropData();
459: propData.setName("TimeSpan");
460: propData.setType("TimeSpan");
461: propData.setValue(""); // Leave empty
462: pgData.addProperty(propData);
463:
464: propData = new PGPropData();
465: propData.setName("Communities");
466: propData.setType("Collection");
467: propData.setSubType("String");
468: PGPropMultiVal values = new PGPropMultiVal();
469: values.addValue("COUGAAR");
470: propData.setValue(values);
471: pgData.addProperty(propData);
472:
473: // add in default community
474: // communityPG.setTimeSpan(DEFAULT_START_TIME, DEFAULT_END_TIME);
475:
476: return pgData;
477: }
478:
479: protected int setAssignmentPG(int newVal, StreamTokenizer tokens,
480: AgentAssetData aad) {
481:
482: PropGroupData pgData = new PropGroupData(
483: PropGroupData.ASSIGNMENT);
484: PGPropData propData = null;
485:
486: try {
487: newVal = tokens.nextToken();
488: // Parse through the property section of the file
489: while (newVal != StreamTokenizer.TT_EOF) {
490: propData = new PGPropData();
491: propData.setName(tokens.sval);
492:
493: if ((tokens.ttype == StreamTokenizer.TT_WORD)
494: && !(tokens.sval.substring(0, 1).equals("["))) {
495:
496: newVal = tokens.nextToken();
497: propData.setType(tokens.sval);
498: newVal = tokens.nextToken();
499: propData.setValue(tokens.sval);
500: newVal = tokens.nextToken();
501: pgData.addProperty(propData);
502: } else {
503: // Reached a left bracket "[", want to exit block
504: break;
505: }
506: } //while
507: } catch (Exception e) {
508: if (log.isErrorEnabled()) {
509: log.error("Exception", e);
510: }
511: }
512: aad.addPropertyGroup(pgData);
513: return newVal;
514: }
515:
516: // This needs to be modified to just return values.
517: // It should not create the types.
518: protected Object parseArgs(String type, String arg) {
519: int i;
520:
521: type = type.trim();
522: arg = arg.trim();
523:
524: if ((i = type.indexOf("<")) >= 0) {
525: int j = type.lastIndexOf(">");
526: String ctype = type.substring(0, i).trim();
527: String etype = type.substring(i + 1, j).trim();
528: Collection c = null;
529: if (ctype.equals("Collection") || ctype.equals("List")) {
530: c = new ArrayList();
531: } else {
532: throw new RuntimeException(
533: "Unparsable collection type: " + type);
534: }
535:
536: Vector l = org.cougaar.util.StringUtility.parseCSV(arg);
537: for (Iterator it = l.iterator(); it.hasNext();) {
538: c.add((String) parseE(etype, (String) it.next()));
539: }
540: return c;
541: } else if ((i = type.indexOf("/")) >= 0) {
542: // Handle Measure Object Here.
543: return arg;
544: } else {
545: return arg;
546: }
547: }
548:
549: private Object parseE(String type, String arg) {
550: int i;
551:
552: type = type.trim();
553: arg = arg.trim();
554:
555: if ((i = type.indexOf("<")) >= 0) {
556: int j = type.lastIndexOf(">");
557: String ctype = type.substring(0, i).trim();
558: String etype = type.substring(i + 1, j).trim();
559: Collection c = null;
560: if (ctype.equals("Collection") || ctype.equals("List")) {
561: c = new ArrayList();
562: } else {
563: throw new RuntimeException(
564: "Unparsable collection type: " + type);
565: }
566:
567: Vector l = org.cougaar.util.StringUtility.parseCSV(arg);
568: for (Iterator it = l.iterator(); it.hasNext();) {
569: c.add((String) parseE(etype, (String) it.next()));
570: }
571: return c;
572: } else if ((i = type.indexOf("/")) >= 0) {
573: // Measure Object. How should we handle this?
574: return arg;
575: } else {
576: return arg;
577: }
578: }
579:
580: private String getType(String type) {
581: int i;
582: if ((i = type.indexOf("<")) > -1) { // deal with collections
583: return type.substring(0, i);
584: } else {
585: return type;
586: }
587: }
588:
589: private String getSubType(String type) {
590: int i;
591: if ((i = type.indexOf("<")) > -1) { // deal with collections
592: int j = type.lastIndexOf(">");
593: return type.substring(i + 1, j);
594: } else {
595: return type;
596: }
597: }
598:
599: private static class TrivialTimeSpan implements TimeSpan {
600: long myStart;
601: long myEnd;
602:
603: public TrivialTimeSpan(long start, long end) {
604: myStart = start;
605: myEnd = end;
606: }
607:
608: public long getStartTime() {
609: return myStart;
610: }
611:
612: public long getEndTime() {
613: return myEnd;
614: }
615: }
616:
617: }// PrototypeParser
|