001/* 002 * Copyright (c) 2004-2010 The Regents of the University of California. 003 * All rights reserved. 004 * 005 * '$Author: welker $' 006 * '$Date: 2010-05-06 05:21:26 +0000 (Thu, 06 May 2010) $' 007 * '$Revision: 24234 $' 008 * 009 * Permission is hereby granted, without written agreement and without 010 * license or royalty fees, to use, copy, modify, and distribute this 011 * software and its documentation for any purpose, provided that the above 012 * copyright notice and the following two paragraphs appear in all copies 013 * of this software. 014 * 015 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY 016 * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 017 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF 018 * THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF 019 * SUCH DAMAGE. 020 * 021 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, 022 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 023 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE 024 * PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF 025 * CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, 026 * ENHANCEMENTS, OR MODIFICATIONS. 027 * 028 */ 029 030package org.ecoinformatics.seek.sms; 031 032/** 033 *@author Shawn Bowers 034 * 035 * A quick hack at a start to a local Kepler LSID suite of services 036 * for kepler. This ultimately is an implementation of each 037 * LSIDxyzService, but is local to Kepler. Not sure how all of this 038 * will eventually work ... 039 * 040 * This class locally maintains the default actor library. The actor 041 * library is passed at start up; and a hash table is created of all 042 * named objects in the library. New objects can be added, etc. 043 * Each new addition or change should update default actor library, 044 * persisting the change locally. 045 */ 046 047import java.io.BufferedWriter; 048import java.io.File; 049import java.io.FileWriter; 050import java.util.Enumeration; 051import java.util.Hashtable; 052import java.util.Iterator; 053import java.util.List; 054import java.util.StringTokenizer; 055import java.util.Vector; 056 057import org.kepler.moml.NamedObjId; 058 059import ptolemy.actor.lib.Const; 060import ptolemy.kernel.ComponentEntity; 061import ptolemy.kernel.CompositeEntity; 062import ptolemy.kernel.util.Attribute; 063import ptolemy.kernel.util.NamedObj; 064import ptolemy.moml.EntityLibrary; 065import ptolemy.vergil.tree.EntityTreeModel; 066import ptolemy.vergil.tree.VisibleTreeModel; 067 068/* 069 * KeplerLocalLSIDService Interface 070 * { 071 * // singleton 072 * 073 * KeplerLocalLSIDService instance(); 074 * 075 * // initialization hacks, called from TabbedLibraryPane at setup 076 * 077 * void setBasicActorLibrary(EntityTreeModel _libraryModel); 078 * EntityTreeModel getBasicActorLibrary(); 079 * 080 * // lsid ops 081 * 082 * void assignLSID(String lsid, NamedObj obj); 083 * void updateLSID(String lsid, NamedObj obj); 084 * NamedObj getData(String lsid); 085 * Iterator<String> getLSIDFor(NamedObj obj) 086 * 087 * // helper ops 088 * 089 * String createLSID(String namespace, String id); 090 * String createLocallyUniqueLSID(String namespace); 091 * boolean isAssignedLSID(String lsid); 092 * boolean isWellFormedLSID(String lsid) 093 * Iterator<String> assignedLSIDs(); 094 * void commitChanges() 095 * } 096 */ 097 098/** 099 * Description of the Class 100 * 101 *@author berkley 102 *@created February 17, 2005 103 */ 104public class KeplerLocalLSIDService { 105 106 /* 107 * PRIVATE ATTRIBUTES 108 */ 109 // singleton instance 110 private static KeplerLocalLSIDService _service = null; 111 112 // indexed, main-memory storage and management 113 private Hashtable _assignedObjects = new Hashtable(); 114 // maps lsid -> namedObj 115 private EntityTreeModel _libraryModel = null; 116 // orig. lib. of actors 117 private Vector _managedLsids = new Vector(); 118 // list of managed lsids; that have been assigned 119 private Hashtable _lastDomainId = new Hashtable(); 120 // for finding new, unqiue domains 121 122 // references to the database of actors 123 private static String KEPLER = System.getProperty("KEPLER"); 124 private static String KEPLERACTORLIB = KEPLER 125 + "/configs/ptolemy/configs/kepler/basicKeplerActorLibrary.xml"; 126 127 // prefix for identifier 128 private static String URN = "urn"; 129 private static String LSID = "lsid"; 130 private static String DOMAIN = "localhost"; 131 132 /* 133 * PROTECTED CONSTRUCTOR 134 */ 135 /** Constructor for the KeplerLocalLSIDService object */ 136 protected KeplerLocalLSIDService() { 137 // construct a default library, prior to setBasicActorLibrary 138 _libraryModel = new VisibleTreeModel(new CompositeEntity()); 139 } 140 141 /* 142 * SINGLETON CONSTRUCTOR 143 */ 144 145 /** 146 *@return The unique instance of this class This must be called to 147 * create/obtain an instance of the service 148 */ 149 public static KeplerLocalLSIDService instance() { 150 if (_service == null) { 151 _service = new KeplerLocalLSIDService(); 152 } 153 return _service; 154 } 155 156 /* 157 * INITIALIZATION 158 */ 159 160 /** 161 * Assigns the current kepler actor library. Clears current set of lsid 162 * objects. This operation is here because there isn't a great way in 163 * Kepler/Ptolemy to access "global" objects. Here, we grab the library 164 * model that is initially given to Kepler when the graph editor starts up. 165 * 166 *@param _libraryModel 167 * The current kepler actor library 168 */ 169 public void setBasicActorLibrary(EntityTreeModel _libraryModel) { 170 // clear the hashtable 171 _assignedObjects = new Hashtable(); 172 // set the library model 173 this._libraryModel = _libraryModel; 174 // load up the hashtable 175 getNamedObjIds(_libraryModel.getRoot()); 176 177 } 178 179 /** 180 * This operation provides access to the assigned library model. 181 * 182 *@return The current kepler actor library 183 */ 184 public EntityTreeModel getBasicActorLibrary() { 185 return _libraryModel; 186 } 187 188 // ......... 189 // recursive helper function to traverse and pull out the named 190 // objects with ids 191 // ......... 192 /** 193 * Gets the namedObjIds attribute of the KeplerLocalLSIDService object 194 * 195 *@param parent 196 * Description of the Parameter 197 */ 198 private void getNamedObjIds(Object parent) { 199 // check if the parent has an id, and if so add to hashtable 200 if (parent instanceof NamedObj) { 201 _addNamedObject((NamedObj) parent); 202 } 203 // iterator over children 204 for (int i = 0; i < _libraryModel.getChildCount(parent); i++) { 205 getNamedObjIds(_libraryModel.getChild(parent, i)); 206 } 207 } 208 209 /* 210 * MAIN LSID OPERATIONS 211 */ 212 213 /** 214 * Adds a named object to an lsid that hasn't been previously assigned. The 215 * lsid cannot be previously assigned to an object. To create a well-formed 216 * lsid, use createLSID. 217 * 218 *@param obj 219 * The object to assign an lsid to 220 *@param lsid 221 * Description of the Parameter 222 *@exception IllegalLSIDAssignmentException 223 * Description of the Exception 224 *@return true if the object was assigned to the lsid correctly, false 225 * otherwise. 226 */ 227 public void assignLSID(String lsid, NamedObj obj) 228 throws IllegalLSIDAssignmentException { 229 // the lsid must not be assigned 230 if (_assignedObjects.containsKey(lsid)) { 231 throw new IllegalLSIDAssignmentException(lsid 232 + " already assigned to an object"); 233 } 234 235 // make sure there isn't already an obj with the same entity name 236 // to be assigned 237 Enumeration e = _assignedObjects.elements(); 238 while (e.hasMoreElements()) { 239 NamedObj assignedObj = (NamedObj) e.nextElement(); 240 String name = assignedObj.getName(); 241 if (name.equals(obj.getName())) { 242 String msg = "Object name '" + obj.getName() 243 + "' already exists in library"; 244 throw new IllegalLSIDAssignmentException(msg); 245 } 246 } 247 248 try { 249 // add the id 250 NamedObjId objId = new NamedObjId(obj, NamedObjId.NAME); 251 objId.setContainer(obj); 252 objId.setExpression(lsid); 253 // update the assigned objects 254 _assignedObjects.put(lsid, obj); 255 if (!_managedLsids.contains(lsid)) { 256 _managedLsids.add(lsid); 257 } 258 } catch (ptolemy.kernel.util.NameDuplicationException nde) { 259 // don't add the entity id, but do add the lsid to the DB. 260 _assignedObjects.put(lsid, obj); 261 if (!_managedLsids.contains(lsid)) { 262 _managedLsids.add(lsid); 263 } 264 } catch (Exception ex) { 265 throw new IllegalLSIDAssignmentException(ex.toString()); 266 } 267 } 268 269 /** 270 * Updates a previously assigned lsid to be assigned the given object. 271 * Removes the old object from the actor library, and adds the given object. 272 * 273 *@param lsid 274 * the lsid to update 275 *@param obj 276 * the new object to connect to the lsid 277 *@exception IllegalLSIDAssignmentException 278 * Description of the Exception 279 */ 280 public void updateLSID(String lsid, NamedObj obj) 281 throws IllegalLSIDAssignmentException { 282 // the lsid must be assigned 283 if (!_assignedObjects.containsKey(lsid)) { 284 throw new IllegalLSIDAssignmentException( 285 lsid 286 + " cannot be updated because it is not assigned to an object"); 287 } 288 try { 289 NamedObj oldObj = (NamedObj) _assignedObjects.get(lsid); 290 if (oldObj instanceof Attribute) { 291 ((Attribute) oldObj).setContainer(null); 292 } else if (oldObj instanceof ComponentEntity) { 293 ((ComponentEntity) oldObj).setContainer(null); 294 } 295 _assignedObjects.remove(lsid); 296 // need to remove the object from the actor library!!! 297 assignLSID(lsid, obj); 298 } catch (Exception e) { 299 throw new IllegalLSIDAssignmentException(e.toString()); 300 } 301 } 302 303 /* 304 * LSID HELPER OPERATIONS 305 */ 306 /** 307 *@param namespace 308 * Description of the Parameter 309 *@param id 310 * Description of the Parameter 311 *@exception IllegalLSIDException 312 * Description of the Exception 313 *@return an lsid with the default domain and the given namespace and id 314 */ 315 public String createLSID(String namespace, String id) 316 throws IllegalLSIDException { 317 String lsid = URN + ":" + LSID + ":" + DOMAIN + ":" + namespace + ":" 318 + id; 319 if (!isWellFormedLSID(lsid)) { 320 throw new IllegalLSIDException(lsid); 321 } 322 return lsid; 323 } 324 325 /** 326 * This is a simple algorithm that computes a new id for a given namespace 327 * in the default domain. Appends a LOCALID to the id, so shouldn't be 328 * duplicated in other ids in the same domain. 329 * 330 *@param namespace 331 * Description of the Parameter 332 *@return a unqiue lsid, relevant to assigned lsids, for the given 333 * namespace. 334 */ 335 public String createLocallyUniqueLSID(String namespace) { 336 try { 337 boolean found = false; 338 Integer id = (Integer) _lastDomainId.get(namespace); 339 if (id == null) 340 id = new Integer(-1); 341 int newId = id.intValue(); 342 while (!found) { 343 newId = newId + 1; 344 String lsid = createLSID(namespace, "LOCALID" + newId); 345 if (!isAssignedLSID(lsid)) { 346 found = true; 347 if (_lastDomainId.contains(namespace)) { 348 _lastDomainId.remove(namespace); 349 } 350 _lastDomainId.put(namespace, new Integer(newId)); 351 } 352 } 353 return createLSID(namespace, "LOCALID" + newId); 354 } catch (Exception e) { 355 e.printStackTrace(); 356 } 357 return null; 358 } 359 360 /** 361 *@param obj 362 * Description of the Parameter 363 *@return The lSIDFor value 364 */ 365 public Iterator getLSIDFor(NamedObj obj) { 366 Vector result = new Vector(); 367 368 if (_assignedObjects.containsValue(obj)) { 369 Enumeration keys = _assignedObjects.keys(); 370 // for each key, check if the associated object equals 371 // this object and if so, add to result 372 while (keys.hasMoreElements()) { 373 String lsid = (String) keys.nextElement(); 374 NamedObj tmp = (NamedObj) _assignedObjects.get(lsid); 375 if (tmp.equals(obj)) { 376 result.add(lsid); 377 } 378 } 379 } 380 return result.iterator(); 381 } 382 383 /** 384 *@param lsid 385 * the lsid to test 386 *@return true if the given lsid is known to the service 387 */ 388 public boolean isAssignedLSID(String lsid) { 389 return _managedLsids.contains(lsid); 390 } 391 392 /** 393 *@param lsid 394 * the lsid to test 395 *@return true if the lsid is well formed, false otherwise 396 */ 397 public boolean isWellFormedLSID(String lsid) { 398 String delim = ":"; 399 StringTokenizer strTok = new StringTokenizer(lsid, delim, false); 400 String str = ""; 401 try { 402 // urn part 403 str = strTok.nextToken(); 404 if (!str.equals(URN)) { 405 return false; 406 } 407 // lsid 408 str = strTok.nextToken(); 409 if (!str.equals(LSID)) { 410 return false; 411 } 412 // the domain 413 str = strTok.nextToken(); 414 if (containsWhiteSpace(str)) { 415 return false; 416 } 417 // the namespace 418 str = strTok.nextToken(); 419 if (containsWhiteSpace(str)) { 420 return false; 421 } 422 // the id 423 str = strTok.nextToken(); 424 if (containsWhiteSpace(str)) { 425 return false; 426 } 427 // the optional version 428 if (strTok.hasMoreTokens() 429 && containsWhiteSpace(strTok.nextToken())) { 430 return false; 431 } 432 // no more tokens 433 if (strTok.hasMoreTokens()) { 434 return false; 435 } 436 return true; 437 } catch (Exception e) { 438 return false; 439 } 440 } 441 442 /** 443 * Description of the Method 444 * 445 *@param str 446 * Description of the Parameter 447 *@return Description of the Return Value 448 */ 449 private boolean containsWhiteSpace(String str) { 450 StringTokenizer strTok = new StringTokenizer(str); 451 return (strTok.countTokens() != 1); 452 } 453 454 /** 455 *@param lsid 456 * Description of the Parameter 457 *@return null if not a resolvable lsid (i.e., unknown lsid) 458 */ 459 public NamedObj getData(String lsid) { 460 return (NamedObj) _assignedObjects.get(lsid); 461 } 462 463 /** 464 * Adds a new NamedObj instance to the engine 465 * 466 *@param obj 467 * the instance to add, which must have an NamedObjId property 468 *@return true if the item was added successfully 469 */ 470 private boolean _addNamedObject(NamedObj obj) { 471 List idAtts = obj.attributeList(NamedObjId.class); 472 Iterator iter = idAtts.iterator(); 473 boolean result = iter.hasNext(); 474 while (iter.hasNext()) { 475 NamedObjId id = (NamedObjId) iter.next(); 476 // check if it is already there ... 477 if (!_assignedObjects.containsKey(id.getExpression())) { 478 String lsid = id.getExpression(); 479 if (!_managedLsids.contains(lsid)) { 480 _managedLsids.add(lsid); 481 } 482 _assignedObjects.put(lsid, obj); 483 } 484 } 485 return result; 486 } 487 488 /** TODO: throw error */ 489 public void commitChanges() { 490 491 try { 492 // open the KEPLERACTORLIB file 493 File file = new File(KEPLERACTORLIB); 494 BufferedWriter output = new BufferedWriter(new FileWriter(file)); 495 496 // write out the header of the file 497 output.write("<?xml version=\"1.0\" standalone=\"no\"?>\n"); 498 output 499 .write("<!DOCTYPE plot PUBLIC \"-//UC Berkeley//DTD MoML 1//EN\"\n"); 500 output 501 .write("\"http://ptolemy.eecs.berkeley.edu/xml/dtd/MoML_1.dtd\">\n"); 502 output.write("<group>\n"); 503 504 // add each unique item in the hashtable to root 505 Vector objsToAdd = new Vector(); 506 Enumeration e = _assignedObjects.elements(); 507 while (e.hasMoreElements()) { 508 NamedObj obj = (NamedObj) e.nextElement(); 509 if (!objsToAdd.contains(obj)) { 510 objsToAdd.add(obj); 511 } 512 } 513 514 for (Iterator i = objsToAdd.iterator(); i.hasNext();) { 515 NamedObj obj = (NamedObj) i.next(); 516 output.write("\n" + obj.exportMoML() + "\n"); 517 } 518 output.write("</group>\n"); 519 520 // close the file 521 output.close(); 522 523 } catch (Exception e) { 524 e.printStackTrace(); 525 } 526 527 } 528 529 /** 530 * Description of the Method 531 * 532 *@return Description of the Return Value 533 */ 534 public Iterator assignedLSIDs() { 535 return _managedLsids.iterator(); 536 } 537 538 /* 539 * Testing 540 */ 541 542 // for testing 543 /** 544 * The main program for the KeplerLocalLSIDService class 545 * 546 *@param args 547 * The command line arguments 548 */ 549 public static void main(String[] args) { 550 KeplerLocalLSIDService serv = KeplerLocalLSIDService.instance(); 551 try { 552 System.out.println(">>> Assigning const"); 553 String lsid = serv.createLSID("bowers", "myFavoriteService"); 554 Const c = new Const(new EntityLibrary(), "myConst"); 555 serv.assignLSID(lsid, c); 556 557 System.out.println(">>> Assigning another const"); 558 String lsid0 = serv.createLSID("bowers", "myOtherFavoriteService"); 559 System.out.println(">>> Updating const"); 560 Const c0 = new Const(new EntityLibrary(), "myFufuConst"); 561 serv.updateLSID(lsid, c0); 562 563 serv.commitChanges(); 564 565 } catch (Exception e) { 566 e.printStackTrace(); 567 } 568 } 569 570}