0001: /*
0002: * <copyright>
0003: *
0004: * Copyright 1997-2004 BBNT Solutions, LLC
0005: * under sponsorship of the Defense Advanced Research Projects
0006: * Agency (DARPA).
0007: *
0008: * You can redistribute this software and/or modify it under the
0009: * terms of the Cougaar Open Source License as published on the
0010: * Cougaar Open Source Website (www.cougaar.org).
0011: *
0012: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
0013: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
0014: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
0015: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
0016: * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
0017: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
0018: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
0019: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
0020: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
0021: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
0022: * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0023: *
0024: * </copyright>
0025: */
0026:
0027: package org.cougaar.planning.plugin.asset;
0028:
0029: import java.lang.reflect.Constructor;
0030: import java.lang.reflect.Field;
0031: import java.lang.reflect.Method;
0032: import java.text.DateFormat;
0033: import java.text.ParseException;
0034: import java.util.ArrayList;
0035: import java.util.Collection;
0036: import java.util.HashMap;
0037: import java.util.Iterator;
0038: import java.util.List;
0039: import java.util.Map;
0040: import java.util.StringTokenizer;
0041: import java.util.Vector;
0042:
0043: import org.cougaar.core.logging.LoggingServiceWithPrefix;
0044: import org.cougaar.core.mts.MessageAddress;
0045: import org.cougaar.core.service.DomainService;
0046: import org.cougaar.core.service.LoggingService;
0047: import org.cougaar.planning.Constants;
0048: import org.cougaar.planning.ldm.PlanningFactory;
0049: import org.cougaar.planning.ldm.asset.Asset;
0050: import org.cougaar.planning.ldm.asset.LocationSchedulePG;
0051: import org.cougaar.planning.ldm.asset.LocationSchedulePGImpl;
0052: import org.cougaar.planning.ldm.asset.NewClusterPG;
0053: import org.cougaar.planning.ldm.asset.NewItemIdentificationPG;
0054: import org.cougaar.planning.ldm.asset.NewLocationSchedulePG;
0055: import org.cougaar.planning.ldm.asset.NewPropertyGroup;
0056: import org.cougaar.planning.ldm.asset.NewRelationshipPG;
0057: import org.cougaar.planning.ldm.asset.NewTypeIdentificationPG;
0058: import org.cougaar.planning.ldm.asset.PropertyGroup;
0059: import org.cougaar.planning.ldm.asset.RelationshipBG;
0060: import org.cougaar.planning.ldm.measure.Latitude;
0061: import org.cougaar.planning.ldm.measure.Longitude;
0062: import org.cougaar.planning.ldm.plan.AspectType;
0063: import org.cougaar.planning.ldm.plan.AspectValue;
0064: import org.cougaar.planning.ldm.plan.HasRelationships;
0065: import org.cougaar.planning.ldm.plan.LatLonPointImpl;
0066: import org.cougaar.planning.ldm.plan.LocationScheduleElement;
0067: import org.cougaar.planning.ldm.plan.LocationScheduleElementImpl;
0068: import org.cougaar.planning.ldm.plan.NewPrepositionalPhrase;
0069: import org.cougaar.planning.ldm.plan.NewRoleSchedule;
0070: import org.cougaar.planning.ldm.plan.NewSchedule;
0071: import org.cougaar.planning.ldm.plan.NewTask;
0072: import org.cougaar.planning.ldm.plan.Preference;
0073: import org.cougaar.planning.ldm.plan.Relationship;
0074: import org.cougaar.planning.ldm.plan.Role;
0075: import org.cougaar.planning.ldm.plan.Schedule;
0076: import org.cougaar.planning.ldm.plan.ScheduleImpl;
0077: import org.cougaar.planning.ldm.plan.ScoringFunction;
0078: import org.cougaar.planning.ldm.plan.TimeAspectValue;
0079: import org.cougaar.planning.ldm.plan.Verb;
0080: import org.cougaar.planning.plugin.legacy.SimplePlugin;
0081: import org.cougaar.planning.service.AssetInitializerService;
0082: import org.cougaar.util.ConfigFinder;
0083: import org.cougaar.util.Reflect;
0084: import org.cougaar.util.StateModelException;
0085: import org.cougaar.util.TimeSpan;
0086: import org.cougaar.util.UnaryPredicate;
0087:
0088: /**
0089: * Generic plugin to create a local asset and the Report tasks
0090: * associated with all the local asset's relationships.
0091: *
0092: * Local asset must have ClusterPG and
0093: * RelationshipPG, Presumption is that the 'other' assets in all the
0094: * relationships have both Cluster and Relationship PGs.
0095: * Currently assumes that each Agent has exactly 1 local asset.
0096: *
0097: * Extensions of this class load this information from specific media such as files.
0098: * Now supports adding additional relationships via plugin parameters. Each
0099: * parameter represents 1 relationship between the local asset and some 'other'
0100: * asset. Parameter must completely identify both the other asset and the
0101: * relationship. Building the other asset requires knowing the asset's message
0102: * address (ClusterPG), item identification (ItemIdentificationPG), and type
0103: * identification (TypeIdentificationPG). Building the relationship requires
0104: * knowing the role and optionally the start and end times.
0105: *
0106: * Parameter format -
0107: * Relationship:MessageAddress=<ClusterPG.getMessageAddress of other asset>,\
0108: * ItemIdentification=<ItemIdentificationPG.getItemIdentification of other asset>,\
0109: * TypeIdentification=<TypeIdentificationPG.getTypeIdentification of other asset>,\
0110: * Role=<Role performed by the local asset>\
0111: * StartTime=<Date relationship starts>\
0112: * EndTime=<Date relations ends>
0113: *
0114: * Sample parameter -
0115: * Relationship:MessageAddress=DISCOM-1-AD,ItemIdentification=DISCOM-1-AD,TypeIdentification=UTC/NBTTT,Role=Superior,StartTime=01/01/2001 12:00 am,EndTime= 01/01/2010 11:59 pm
0116: *
0117: * StartTime and EndTime specifications are optional. Will default to
0118: * getDefaultStartTime()/getDefaultEndTime() if not included
0119: **/
0120: public class AssetDataPlugin extends SimplePlugin {
0121: // See bug 3869 -- should be ComponentPlugin, but not trivial
0122:
0123: public static final String SELF = ("Self");
0124:
0125: protected static TrivialTimeSpan ETERNITY = new TrivialTimeSpan(
0126: TimeSpan.MIN_VALUE, TimeSpan.MAX_VALUE);
0127:
0128: protected DateFormat myDateFormat = DateFormat.getInstance();
0129:
0130: protected String myAssetClassName = null;
0131: protected List myRelationships = new ArrayList();
0132: protected Map myOtherAssets = new HashMap();
0133: protected Asset myLocalAsset = null;
0134: protected PlanningFactory myPlanningFactory;
0135: protected AssetInitializerService myAssetInitializerService;
0136: protected LoggingService myLogger;
0137:
0138: public void load(Object object) throws StateModelException {
0139: super .load(object);
0140: myPlanningFactory = (PlanningFactory) getFactory("planning");
0141: if (myPlanningFactory == null) {
0142: throw new RuntimeException("Missing \"planning\" factory");
0143: }
0144:
0145: myLogger = (LoggingService) getBindingSite().getServiceBroker()
0146: .getService(this , LoggingService.class, null);
0147: if (myLogger == null) {
0148: myLogger = LoggingService.NULL;
0149: }
0150: myLogger = LoggingServiceWithPrefix.add(myLogger,
0151: getAgentIdentifier() + ": ");
0152:
0153: initAssets();
0154: }
0155:
0156: public void execute() {
0157: }
0158:
0159: public long getDefaultStartTime() {
0160: return TimeSpan.MIN_VALUE;
0161: }
0162:
0163: public long getDefaultEndTime() {
0164: return TimeSpan.MAX_VALUE;
0165: }
0166:
0167: public void setAssetInitializerService(AssetInitializerService ais) {
0168: myAssetInitializerService = ais;
0169: }
0170:
0171: protected void setupSubscriptions() {
0172: getSubscriber().setShouldBePersisted(false);
0173:
0174: /*
0175: if (!didRehydrate()) {
0176: processAssets(); // Objects should already exist after rehydration
0177: } */
0178: }
0179:
0180: protected void initAssets() {
0181: try {
0182: openTransaction();
0183:
0184: // Look to see whether we've already created the local asset
0185: if (didRehydrate()) {
0186: Collection queryCollection = getBlackboardService()
0187: .query(new UnaryPredicate() {
0188: public boolean execute(Object o) {
0189: return (o instanceof LocalAssetInfo);
0190: }
0191: });
0192:
0193: if (!queryCollection.isEmpty()) {
0194: final Object key = ((LocalAssetInfo) queryCollection
0195: .iterator().next()).getKey();
0196: String className = ((LocalAssetInfo) queryCollection
0197: .iterator().next()).getClassName();
0198: if (queryCollection.size() > 1) {
0199: myLogger.warn("Found " + queryCollection.size()
0200: + " keys for the local Asset."
0201: + " Using - " + key);
0202: }
0203:
0204: Collection assetCollection = getBlackboardService()
0205: .query(new UnaryPredicate() {
0206: public boolean execute(Object o) {
0207: return ((o instanceof Asset) && (((Asset) o)
0208: .getKey().equals(key)));
0209: }
0210: });
0211:
0212: if (!assetCollection.isEmpty()) {
0213: myLocalAsset = (Asset) assetCollection
0214: .iterator().next();
0215: myAssetClassName = className;
0216: } else {
0217: myLogger
0218: .warn("Did not find local asset for key "
0219: + key);
0220: }
0221: }
0222: }
0223:
0224: if (myLocalAsset == null) {
0225: processAssets();
0226: }
0227: } catch (Exception e) {
0228: synchronized (System.err) {
0229: myLogger.error(this + " caught " + e);
0230: e.printStackTrace();
0231: }
0232: } finally {
0233: closeTransactionDontReset();
0234: }
0235: }
0236:
0237: /**
0238: * Parses the prototype-ini file and in the process sets up
0239: * the relationships with pairs of "relationship"/"asset
0240: */
0241:
0242: protected void processAssets() {
0243: try {
0244: String aId = getAgentIdentifier().toString();
0245:
0246: if (myAssetInitializerService == null) {
0247: myLogger.fatal("AssetInitializerService is null."
0248: + " Unable to create local asset.");
0249: return;
0250: }
0251: AssetDataReader assetDataReader = getAssetDataReader();
0252: assetDataReader.readAsset(aId, new AssetDataCallbackImpl());
0253:
0254: // Process relationships specified as plugin arguments
0255: addParamRelationships();
0256:
0257: if (myLogger.isDebugEnabled()) {
0258: myLogger.debug("property groups for local asset: ");
0259: Vector all = myLocalAsset.fetchAllProperties();
0260: try {
0261: for (Iterator i = all.iterator(); i.hasNext();) {
0262: Object o = i.next();
0263: if (!(o instanceof PropertyGroup))
0264: continue;
0265: PropertyGroup pg = (PropertyGroup) o;
0266: Class pgc = pg.getClass();
0267: myLogger.debug(pgc.getName());
0268: Method[] methods = pgc.getMethods();
0269: for (int j = 0; j < methods.length; j++) {
0270: Method method = methods[j];
0271: if (method.getName().startsWith("get")
0272: && method.getParameterTypes().length == 0) {
0273: Object value = methods[j].invoke(pg,
0274: new Object[0]);
0275: myLogger.debug(" " + method.getName()
0276: + " = " + value);
0277: }
0278: }
0279: }
0280: } catch (Exception e) {
0281: e.printStackTrace();
0282: }
0283: }
0284:
0285: getBlackboardService().publishAdd(myLocalAsset);
0286: LocalAssetInfo localAssetInfo = new LocalAssetInfo(
0287: myLocalAsset, myAssetClassName);
0288: getBlackboardService().publishAdd(localAssetInfo);
0289:
0290: // Put the assets for this agent into array
0291: for (Iterator iterator = myRelationships.iterator(); iterator
0292: .hasNext();) {
0293: Relationship relationship = (Relationship) iterator
0294: .next();
0295: report(relationship);
0296: }
0297: } catch (Exception e) {
0298: e.printStackTrace();
0299: }
0300: }
0301:
0302: protected void createMyLocalAsset(String assetClassName) {
0303: myAssetClassName = assetClassName;
0304: myLocalAsset = myPlanningFactory.createAsset(myAssetClassName);
0305: // set up this asset's available schedule
0306: NewSchedule availsched = myPlanningFactory.newSimpleSchedule(
0307: getDefaultStartTime(), getDefaultEndTime());
0308: // set the available schedule
0309: ((NewRoleSchedule) myLocalAsset.getRoleSchedule())
0310: .setAvailableSchedule(availsched);
0311:
0312: // initialize the relationship info
0313: NewRelationshipPG pg = (NewRelationshipPG) myLocalAsset
0314: .getRelationshipPG();
0315:
0316: RelationshipBG bg = new RelationshipBG();
0317: // init sets the relationship schedule on the PG and sets the pointer from pg to bg
0318: bg.init(pg, (HasRelationships) myLocalAsset);
0319:
0320: // this asset is local to the agent
0321: pg.setLocal(true);
0322: }
0323:
0324: protected void report(Relationship relationship) {
0325: Asset sendTo = (((Asset) relationship.getA()).getKey()
0326: .equals(myLocalAsset.getKey())) ? myPlanningFactory
0327: .cloneInstance((Asset) relationship.getB())
0328: : myPlanningFactory.cloneInstance((Asset) relationship
0329: .getA());
0330:
0331: Asset localClone = myPlanningFactory
0332: .cloneInstance(myLocalAsset);
0333:
0334: List roles = new ArrayList(1);
0335: Role role = (((Asset) relationship.getA()).getKey()
0336: .equals(myLocalAsset.getKey())) ? relationship
0337: .getRoleA() : relationship.getRoleB();
0338: roles.add(role);
0339:
0340: NewTask reportTask = createReportTask(localClone, sendTo,
0341: roles, relationship.getStartTime(), relationship
0342: .getEndTime());
0343: getBlackboardService().publishAdd(reportTask);
0344:
0345: }
0346:
0347: protected NewPropertyGroup createPropertyGroup(String propertyName)
0348: throws Exception {
0349: return (NewPropertyGroup) myPlanningFactory
0350: .createPropertyGroup(propertyName);
0351: }
0352:
0353: protected void addPropertyToAsset(PropertyGroup pg) {
0354: myLocalAsset.addOtherPropertyGroup(pg);
0355: }
0356:
0357: protected void setLocationSchedule(String latStr, String lonStr) {
0358: Latitude lat = Latitude.newLatitude(latStr);
0359:
0360: Longitude lon = Longitude.newLongitude(lonStr);
0361:
0362: LatLonPointImpl loc = new LatLonPointImpl(lat, lon);
0363:
0364: // create LocationScheduleElementImpl
0365: LocationScheduleElement locSchedElem = new LocationScheduleElementImpl(
0366: TimeSpan.MIN_VALUE, TimeSpan.MAX_VALUE, loc);
0367:
0368: // add to schedule
0369: LocationSchedulePG locSchedPG = myLocalAsset
0370: .getLocationSchedulePG();
0371: if (locSchedPG == null) {
0372: locSchedPG = new LocationSchedulePGImpl();
0373: myLocalAsset.setLocationSchedulePG(locSchedPG);
0374: }
0375: Schedule locSched = locSchedPG.getSchedule();
0376: if (locSched == null) {
0377: locSched = new ScheduleImpl();
0378: ((NewLocationSchedulePG) locSchedPG).setSchedule(locSched);
0379: }
0380: locSched.add(locSchedElem);
0381: }
0382:
0383: protected void addRelationship(String typeId, String itemId,
0384: String otherAgentId, String roleName, long start, long end) {
0385: Asset otherAsset = getAsset(myAssetClassName, itemId, typeId,
0386: otherAgentId);
0387: Relationship relationship = myPlanningFactory.newRelationship(
0388: Role.getRole(roleName),
0389: (HasRelationships) myLocalAsset,
0390: (HasRelationships) otherAsset, start, end);
0391: myRelationships.add(relationship);
0392: }
0393:
0394: //create the Report task to be sent to myself which will result in an asset
0395: //transfer of the copyOfMyself being sent to the agent I am supporting.
0396: protected NewTask createReportTask(Asset reportingAsset,
0397: Asset sendto, Collection roles, long startTime, long endTime) {
0398: NewTask reportTask = myPlanningFactory.newTask();
0399: reportTask.setDirectObject(reportingAsset);
0400:
0401: Vector prepPhrases = new Vector(2);
0402: NewPrepositionalPhrase newpp = myPlanningFactory
0403: .newPrepositionalPhrase();
0404: newpp.setPreposition(Constants.Preposition.FOR);
0405: newpp.setIndirectObject(sendto);
0406: prepPhrases.add(newpp);
0407:
0408: newpp = myPlanningFactory.newPrepositionalPhrase();
0409: newpp.setPreposition(Constants.Preposition.AS);
0410: newpp.setIndirectObject(roles);
0411: prepPhrases.add(newpp);
0412: reportTask.setPrepositionalPhrases(prepPhrases.elements());
0413:
0414: reportTask.setPlan(myPlanningFactory.getRealityPlan());
0415: reportTask.setSource(getAgentIdentifier());
0416:
0417: AspectValue startTAV = TimeAspectValue.create(
0418: AspectType.START_TIME, startTime);
0419: ScoringFunction startScoreFunc = ScoringFunction
0420: .createStrictlyAtValue(startTAV);
0421: Preference startPreference = myPlanningFactory.newPreference(
0422: AspectType.START_TIME, startScoreFunc);
0423:
0424: AspectValue endTAV = TimeAspectValue.create(
0425: AspectType.END_TIME, endTime);
0426: ScoringFunction endScoreFunc = ScoringFunction
0427: .createStrictlyAtValue(endTAV);
0428: Preference endPreference = myPlanningFactory.newPreference(
0429: AspectType.END_TIME, endScoreFunc);
0430:
0431: Vector preferenceVector = new Vector(2);
0432: preferenceVector.addElement(startPreference);
0433: preferenceVector.addElement(endPreference);
0434:
0435: reportTask.setPreferences(preferenceVector.elements());
0436:
0437: reportTask.setVerb(getReportVerb(roles));
0438:
0439: return reportTask;
0440: }
0441:
0442: protected Verb getReportVerb(Collection roles) {
0443: return Constants.Verb.Report;
0444: }
0445:
0446: protected Asset getAsset(String className,
0447: String itemIdentification, String typeIdentification,
0448: String agentName) {
0449:
0450: Asset asset = myPlanningFactory.createAsset(className);
0451:
0452: ((NewTypeIdentificationPG) asset.getTypeIdentificationPG())
0453: .setTypeIdentification(typeIdentification);
0454:
0455: NewItemIdentificationPG itemIdProp = (NewItemIdentificationPG) asset
0456: .getItemIdentificationPG();
0457: itemIdProp.setItemIdentification(itemIdentification);
0458: itemIdProp.setNomenclature(itemIdentification);
0459:
0460: NewClusterPG cpg = (NewClusterPG) asset.getClusterPG();
0461: cpg.setMessageAddress(MessageAddress
0462: .getMessageAddress(agentName));
0463:
0464: Asset saved = (Asset) myOtherAssets.get(asset.getKey());
0465: if (saved == null) {
0466: myOtherAssets.put(asset.getKey(), asset);
0467: saved = asset;
0468: }
0469: return saved;
0470: }
0471:
0472: public long parseDate(String dateString) throws ParseException {
0473: return myDateFormat.parse(dateString).getTime();
0474: }
0475:
0476: protected Object parseExpr(String type, String arg) {
0477: int i;
0478:
0479: type = type.trim();
0480: arg = arg.trim();
0481:
0482: if ((i = type.indexOf("<")) >= 0) {
0483: int j = type.lastIndexOf(">");
0484: String ctype = type.substring(0, i).trim();
0485: String etype = type.substring(i + 1, j).trim();
0486: Collection c = null;
0487: if (ctype.equals("Collection") || ctype.equals("List")) {
0488: c = new ArrayList();
0489: } else {
0490: throw new RuntimeException(
0491: "Unparsable collection type: " + type);
0492: }
0493:
0494: String[] l = org.cougaar.util.CSVUtility.parse(arg);
0495: for (int ix = 0; ix < l.length; ix++) {
0496: c.add(parseExpr(etype, l[ix]));
0497: }
0498: return c;
0499: } else if ((i = type.indexOf("/")) >= 0) {
0500: String m = type.substring(0, i).trim();
0501: String mt = type.substring(i + 1).trim();
0502: double qty = Double.valueOf(arg).doubleValue();
0503: return createMeasureObject(m, qty, mt);
0504: } else {
0505: Class cl = findClass(type);
0506:
0507: try {
0508: if (cl.isInterface()) {
0509: if (TimeSpan.class.isAssignableFrom(cl)) {
0510: String[] svs = org.cougaar.util.CSVUtility
0511: .parse(arg);
0512: long startTime = getDefaultStartTime();
0513: long endTime = getDefaultEndTime();
0514: for (int ix = 0; ix < svs.length; ix++) {
0515: String ss = svs[ix];
0516:
0517: int eq = ss.indexOf('=');
0518: if (eq < 0) {
0519: throw new IllegalArgumentException(
0520: "Missing \"=\" in " + ss);
0521: }
0522: String slotname = ss.substring(0, eq)
0523: .trim();
0524: String vspec = ss.substring(eq + 1).trim();
0525: try {
0526: long time = parseDate(vspec);
0527: if (slotname.equals("startTime")) {
0528: startTime = time;
0529: } else if (slotname.equals("endTime")) {
0530: endTime = time;
0531: }
0532: } catch (ParseException pe) {
0533: }
0534: }
0535: return new TrivialTimeSpan(startTime, endTime);
0536: } else {
0537: // interface means try the COF
0538: return parseWithCOF(cl, arg);
0539: }
0540: } else {
0541: Class ac = getArgClass(cl);
0542: Object[] args = { arg };
0543: Constructor cons = Reflect.getConstructor(ac,
0544: stringArgSpec);
0545: if (cons != null) {
0546: // found a constructor - use it
0547: return cons.newInstance(args);
0548: } else {
0549: Method fm = Reflect.getMethod(ac, "create",
0550: stringArgSpec);
0551: if (fm == null) {
0552: String n = ac.getName();
0553: // remove the package prefix
0554: n = n.substring(n.lastIndexOf('.') + 1)
0555: .trim();
0556: fm = Reflect.getMethod(ac, "create" + n,
0557: stringArgSpec);
0558: if (fm == null)
0559: fm = Reflect.getMethod(ac, "get" + n,
0560: stringArgSpec);
0561: }
0562: if (fm == null) {
0563: throw new RuntimeException(
0564: "Couldn't figure out how to construct "
0565: + type);
0566: }
0567: return fm.invoke(null, args);
0568: }
0569: }
0570: } catch (Exception e) {
0571: myLogger.error("Exception constructing " + type
0572: + " from \"" + arg + "\":");
0573: e.printStackTrace();
0574: throw new RuntimeException("Construction problem " + e);
0575: }
0576: }
0577: }
0578:
0579: protected AssetDataReader getAssetDataReader() {
0580: return myAssetInitializerService.getAssetDataReader();
0581: }
0582:
0583: private static Class[] stringArgSpec = { String.class };
0584:
0585: private static Class[][] argClasses = {
0586: { Integer.TYPE, Integer.class },
0587: { Double.TYPE, Double.class },
0588: { Boolean.TYPE, Boolean.class },
0589: { Float.TYPE, Float.class }, { Long.TYPE, Long.class },
0590: { Short.TYPE, Short.class }, { Byte.TYPE, Byte.class },
0591: { Character.TYPE, Character.class } };
0592:
0593: private static Class getArgClass(Class c) {
0594: if (!c.isPrimitive())
0595: return c;
0596: for (int i = 0; i < argClasses.length; i++) {
0597: if (c == argClasses[i][0])
0598: return argClasses[i][1];
0599: }
0600: throw new IllegalArgumentException("Class " + c
0601: + " is an unknown primitive.");
0602: }
0603:
0604: protected String getType(String type) {
0605: int i;
0606: if ((i = type.indexOf("<")) > -1) { // deal with collections
0607: // int j = type.lastIndexOf(">");
0608: return getType(type.substring(0, i).trim()); // deal with measures
0609: } else if ((i = type.indexOf("/")) > -1) {
0610: return getType(type.substring(0, i).trim());
0611: } else {
0612: return type;
0613: }
0614: }
0615:
0616: protected Object parseWithCOF(Class cl, String val) {
0617: String name = cl.getName();
0618: int dot = name.lastIndexOf('.');
0619: if (dot != -1)
0620: name = name.substring(dot + 1).trim();
0621:
0622: try {
0623: // lookup method on ldmf
0624: Object o = callFactoryMethod(name);
0625:
0626: String[] svs = org.cougaar.util.CSVUtility.parse(val);
0627: // svs should be a set of strings like "slot=value" or "slot=type value"
0628: for (int i = 0; i < svs.length; i++) {
0629: String ss = svs[i];
0630: if (myLogger.isDebugEnabled()) {
0631: myLogger.debug("Processing \"" + ss + "\"");
0632: }
0633:
0634: int eq = ss.indexOf('=');
0635: if (eq < 0) {
0636: throw new IllegalArgumentException(
0637: "Missing \"=\" in " + ss);
0638: }
0639: String slotname = ss.substring(0, eq).trim();
0640: String vspec = ss.substring(eq + 1).trim();
0641:
0642: int spi = vspec.indexOf(' ');
0643: Object v;
0644: if (spi == -1) {
0645: v = vspec;
0646: } else {
0647: String st = vspec.substring(0, spi).trim();
0648: String sv = vspec.substring(spi + 1).trim();
0649: v = parseExpr(st, sv);
0650: }
0651: callSetMethod(o, slotname, v);
0652: }
0653: return o;
0654: } catch (Exception e) {
0655: myLogger.error("Exception parsing " + val, e);
0656: return null;
0657: }
0658: }
0659:
0660: private Object callFactoryMethod(String ifcname) {
0661: // look up a zero-arg factory method in the ldmf
0662: String newname = "new" + ifcname;
0663:
0664: DomainService domainService = (DomainService) getDelegate()
0665: .getServiceBroker().getService(this ,
0666: DomainService.class, null);
0667:
0668: if (domainService == null) {
0669: throw new RuntimeException("Unable to get DomainService");
0670: }
0671:
0672: List factories = domainService.getFactories();
0673: for (Iterator i = factories.iterator(); i.hasNext();) {
0674: try {
0675: Class ldmfc = i.next().getClass();
0676: Method fm = ldmfc.getMethod(newname, nullClassList);
0677: // Documentation says first arg is ignored for static methods,
0678: // which it is ?always?
0679: return fm.invoke(myPlanningFactory, nullArgList);
0680: } catch (NoSuchMethodException nsme) {
0681: // This is okay - just try the next factory
0682: } catch (Exception e) {
0683: myLogger.error("Problem loading Domain Factory", e);
0684: }
0685: }
0686:
0687: throw new RuntimeException(
0688: "Couldn't find a factory method for " + ifcname);
0689: }
0690:
0691: private static final Class nullClassList[] = {};
0692: private static final Object nullArgList[] = {};
0693:
0694: private void callSetMethod(Object o, String slotname, Object value) {
0695: Class oc = o.getClass();
0696: String setname = "set" + slotname;
0697: Class vc = value.getClass();
0698:
0699: try {
0700: Method ms[] = Reflect.getMethods(oc);
0701: for (int i = 0; i < ms.length; i++) {
0702: Method m = ms[i];
0703: if (setname.equals(m.getName())) {
0704: Class mps[] = m.getParameterTypes();
0705: if (mps.length == 1 && mps[0].isAssignableFrom(vc)) {
0706: Object args[] = { value };
0707: m.invoke(o, args);
0708: return;
0709: }
0710: }
0711: }
0712: } catch (Exception e) {
0713: throw new RuntimeException("Couldn't find set" + slotname
0714: + " for " + o + ", value " + value
0715: + ". Typo in slot name: " + slotname + "?");
0716: }
0717:
0718: throw new RuntimeException("Couldn't find set" + slotname
0719: + " for " + o + ", value " + value);
0720: }
0721:
0722: /**
0723: * Returns the integer value for the appropriate
0724: * unitOfMeasure field in the measureClass
0725: */
0726: protected int getMeasureUnit(String measureClass,
0727: String unitOfMeasure) {
0728: try {
0729: String fullClassName = "org.cougaar.planning.ldm.measure."
0730: + measureClass;
0731: Field f = Class.forName(fullClassName).getField(
0732: unitOfMeasure);
0733: return f.getInt(null);
0734: } catch (Exception e) {
0735: myLogger.error("Exception " + e + ": for measure unit: "
0736: + unitOfMeasure);
0737: e.printStackTrace();
0738: }
0739: return -1;
0740: }
0741:
0742: /**
0743: * Returns a measure object which is an instance of className and has
0744: * a quantity of unitOfMeasure
0745: */
0746: protected Object createMeasureObject(String className,
0747: double quantity, String unitOfMeasure) {
0748: try {
0749: Class classObj = Class
0750: .forName("org.cougaar.planning.ldm.measure."
0751: + className);
0752: String methodName = "new" + className;
0753: Class parameters[] = { double.class, int.class };
0754: Method meth = classObj.getMethod(methodName, parameters);
0755: Object arguments[] = {
0756: new Double(quantity),
0757: new Integer(
0758: getMeasureUnit(className, unitOfMeasure)) };
0759: return meth.invoke(classObj, arguments); // static method call
0760: } catch (Exception e) {
0761: e.printStackTrace();
0762: }
0763: return null;
0764: }
0765:
0766: private static HashMap classes;
0767: protected static Collection packages = new ArrayList();
0768:
0769: static {
0770: // initialize packages:
0771: packages.add("org.cougaar.planning.ldm.measure");
0772: packages.add("org.cougaar.planning.ldm.plan");
0773: packages.add("org.cougaar.planning.ldm.asset");
0774: packages.add("org.cougaar.planning.ldm.oplan");
0775:
0776: packages.add("java.lang"); // extras for fallthrough
0777: packages.add("java.util");
0778:
0779: // initialize the classmap with some common ones
0780: classes = new HashMap();
0781:
0782: classes.put("MessageAddress", MessageAddress.class);
0783:
0784: // precache some builtins
0785: classes.put("long", Long.TYPE);
0786: classes.put("int", Integer.TYPE);
0787: classes.put("integer", Integer.TYPE);
0788: classes.put("boolean", Boolean.TYPE);
0789: classes.put("float", Float.TYPE);
0790: classes.put("double", Double.TYPE);
0791: // and some java.lang
0792: classes.put("Double", Double.class);
0793: classes.put("String", String.class);
0794: classes.put("Integer", Integer.class);
0795: // and some java.util
0796: classes.put("Collection", Collection.class);
0797: classes.put("List", List.class);
0798: classes.put("TimeSpan", TimeSpan.class);
0799:
0800: // COUGAAR-specific stuff will be looked for
0801: }
0802:
0803: private Class findClass(String name) {
0804: synchronized (classes) {
0805: Class c = (Class) classes.get(name);
0806: // try the cache
0807: if (c != null)
0808: return c;
0809:
0810: for (Iterator i = packages.iterator(); i.hasNext();) {
0811: String pkg = (String) i.next();
0812: try { // Oh so ugly!
0813: c = Class.forName(pkg + "." + name);
0814: if (c != null) { // silly
0815: classes.put(name, c);
0816: return c;
0817: }
0818: } catch (ClassNotFoundException e) {
0819: }
0820: ; // sigh
0821: }
0822: throw new RuntimeException("Could not find a class for '"
0823: + name + "'.");
0824: }
0825: }
0826:
0827: /**
0828: * Creates and calls the appropriate "setter" method for the property
0829: * which is of type className.
0830: */
0831: protected void callSetter(NewPropertyGroup pg, String setterName,
0832: String type, Object[] arguments) {
0833: Class parameters[] = new Class[1];
0834:
0835: try {
0836: parameters[0] = findClass(type);
0837: Method meth = findMethod(pg.getClass(), setterName,
0838: parameters);
0839: if (meth == null) {
0840: StringBuffer msg = new StringBuffer();
0841: msg.append("Method not found: ");
0842: msg.append(setterName);
0843: msg.append("(");
0844: for (int i = 0; i < parameters.length; i++) {
0845: if (i > 0)
0846: msg.append(", ");
0847: msg.append(parameters[i].getName());
0848: }
0849: msg.append(")");
0850: myLogger.error(msg.toString());
0851: return;
0852: }
0853: meth.invoke(pg, arguments);
0854: } catch (Exception e) {
0855: myLogger.error("Exception: callSetter("
0856: + pg.getClass().getName() + ", " + setterName
0857: + ", " + type + ", " + arguments + " : " + e);
0858: e.printStackTrace();
0859: }
0860: }
0861:
0862: private static Method findMethod(Class c, String name,
0863: Class params[]) {
0864: Method ms[] = Reflect.getMethods(c);
0865: int pl = params.length;
0866: for (int i = 0; i < ms.length; i++) {
0867: Method m = ms[i];
0868: if (name.equals(m.getName())) {
0869: Class mps[] = m.getParameterTypes();
0870: if (mps.length == pl) {
0871: int j;
0872: for (j = 0; j < pl; j++) {
0873: if (!(mps[j].isAssignableFrom(params[j])))
0874: break; // j loop
0875: }
0876: if (j == pl) // all passed
0877: return m;
0878: }
0879: }
0880: }
0881: return null;
0882: }
0883:
0884: public static final String ATTRIBUTE_DELIMITER = "=";
0885: public static final String VALUE_DELIMITER = ",";
0886: public static final String KEYWORD_DELIMITER = ":";
0887:
0888: protected void addParamRelationships() {
0889: Collection params = getDelegate().getParameters();
0890:
0891: for (Iterator iterator = params.iterator(); iterator.hasNext();) {
0892: String param = (String) iterator.next();
0893:
0894: addParamRelationship(param);
0895: }
0896: }
0897:
0898: public static final String RELATIONSHIP_KEY = "Relationship";
0899:
0900: protected void addParamRelationship(String param) {
0901: StringTokenizer tokenizer = new StringTokenizer(param,
0902: KEYWORD_DELIMITER + ATTRIBUTE_DELIMITER
0903: + VALUE_DELIMITER, true);
0904:
0905: if (myLogger.isDebugEnabled()) {
0906: myLogger
0907: .debug("addParamRelationship: param = " + param
0908: + " - tokenizer count = "
0909: + tokenizer.countTokens());
0910: }
0911:
0912: String nextAttribute = getToken(tokenizer, KEYWORD_DELIMITER);
0913:
0914: if (!nextAttribute.equals(RELATIONSHIP_KEY)) {
0915: if (myLogger.isDebugEnabled()) {
0916: myLogger
0917: .debug("addParamRelationship: skipping param - "
0918: + param);
0919: }
0920: return;
0921: }
0922:
0923: String messageAddress = null;
0924: String typeIdentification = null;
0925: String itemIdentification = null;
0926: String role = "";
0927: long start = getDefaultStartTime();
0928: long end = getDefaultEndTime();
0929:
0930: while (tokenizer.hasMoreTokens()) {
0931:
0932: nextAttribute = getToken(tokenizer, ATTRIBUTE_DELIMITER);
0933:
0934: if (myLogger.isDebugEnabled()) {
0935: myLogger.debug("addParamRelelationship: nextAttribute "
0936: + nextAttribute);
0937: }
0938:
0939: if (nextAttribute == null) {
0940: myLogger.error("Unrecognized attribute "
0941: + nextAttribute + " in " + param
0942: + ". No relationship added.");
0943: return;
0944: } else if (nextAttribute.equals("MessageAddress")) {
0945: messageAddress = getToken(tokenizer, VALUE_DELIMITER);
0946: } else if (nextAttribute.equals("ItemIdentification")) {
0947: itemIdentification = getToken(tokenizer,
0948: VALUE_DELIMITER);
0949: } else if (nextAttribute.equals("TypeIdentification")) {
0950: typeIdentification = getToken(tokenizer,
0951: VALUE_DELIMITER);
0952: } else if (nextAttribute.equals("Role")) {
0953: role = getToken(tokenizer, VALUE_DELIMITER);
0954: } else if (nextAttribute.equals("StartTime")) {
0955: String timeString = getToken(tokenizer, VALUE_DELIMITER);
0956: if (myLogger.isDebugEnabled())
0957: myLogger.debug("trying to parse timeString: "
0958: + timeString + " from " + param);
0959: try {
0960: if (timeString != null)
0961: start = parseDate(timeString);
0962: else
0963: start = getDefaultStartTime();
0964: } catch (java.text.ParseException pe) {
0965: myLogger.error("Unable to parse start date from "
0966: + param + ". Start time defaulting to "
0967: + getDefaultStartTime());
0968: }
0969: } else if (nextAttribute.equals("EndTime")) {
0970: String timeString = getToken(tokenizer, VALUE_DELIMITER);
0971: try {
0972: if (timeString != null)
0973: end = parseDate(timeString);
0974: else
0975: end = getDefaultEndTime();
0976: } catch (java.text.ParseException pe) {
0977: myLogger.error("Unable to parse end date from "
0978: + param + ". Start time defaulting to "
0979: + getDefaultEndTime());
0980: }
0981: } else {
0982: myLogger.error("Unrecognized attribute "
0983: + nextAttribute + " in " + param
0984: + ". No relationship added.");
0985: return;
0986: }
0987: }
0988:
0989: if ((messageAddress == null) || (typeIdentification == null)
0990: || (itemIdentification == null) || (role == null)) {
0991: myLogger.error("Incomplete relationship specification - "
0992: + param + ". No relationship added.");
0993: } else {
0994: addRelationship(typeIdentification, itemIdentification,
0995: messageAddress, role, start, end);
0996: }
0997: }
0998:
0999: private String getToken(StringTokenizer tokenizer, String delim) {
1000: String token = null;
1001: if (tokenizer.hasMoreTokens()) {
1002: token = tokenizer.nextToken(delim);
1003: if (tokenizer.hasMoreTokens()
1004: && !(tokenizer.nextToken().equals(delim))) {
1005: token = null;
1006: }
1007: }
1008:
1009: return token;
1010: }
1011:
1012: private static class TrivialTimeSpan implements TimeSpan {
1013: long myStart;
1014: long myEnd;
1015:
1016: public TrivialTimeSpan(long start, long end) {
1017: myStart = start;
1018: myEnd = end;
1019: }
1020:
1021: public long getStartTime() {
1022: return myStart;
1023: }
1024:
1025: public long getEndTime() {
1026: return myEnd;
1027: }
1028: }
1029:
1030: private class AssetDataCallbackImpl implements AssetDataCallback {
1031: public ConfigFinder getConfigFinder() {
1032: return AssetDataPlugin.this .getConfigFinder();
1033: }
1034:
1035: public void createMyLocalAsset(String assetClassName) {
1036: AssetDataPlugin.this .createMyLocalAsset(assetClassName);
1037: }
1038:
1039: public boolean hasMyLocalAsset() {
1040: return (myLocalAsset != null);
1041: }
1042:
1043: public NewPropertyGroup createPropertyGroup(String propertyName)
1044: throws Exception {
1045: return AssetDataPlugin.this
1046: .createPropertyGroup(propertyName);
1047: }
1048:
1049: public Object parseExpr(String dataType, String value) {
1050: return AssetDataPlugin.this .parseExpr(dataType, value);
1051: }
1052:
1053: public long parseDate(String dateString) throws ParseException {
1054: return AssetDataPlugin.this .parseDate(dateString);
1055: }
1056:
1057: public String getType(String type) {
1058: return AssetDataPlugin.this .getType(type);
1059: }
1060:
1061: public void callSetter(NewPropertyGroup pg, String setterName,
1062: String type, Object[] arguments) {
1063: AssetDataPlugin.this .callSetter(pg, setterName, type,
1064: arguments);
1065: }
1066:
1067: public void setLocationSchedule(String latStr, String lonStr) {
1068: AssetDataPlugin.this .setLocationSchedule(latStr, lonStr);
1069: }
1070:
1071: public long getDefaultStartTime() {
1072: return AssetDataPlugin.this .getDefaultStartTime();
1073: }
1074:
1075: public long getDefaultEndTime() {
1076: return AssetDataPlugin.this .getDefaultEndTime();
1077: }
1078:
1079: public void addPropertyToAsset(PropertyGroup pg) {
1080: AssetDataPlugin.this .addPropertyToAsset(pg);
1081: }
1082:
1083: public void addRelationship(String typeId, String itemId,
1084: String otherAgentId, String roleName, long start,
1085: long end) {
1086: AssetDataPlugin.this .addRelationship(typeId, itemId,
1087: otherAgentId, roleName, start, end);
1088: }
1089: }
1090:
1091: private static class LocalAssetInfo implements java.io.Serializable {
1092: private Object myKey = null;
1093: private String myClassName = "";
1094:
1095: public LocalAssetInfo(Asset localAsset, String className) {
1096: myKey = localAsset.getKey();
1097: myClassName = className;
1098: }
1099:
1100: public LocalAssetInfo() {
1101: }
1102:
1103: public Object getKey() {
1104: return myKey;
1105: }
1106:
1107: public void setKey(Object key) {
1108: myKey = key;
1109: }
1110:
1111: public String getClassName() {
1112: return myClassName;
1113: }
1114:
1115: public void setClassName(String className) {
1116: myClassName = className;
1117: }
1118: }
1119: }
|