001/* 002 * Copyright (c) 2009-2010 The Regents of the University of California. 003 * All rights reserved. 004 * 005 * '$Author: aschultz $' 006 * '$Date: 2011-03-02 19:59:11 +0000 (Wed, 02 Mar 2011) $' 007 * '$Revision: 27233 $' 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.kepler.objectmanager; 031 032import java.util.ArrayList; 033import java.util.Collections; 034import java.util.HashMap; 035import java.util.Iterator; 036import java.util.Map; 037import java.util.Vector; 038 039import org.apache.commons.logging.Log; 040import org.apache.commons.logging.LogFactory; 041import org.kepler.moml.NamedObjId; 042import org.kepler.objectmanager.cache.CacheException; 043import org.kepler.objectmanager.cache.CacheManager; 044import org.kepler.objectmanager.cache.CacheObject; 045import org.kepler.objectmanager.cache.CacheObjectInterface; 046import org.kepler.objectmanager.lsid.KeplerLSID; 047 048import ptolemy.kernel.CompositeEntity; 049import ptolemy.kernel.util.NamedObj; 050 051/** 052 * The ObjectManager searches through all of the NamedObj Objects in the 053 * workspace to see if any of them have a KeplerLSID associated with them. 054 * 055 * @author Aaron Schultz 056 * @version $Id: ObjectManager.java 27233 2011-03-02 19:59:11Z aschultz $ 057 * 058 */ 059public class ObjectManager { 060 061 private static final Log log = LogFactory.getLog(ObjectManager.class 062 .getName()); 063 private static final boolean isDebugging = log.isDebugEnabled(); 064 065 // WeakHashMap will discard items required during KAR save process 066 // (refactored so this is probably only the workflow now). 067 // see: http://bugzilla.ecoinformatics.org/show_bug.cgi?id=5200 068 //private WeakHashMap<KeplerLSID, NamedObj> _namedObjs; 069 private Map<KeplerLSID, NamedObj> _namedObjs; 070 071 /** 072 * Empty constructor 073 */ 074 public ObjectManager() { 075 //_namedObjs = new WeakHashMap<KeplerLSID, NamedObj>(1); 076 HashMap<KeplerLSID, NamedObj> hashMap = new HashMap<KeplerLSID, NamedObj>(1); 077 _namedObjs = Collections.synchronizedMap(hashMap); 078 } 079 080 /** 081 * Add a NamedObject to the ObjectManager. These are searched when getting 082 * an object by LSID. 083 * 084 * @param namedObj 085 * @throws Exception 086 */ 087 public void addNamedObj(NamedObj namedObj) throws Exception { 088 KeplerLSID lsid = NamedObjId.getIdFor(namedObj); 089 //Set<KeplerLSID> keys = _namedObjs.keySet(); 090 //Collection<NamedObj> values = _namedObjs.values(); 091 if (_namedObjs.containsKey(lsid)) { 092 _namedObjs.remove(lsid); 093 } 094 _namedObjs.put(lsid, namedObj); 095 } 096 097 098 /** 099 * Attempt to remove NamedObj from ObjectManager: 100 * if getIdFor(namedObj) returns an LSID for an object 101 * in the ObjectManager, it will be removed. 102 * 103 * @param namedObj 104 * @return removed NamedObj, or null if none. 105 */ 106 public NamedObj removeNamedObj(NamedObj namedObj) { 107 KeplerLSID lsid = NamedObjId.getIdFor(namedObj); 108 return _namedObjs.remove(lsid); 109 } 110 111 /** 112 * Attempt to remove NamedObj from ObjectManager: 113 * if getIdFor(namedObj) returns an LSID for an object 114 * in the ObjectManager, it will be removed. 115 * 116 * @param namedObj 117 * @return removed NamedObj, or null if none. 118 */ 119 public ArrayList<NamedObj> removeNamedObjs(NamedObj namedObj) { 120 KeplerLSID lsid = NamedObjId.getIdFor(namedObj); 121 //it is modified because of bug // http://bugzilla.ecoinformatics.org/show_bug.cgi?id=5095#c14 122 // the reason is because the lsid of an updated namedObj is changed, the old method won't remove the old versions of namedObj. 123 //return _namedObjs.remove(lsid); 124 return removeObjectsForLSIDWithoutRevision(lsid.toStringWithoutRevision()); 125 } 126 127 /** 128 * Attempts to remove object from ObjectManager: 129 * if getObjectRevision(lsid) returns a NamedObj, calls removeNamedObj on 130 * this NamedObj. 131 * 132 * NOTE: Chances are good this won't remove the NamedObj you want. 133 * 134 * @param lsid 135 * @return removed NamedObj, or null if none. 136 * @throws Exception 137 */ 138 public NamedObj removeObject(KeplerLSID lsid) throws Exception { 139 if (isDebugging) 140 log.debug("removeObject(" + lsid + ")"); 141 NamedObj no = getObjectRevision(lsid); 142 if (no != null) { 143 return removeNamedObj(no); 144 } 145 return null; 146 } 147 148 /** 149 * @param lsid for the NamedObj to remove from ObjectManager 150 * @return the NamedObj removed, or null if none. 151 */ 152 public NamedObj removeObjectForLSID(KeplerLSID lsid){ 153 return _namedObjs.remove(lsid); 154 } 155 156 /** 157 * Remove all NamedObjects from ObjectManager that match this lsid without 158 * revision. 159 * @param lsidWithoutRevision 160 * @return ArrayList of NamedObjs that were removed. 161 */ 162 public ArrayList<NamedObj> removeObjectsForLSIDWithoutRevision(String lsidWithoutRevision){ 163 ArrayList<NamedObj> removedNamedObjects = new ArrayList<NamedObj>(); 164 Iterator<KeplerLSID> lsidItr = _namedObjs.keySet().iterator(); 165 ArrayList<KeplerLSID> lsidsToRemove = new ArrayList<KeplerLSID>(); 166 while (lsidItr.hasNext()){ 167 KeplerLSID lsid = lsidItr.next(); 168 if (lsid.toStringWithoutRevision().equals(lsidWithoutRevision)){ 169 lsidsToRemove.add(lsid); 170 } 171 } 172 173 lsidItr = lsidsToRemove.iterator(); 174 while(lsidItr.hasNext()){ 175 KeplerLSID lsid = lsidItr.next(); 176 NamedObj removedNamedObj = _namedObjs.remove(lsid); 177 removedNamedObjects.add(removedNamedObj); 178 } 179 180 return removedNamedObjects; 181 } 182 183 /** 184 * 185 * @param lsid 186 * @return 187 * @throws Exception 188 */ 189 public String getObjectType(KeplerLSID lsid) throws Exception { 190 if (isDebugging) 191 log.debug("getObjectType(" + lsid + ")"); 192 NamedObj no = getObjectRevision(lsid); 193 if (no == null) { 194 return null; 195 } 196 return no.getClass().getName(); 197 } 198 199 /** 200 * 201 * @param lsid 202 * @return 203 * @throws Exception 204 */ 205 public NamedObj getObjectRevision(KeplerLSID lsid) throws Exception { 206 if (isDebugging) { 207 log.debug("getObjectRevision(" + lsid + ")"); 208 printDebugInfo(); 209 } 210 211 boolean matchRevision = true; 212 213 NamedObj obj = getObjectFromManager(lsid, matchRevision); 214 if (obj == null) { 215 if (isDebugging) 216 log.debug(lsid + " is not registered with ObjectManager"); 217 obj = getObjectFromCache(lsid); 218 if (obj == null) { 219 if (isDebugging) 220 log.debug(lsid + " is not registered with CacheManager"); 221 } 222 } 223 224 if (obj != null) { 225 if (isDebugging) 226 log.debug(obj.getName() + " was found"); 227 // Make sure it has the NamedObjId Attribute 228 NamedObjId noi = NamedObjId.getIdAttributeFor(obj); 229 if (noi == null) { 230 NamedObjId lsidSA = new NamedObjId(obj, NamedObjId.NAME); 231 lsidSA.setExpression(lsid.toString()); 232 } else { 233 KeplerLSID lsidCheck = noi.getId(); 234 if (!lsidCheck.equals(lsid)) { 235 log.error("lsids don't match: " + lsid.toString() + " != " + lsidCheck); 236 noi.setExpression(lsid.toString()); 237 } 238 } 239 } 240 241 return obj; 242 } 243 244 /** 245 * Return the NamedObj that has the highest revision number for a given LSID 246 * after searching through all the NamedObjs accessible by the 247 * ObjectManager. If no NamedObj is found at all then try to get the highest 248 * revision from the cache. If that doesn't find anything then return null. 249 * This method will replace the existing getObject(KeplerLSID) method 250 * 251 * @param lsid 252 * @return 253 * @throws Exception 254 */ 255 public NamedObj getHighestObjectRevision(KeplerLSID lsid) throws Exception { 256 boolean matchRevision = false; 257 258 Vector<NamedObj> allObjs = new Vector<NamedObj>(); 259 260 for (NamedObj namedObj : _namedObjs.values()) { 261 if (namedObj instanceof CompositeEntity) { 262 Vector<NamedObj> theNOS = findAll(lsid, 263 (CompositeEntity) namedObj, matchRevision); 264 265 if (theNOS != null) { 266 for (NamedObj no : theNOS) { 267 allObjs.add(no); 268 } 269 } 270 } else { 271 if (NamedObjId.idMatches(lsid, namedObj, matchRevision)) { 272 allObjs.add(namedObj); 273 } 274 } 275 } 276 277 NamedObj noWithHighestLSID = null; 278 for (NamedObj no : allObjs) { 279 if (noWithHighestLSID == null) { 280 noWithHighestLSID = no; 281 } else { 282 NamedObjId idAtt = NamedObjId.getIdAttributeFor(no); 283 if (idAtt != null) { 284 KeplerLSID objId = idAtt.getId(); 285 286 NamedObjId noWithHighestIdAtt = NamedObjId.getIdAttributeFor(noWithHighestLSID); 287 KeplerLSID noWithHighestObjId = noWithHighestIdAtt.getId(); 288 289 if (objId.getRevision() > noWithHighestObjId.getRevision()) { 290 noWithHighestLSID = no; 291 } 292 } 293 } 294 } 295 296 if (noWithHighestLSID == null) { 297 // get the highest revision from the CacheManager 298 try { 299 CacheObject co = CacheManager.getInstance().getHighestCacheObjectRevision(lsid); 300 if (co != null){ 301 Object o = co.getObject(); 302 if (o instanceof NamedObj) { 303 noWithHighestLSID = (NamedObj) o; 304 } 305 } 306 } catch (CacheException ce) { 307 ce.printStackTrace(); 308 } 309 310 } 311 312 return noWithHighestLSID; 313 } 314 315 /** 316 * Return all of the NamedObjs contained by the given CompositeEntity that 317 * match the given lsid either with or without matching the revision as 318 * specified. 319 * 320 * @param lsid 321 * @param composite 322 * @param matchRevision 323 * @return 324 */ 325 private Vector<NamedObj> findAll(KeplerLSID lsid, 326 CompositeEntity composite, boolean matchRevision) { 327 Vector<NamedObj> objs = new Vector<NamedObj>(3); 328 329 if (NamedObjId.idMatches(lsid, (NamedObj) composite, matchRevision)) { 330 objs.add((NamedObj) composite); 331 } 332 333 for (Object obj : composite.entityList()) { 334 if (obj instanceof NamedObj) { 335 if (NamedObjId.idMatches(lsid, (NamedObj) obj, matchRevision)) { 336 objs.add((NamedObj) obj); 337 } 338 if (obj instanceof CompositeEntity) { 339 Vector<NamedObj> childObjs = findAll(lsid, 340 (CompositeEntity) obj, matchRevision); 341 if (childObjs != null && childObjs.size() > 0) { 342 for (NamedObj o : childObjs) { 343 objs.add(o); 344 } 345 } 346 } 347 } 348 } 349 350 if (objs.size() > 0) { 351 return objs; 352 } 353 return null; 354 } 355 356 /** 357 * Return a NamedObj that has been added to the ObjectManager. 358 * 359 * @param lsid 360 * @return 361 * @throws Exception 362 */ 363 private NamedObj getObjectFromManager(KeplerLSID lsid, boolean matchRevision) 364 throws Exception { 365 if (isDebugging) 366 log.debug("getObjectFromManager(" + lsid + "," + matchRevision 367 + ")"); 368 for (NamedObj namedObj : _namedObjs.values()) { 369 if (namedObj instanceof CompositeEntity) { 370 NamedObj theNO = checkComposite(lsid, 371 (CompositeEntity) namedObj, matchRevision); 372 373 if (theNO != null) { 374 if (isDebugging) 375 log.debug("Found NamedObj: " + theNO.getName() + " " 376 + NamedObjId.getIdFor(theNO)); 377 return theNO; 378 } 379 } else { 380 if (NamedObjId.idMatches(lsid, namedObj, matchRevision)) { 381 return namedObj; 382 } 383 } 384 } 385 return null; 386 } 387 388 /** 389 * Return a NamedObj that has been instantiated from the CacheManager. 390 * 391 * @param lsid 392 * @return 393 * @throws Exception 394 */ 395 private NamedObj getObjectFromCache(KeplerLSID lsid) throws Exception { 396 NamedObj obj = null; 397 398 CacheObjectInterface coi = CacheManager.getInstance().getObject(lsid); 399 if (coi != null) { 400 if (isDebugging) 401 log.debug("CacheObjectInterface found in CacheManager"); 402 Object o = coi.getObject(); 403 if (o != null) { 404 if (isDebugging) { 405 log.debug(o.getClass().getName()); 406 } 407 if (o instanceof NamedObj) { 408 obj = (NamedObj) o; 409 } else if (o instanceof ActorMetadata) { 410 ActorMetadata am = (ActorMetadata) o; 411 obj = am.getActor(); 412 } 413 } 414 } 415 return obj; 416 417 } 418 419 /** 420 * Deeply recurse all entities of the given composite entity and return the 421 * NamedObj that matches the search LSID 422 */ 423 private NamedObj checkComposite(KeplerLSID lsid, CompositeEntity composite, 424 boolean matchRevision) { 425 if (isDebugging) 426 log.debug("checkComposite(" + composite.getName() + ")"); 427 428 if (NamedObjId.idMatches(lsid, (NamedObj) composite, matchRevision)) { 429 return (NamedObj) composite; 430 } 431 432 for (Object obj : composite.entityList()) { 433 if (obj instanceof NamedObj) { 434 if (isDebugging) 435 log.debug(((NamedObj) obj).getName()); 436 if (NamedObjId.idMatches(lsid, (NamedObj) obj, matchRevision)) { 437 return (NamedObj) obj; 438 } 439 if (obj instanceof CompositeEntity) { 440 NamedObj theObj = checkComposite(lsid, 441 (CompositeEntity) obj, matchRevision); 442 if (theObj != null) { 443 return theObj; 444 } 445 } 446 } 447 } 448 return null; 449 } 450 451 /** 452 * Print the objects that are currently registered with the ObjectManager. 453 */ 454 public void printDebugInfo() { 455 System.out.println("*************" 456 + " NamedObjs registered with ObjectManager:"); 457 Iterator<KeplerLSID> lsidItr = _namedObjs.keySet().iterator(); 458 while (lsidItr.hasNext()){ 459 KeplerLSID lsid = lsidItr.next(); 460 System.out.println(_namedObjs.get(lsid).getName()+"=>"+lsid); 461 } 462 463 System.out.println("** getIdFor these NamedObj returns:"); 464 for (NamedObj no : _namedObjs.values()) { 465 System.out.println(no.getName() + " getIdFor("+no.getName()+"):" + NamedObjId.getIdFor(no)); 466 } 467 468 System.out.println("*************\n"); 469 470 } 471 472 /** 473 * Method for getting an instance of this singleton class. 474 */ 475 public static ObjectManager getInstance() { 476 return ObjectManagerHolder.INSTANCE; 477 } 478 479 private static class ObjectManagerHolder { 480 private static final ObjectManager INSTANCE = new ObjectManager(); 481 } 482}