001/* 002 * Copyright (c) 2010 The Regents of the University of California. 003 * All rights reserved. 004 * 005 * '$Author: crawl $' 006 * '$Date: 2015-10-28 20:48:37 +0000 (Wed, 28 Oct 2015) $' 007 * '$Revision: 34128 $' 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 030/** 031 * 032 */ 033package org.kepler.objectmanager.library; 034 035import java.io.File; 036import java.io.IOException; 037import java.sql.Connection; 038import java.sql.PreparedStatement; 039import java.sql.ResultSet; 040import java.sql.SQLException; 041import java.sql.Statement; 042import java.util.HashMap; 043import java.util.Hashtable; 044import java.util.Iterator; 045import java.util.Map; 046import java.util.Map.Entry; 047import java.util.Vector; 048import java.util.regex.Matcher; 049import java.util.regex.Pattern; 050 051import org.apache.commons.logging.Log; 052import org.apache.commons.logging.LogFactory; 053import org.kepler.build.modules.Module; 054import org.kepler.build.modules.ModuleTree; 055import org.kepler.build.util.Version; 056import org.kepler.kar.KARCacheContent; 057import org.kepler.kar.KARCacheError; 058import org.kepler.kar.KARCacheManager; 059import org.kepler.kar.KARCached; 060import org.kepler.kar.KAREntry; 061import org.kepler.kar.KARFile; 062import org.kepler.kar.handlers.ActorMetadataKAREntryHandler; 063import org.kepler.moml.KeplerActorMetadata; 064import org.kepler.moml.KeplerMetadataExtractor; 065import org.kepler.objectmanager.cache.ActorCacheObject; 066import org.kepler.objectmanager.cache.CacheContent; 067import org.kepler.objectmanager.cache.LocalRepositoryManager; 068import org.kepler.objectmanager.cache.LocalRepositoryManager.LocalRepository; 069import org.kepler.objectmanager.lsid.KeplerLSID; 070import org.kepler.sms.NamedOntClass; 071import org.kepler.sms.NamedOntModel; 072import org.kepler.sms.OntologyCatalog; 073import org.kepler.util.DotKeplerManager; 074import org.kepler.util.StatusNotifier; 075 076 077/** 078 * A library index for keeping track of the tree structure in the component 079 * library. This class uses preorder tree traversal method in an SQL table to 080 * maintain the indexed structure of the component library instead of using XML 081 * (as was previously done). This allows for easier control over the ordering of 082 * the contents of the tree, faster and more targeted access to the contents of 083 * the library using SQL queries (and some simple math), and it also introduces 084 * a very useful new Identifier for the contents of the tree, the LIID. 085 * 086 * Two companion tables, LIBRARY_LSIDS and LIBRARY_ATTRIBUTES, are used to store 087 * additional metadata about the library contents. The LIBRARY_LSIDS table 088 * serves to track the existence of multiple LSIDs for one single Component in 089 * the library. This is necessary for handling revision management and the user 090 * will be allowed to toggle which LSID the component is currently associated 091 * with, without destroying the look of the component library tree. The 092 * LIBRARY_ATTRIBUTES table is used for storing single string values that are 093 * associated with component library items. For example, a KAR item can have the 094 * location of that KAR on disk stored as an attribute of the library index 095 * item. 096 * 097 * @author Aaron Schultz 098 */ 099public class LibIndex { 100 private static final Log log = LogFactory.getLog(LibIndex.class.getName()); 101 private static final boolean isDebugging = log.isDebugEnabled(); 102 103 /** 104 * the name of the table in the database 105 */ 106 public static final String LIBRARY_INDEX_TABLE_NAME = "LIBRARY_INDEX"; 107 108 /** 109 * the name of the table in the database used to store attributes 110 */ 111 public static final String LIBRARY_LSIDS_TABLE_NAME = "LIBRARY_LSIDS"; 112 113 /** 114 * the name of the table in the database used to store attributes 115 */ 116 public static final String LIBRARY_ATTRIBUTES_TABLE_NAME = "LIBRARY_ATTRIBUTES"; 117 118 /** 119 * Map of integers for the different types of objects that are stored in the 120 * LIBRARY_INDEX table. To add a new type to the tree you must do a few 121 * things. Add a new static integer here. Modify LibraryManager.getTreeItem 122 * to handle the new type. Add methods to this class for recognizing the 123 * type in KAR files. 124 */ 125 public static final int TYPE_COMPONENT = 1; 126 public static final int TYPE_NAMED_OBJ = 2; 127 public static final int TYPE_ONTOLOGY = 3; 128 public static final int TYPE_CONCEPT = 4; 129 public static final int TYPE_FOLDER = 5; 130 public static final int TYPE_LOCALREPO = 6; 131 public static final int TYPE_KAR = 7; 132 public static final int TYPE_KAR_ERROR = 8; 133 public static final int TYPE_KARFOLDER = 9; 134 public static final int TYPE_OBJECT = 10; 135 136 /** 137 * Attribute names that are used to keep information about Library nodes. 138 */ 139 public static final String ATT_REPOPATH = "REPOPATH"; 140 public static final String ATT_FOLDER = "FOLDER"; 141 public static final String ATT_KARENTRYPATH = "KARENTRYPATH"; 142 public static final String ATT_KARFILE = "KARFILE"; 143 public static final String ATT_XMLFILE = "XMLFILE"; 144 public static final String ATT_CLASSNAME = "CLASSNAME"; 145 146 private LibSearch _searcher; 147 private Hashtable<Integer, Integer> _searchTypeMap; 148 149 // Convenience references 150 private Connection _conn; 151 private Statement _stmt; 152 153 // Prepared Statements 154 private PreparedStatement _updateOrderPrepStmt; 155 private PreparedStatement _updateLsidPrepStmt; 156 private PreparedStatement _getLIIDForKarPrepStmt; 157 private PreparedStatement _getLIIDForXMLPrepStmt; 158 private PreparedStatement _getLIIDForFolderPrepStmt; 159 private PreparedStatement _getLIIDForKarEntryPrepStmt; 160 private PreparedStatement _getLIIDForKarErrorPrepStmt; 161 private PreparedStatement _getLIIDForRepositoryPrepStmt; 162 private PreparedStatement _getLIIDForOntologyNamePrepStmt; 163 private PreparedStatement _getLIIDForOntologyClassPrepStmt; 164 private PreparedStatement _getNumRowsInLibraryIndexPrepStmt; 165 private PreparedStatement _getLIIDOfParentsPrepStmt; 166 private PreparedStatement _getLIIDForParentAndNamePrepStmt; 167 private PreparedStatement _getLIIDForNullParentAndNamePrepStmt; 168 private PreparedStatement _getRangeForLIIDPrepStmt; 169 private PreparedStatement _getLIIDForParentPrepStmt; 170 private PreparedStatement _getLftRgtSumPrepStmt; 171 private PreparedStatement _getLIIDRootsPrepStmt; 172 private PreparedStatement _deleteLIIDFromLibraryAttributesPrepStmt; 173 private PreparedStatement _insertIntoLibraryAttributesPrepStmt; 174 private PreparedStatement _getNumLIIDForLIIDAndLSIDPrepStmt; 175 private PreparedStatement _insertIntoLibraryLSIDsPrepStmt; 176 177 private LibraryManager _libraryManager; 178 179 /** Level for root objects in the tree. */ 180 private static final int ROOT_LEVEL = 1; 181 182 /** Root item for Demos */ 183 private LibItem _demosFolderItem; 184 185 /** Pattern for the modules' persistent workflow directory. */ 186 private Pattern _demosFolderPattern = Pattern.compile(Pattern 187 .quote(DotKeplerManager.getInstance() 188 .getPersistentModuleWorkflowsDirString()) 189 + "([^" + Pattern.quote(File.separator) + "]+)"); 190 191 /** 192 * There are two ways to insert rows into the table. One was is to have the 193 * insert statement handle the ordering of the hierarchy at insert time. 194 * This is very convenient for inserting just one row. But very time 195 * consuming for inserting many rows. For many rows, one may toggle the 196 * _orderedInsert to Off and once the rows have been inserted call the 197 * refreshPreorderValues method to order the rows based on parent 198 * relationships. 199 */ 200 private boolean _orderedInsert; 201 202 /** 203 * A constructor that is given a connection to the database. 204 * 205 * @param conn 206 */ 207 public LibIndex(Connection conn) { 208 initialize(conn); 209 } 210 211 /** 212 * Return the current value of orderedInsert. A value of false means that 213 * items inserted will not be automatically ordered during insert. 214 * 215 * @return 216 */ 217 public boolean isOrderedInsert() { 218 return _orderedInsert; 219 } 220 221 /** 222 * In general orderedInsert should always be true. When inserting many rows 223 * however it is faster to not order the entire table dynamically on every 224 * insert but to wait until all the rows have been inserted and then update 225 * the ordering based on parent relationships using the 226 * refreshPreorderValues method. This method allows you to toggle ordering 227 * during insert to on (true) or off (false). 228 * 229 * @param orderedInsert 230 */ 231 public void setOrderedInsert(boolean orderedInsert) { 232 _orderedInsert = orderedInsert; 233 } 234 235 /** 236 * Initialize the instance. 237 * 238 * @param conn 239 */ 240 private void initialize(Connection conn) { 241 if (isDebugging) 242 log.debug("initialize(" + conn.toString() + ")"); 243 _conn = conn; 244 245 _libraryManager = LibraryManager.getInstance(); 246 247 try { 248 // By creating the statement and keeping it around 249 // make sure to close your resultsets to save memory 250 _stmt = _conn.createStatement(); 251 252 _updateOrderPrepStmt = _conn.prepareStatement("update " 253 + LIBRARY_INDEX_TABLE_NAME 254 + " SET LFT=?, RGT=? WHERE LIID=?"); 255 _updateLsidPrepStmt = _conn.prepareStatement("update " 256 + LIBRARY_INDEX_TABLE_NAME + " SET LSID=? WHERE LIID=?"); 257 258 _getLIIDForKarPrepStmt = _conn.prepareStatement("SELECT LIID FROM " 259 + LIBRARY_ATTRIBUTES_TABLE_NAME + " WHERE NAME = '" 260 + ATT_KARFILE + "' AND VALUE = ?"); 261 262 _getLIIDForXMLPrepStmt = _conn.prepareStatement("SELECT LIID FROM " 263 + LIBRARY_ATTRIBUTES_TABLE_NAME + " WHERE NAME = '" 264 + ATT_XMLFILE + "' AND VALUE = ?"); 265 266 _getLIIDForFolderPrepStmt = _conn.prepareStatement("SELECT LIID FROM " 267 + LIBRARY_ATTRIBUTES_TABLE_NAME + " WHERE NAME = '" 268 + ATT_FOLDER + "' AND VALUE = ?"); 269 270 271 _getLIIDForKarEntryPrepStmt = _conn.prepareStatement("SELECT LIID FROM " 272 + LIBRARY_ATTRIBUTES_TABLE_NAME + " WHERE NAME = '" 273 + ATT_KARENTRYPATH + "' AND VALUE = ?"); 274 275 _getLIIDForKarErrorPrepStmt = _conn.prepareStatement("SELECT LIID FROM " 276 + LIBRARY_ATTRIBUTES_TABLE_NAME + " WHERE NAME = '" 277 + ATT_KARFILE + "' AND VALUE = ?"); 278 279 _getLIIDForRepositoryPrepStmt = _conn.prepareStatement("SELECT LIID FROM " 280 + LIBRARY_ATTRIBUTES_TABLE_NAME + " WHERE NAME = '" 281 + ATT_REPOPATH + "' AND VALUE = ?"); 282 283 _getLIIDForOntologyNamePrepStmt = _conn.prepareStatement("SELECT LIID FROM " 284 + LIBRARY_INDEX_TABLE_NAME + " WHERE NAME = ? AND LEVEL = 1"); 285 286 _getLIIDForOntologyClassPrepStmt = _conn.prepareStatement("SELECT LIID FROM " 287 + LIBRARY_INDEX_TABLE_NAME + " WHERE LSID = ?"); 288 289 _getNumRowsInLibraryIndexPrepStmt = _conn.prepareStatement("SELECT count(LIID) from " 290 + LIBRARY_INDEX_TABLE_NAME); 291 292 _getLIIDOfParentsPrepStmt = _conn.prepareStatement("SELECT LIID from " 293 + LIBRARY_INDEX_TABLE_NAME + " WHERE LFT < ? AND RGT > ? " 294 + "ORDER BY LEVEL"); 295 296 _getLIIDForParentAndNamePrepStmt = _conn.prepareStatement("select liid from " 297 + LIBRARY_INDEX_TABLE_NAME + " where parent = ? and name = ?"); 298 299 _getLIIDForNullParentAndNamePrepStmt = _conn.prepareStatement("select LIID from " 300 + LIBRARY_INDEX_TABLE_NAME + " where PARENT IS NULL AND NAME = ?"); 301 302 _getRangeForLIIDPrepStmt = _conn.prepareStatement("SELECT LFT,RGT from " 303 + LIBRARY_INDEX_TABLE_NAME + " WHERE LIID = ?"); 304 305 _getLIIDForParentPrepStmt = _conn.prepareStatement("SELECT liid FROM " 306 + LIBRARY_INDEX_TABLE_NAME + " WHERE parent = ? ORDER BY TYPE,NAME"); 307 308 _getLftRgtSumPrepStmt = _conn.prepareStatement("select (sum(LFT) + sum(RGT)) FROM " 309 + LIBRARY_INDEX_TABLE_NAME); 310 311 _getLIIDRootsPrepStmt = _conn.prepareStatement("SELECT LIID FROM " 312 + LIBRARY_INDEX_TABLE_NAME + " WHERE LEVEL = 1 ORDER BY TYPE,NAME"); 313 314 _deleteLIIDFromLibraryAttributesPrepStmt = _conn.prepareStatement("DELETE FROM " 315 + LIBRARY_ATTRIBUTES_TABLE_NAME + " WHERE LIID = ?"); 316 317 _insertIntoLibraryAttributesPrepStmt = _conn.prepareStatement("INSERT INTO " 318 + LIBRARY_ATTRIBUTES_TABLE_NAME + " (LIID,NAME,VALUE) values (?, ?, ?)"); 319 320 _getNumLIIDForLIIDAndLSIDPrepStmt = _conn.prepareStatement("SELECT count(LIID) FROM " 321 + LIBRARY_LSIDS_TABLE_NAME + " WHERE LIID = ? AND LSID = ?"); 322 323 _insertIntoLibraryLSIDsPrepStmt = _conn.prepareStatement("insert into " 324 + LIBRARY_LSIDS_TABLE_NAME + " (LIID,LSID) values (?,?)"); 325 326 } catch (SQLException e) { 327 e.printStackTrace(); 328 } 329 330 // Share the connection with the LibSearch 331 _searcher = new LibSearch(_conn); 332 initSearchMap(); 333 334 setOrderedInsert(true); 335 } 336 337 /** 338 * Delete all rows in the LIBRARY_INDEX table. This will also delete all 339 * rows in the LIBRARY_ATTRIBUTES table by cascading foreign key deletes. 340 */ 341 public void clear() { 342 String clear = "delete from " + LIBRARY_INDEX_TABLE_NAME; 343 if (isDebugging) 344 log.debug(clear); 345 String resetAutoInc = "ALTER TABLE " + LIBRARY_INDEX_TABLE_NAME 346 + " ALTER COLUMN LIID RESTART WITH 1"; 347 if (isDebugging) 348 log.debug(resetAutoInc); 349 try { 350 _stmt.executeUpdate(clear); 351 _stmt.execute(resetAutoInc); 352 353 getSearcher().clear(); 354 _stmt.getConnection().commit(); 355 } catch (SQLException e) { 356 e.printStackTrace(); 357 } 358 359 _demosFolderItem = null; 360 } 361 362 /** 363 * Completely delete the library index and recreate it from the contents of 364 * cached KARs. 365 */ 366 public void rebuild() { 367 368 StatusNotifier.log("Building Library Index (this can take several minutes)."); 369 370 clear(); 371 372 setOrderedInsert(false); 373 try { 374 375 KARCacheManager kcm = KARCacheManager.getInstance(); 376 377 // Add all Kar Contents to the Library Index table 378 Vector<KARCacheContent> contents = kcm.getKARCacheContents(); 379 for (KARCacheContent content : contents) { 380 381 assureOntologyComponent(content); 382 assureKarEntry(content); 383 384 } 385 386 // Add all Kar Errors to the Library 387 Vector<KARCacheError> errors = kcm.getKARCacheErrors(); 388 for (KARCacheError error : errors) { 389 assureKarError(error); 390 } 391 392 for(File xmlFile : LocalRepositoryManager.getInstance().getXMLFiles()) { 393 assureXML(xmlFile); 394 } 395 396 // Refresh the ordering of the library (this is much faster than 397 // updating the order every time we insert) 398 refreshPreorderValues(); 399 400 // because we insert with no order here, we can't 401 // easily determine the path to any given LibItem 402 // so we wait until all individual LibItems have been 403 // created and ordered to finish up indexing the items 404 // for the search 405 finishSearchIndexing(); 406 407 } catch (SQLException e) { 408 e.printStackTrace(); 409 } 410 setOrderedInsert(true); 411 } 412 413 /** 414 * Select all of the existing LibItems from the Library Index and insert all 415 * of their parent items into the Search Index. 416 * 417 * @throws SQLException 418 */ 419 private void finishSearchIndexing() throws SQLException { 420 Vector<LibItem> items = getItems(); 421 for (LibItem item : items) { 422 addAllParentsToSearchIndex(item); 423 } 424 } 425 426 /** 427 * Update the default LSID for the given LIID to the given LSID. 428 * 429 * @param liid 430 * @param lsid 431 * @throws SQLException 432 */ 433 public void updateDefaultLsid(int liid, KeplerLSID lsid) 434 throws SQLException { 435 if (isDebugging) 436 log.debug("updateDefaultLsid(" + liid + "," + lsid + ")"); 437 438 try { 439 _updateLsidPrepStmt.setString(1, lsid.toString()); 440 _updateLsidPrepStmt.setInt(2, liid); 441 442 _updateLsidPrepStmt.executeUpdate(); 443 _updateLsidPrepStmt.clearParameters(); 444 _conn.commit(); 445 } catch (SQLException sqle) { 446 throw sqle; 447 } 448 } 449 450 /** 451 * Remove all data from the index database that is associated with the given 452 * Library Index ID and all of the data of it's children. 453 * 454 * @param liid 455 * @return 456 */ 457 public boolean removeItem(int liid) { 458 boolean success = false; 459 LibItem li = null; 460 try { 461 li = _libraryManager.getPopulatedLibItem(liid); 462 } catch (SQLException e) { 463 // TODO Auto-generated catch block 464 e.printStackTrace(); 465 } 466 if (li != null) { 467 success = removeItem(li); 468 } 469 return success; 470 } 471 472 /** 473 * Remove all data from the index database that is associated with the given 474 * Library Item (using the Library Index ID) and all of the data of it's 475 * children. This method is the same as removeItem(int liid). It is here for 476 * convenience. 477 * 478 * @param li 479 * @return 480 */ 481 public boolean removeItem(LibItem li) { 482 String delete = "DELETE FROM " + LibIndex.LIBRARY_INDEX_TABLE_NAME 483 + " WHERE LIID = " + li.getLiid(); 484 // NOTE: the Foreign Key to the parent LIID prevents us from doing this: 485 // + " WHERE LFT >= " + li.getLeft() + " AND RGT <= " + li.getRight(); 486 // which is faster performance wise. Instead we'll trust the ON DELETE 487 // CASCADE for the parent foreign key to properly remove all the 488 // children of the LIID we're removing which is a little slower 489 // performance wise but still should work fine 490 491 String updateLFT = "UPDATE " + LibIndex.LIBRARY_INDEX_TABLE_NAME 492 + " SET LFT = LFT - " + (li.getRight() - li.getLeft() + 1) 493 + " WHERE LFT > " + li.getLeft(); 494 String updateRGT = "UPDATE " + LibIndex.LIBRARY_INDEX_TABLE_NAME 495 + " SET RGT = RGT - " + (li.getRight() - li.getLeft() + 1) 496 + " WHERE RGT > " + li.getLeft(); 497 try { 498 _stmt.executeUpdate(delete); 499 _stmt.executeUpdate(updateLFT); 500 _stmt.executeUpdate(updateRGT); 501 _stmt.getConnection().commit(); 502 } catch (Exception e) { 503 try { 504 _stmt.getConnection().rollback(); 505 } catch (SQLException e1) { 506 e1.printStackTrace(); 507 } 508 return false; 509 } 510 return true; 511 } 512 513 /** 514 * This method will remove the given LSID from being associated with any of 515 * the Library Items. If there is another LSID associated with the given 516 * item then it will be assigned as the default. If the Library Item is only 517 * associated with the given LSID then the Item itself will be removed. 518 * 519 * @param lsid 520 * @return Vector<Integer> all LIIDs that got removed 521 * @throws SQLException 522 */ 523 public Vector<Integer> removeItemsByLsid(KeplerLSID lsidToRemove) 524 throws SQLException { 525 Vector<Integer> liidsThatGotRemoved = new Vector<Integer>(); 526 527 // First keep the history of all LIIDs this LSID was associated with 528 Vector<KeplerLSID> kludge = new Vector<KeplerLSID>(1); 529 kludge.add(lsidToRemove); 530 Vector<Integer> liidAssociations = LibraryManager.getInstance() 531 .getLiidsFor(kludge); 532 533 // Now remove all the LIID -> LSID associations for this LSID 534 String remove = "DELETE FROM " + LIBRARY_LSIDS_TABLE_NAME 535 + " WHERE lsid = '" + lsidToRemove + "'"; 536 _stmt.executeUpdate(remove); 537 538 // Now go through all the liids 539 for (Integer liid : liidAssociations) { 540 // check if this LSID is the default LSID 541 String defaultQuery = "SELECT LSID FROM " 542 + LibIndex.LIBRARY_INDEX_TABLE_NAME + " WHERE LIID = " 543 + liid.intValue(); 544 if (isDebugging) 545 log.debug(defaultQuery); 546 ResultSet rs1 = null; 547 ResultSet rs2 = null; 548 try { 549 rs1 = _stmt.executeQuery(defaultQuery); 550 if (rs1 == null) 551 throw new SQLException("Query Failed: " + defaultQuery); 552 if (rs1.next()) { 553 String currentDefaultLsidStr = rs1.getString(1); 554 KeplerLSID currentDefaultLsid = null; 555 try { 556 currentDefaultLsid = new KeplerLSID(currentDefaultLsidStr); 557 } catch (Exception e) { 558 e.printStackTrace(); 559 } 560 if (currentDefaultLsid.equals(lsidToRemove)) { 561 // This is the default LSID 562 // check if there are any LSIDs that can become the new 563 // default 564 String newDefaultQuery = "SELECT LSID FROM " 565 + LIBRARY_LSIDS_TABLE_NAME 566 + " WHERE LIID = " + liid.intValue() 567 + " order by LSID DESC"; 568 if (isDebugging) 569 log.debug(newDefaultQuery); 570 rs2 = _stmt.executeQuery(newDefaultQuery); 571 if (rs2 == null) 572 throw new SQLException("Query Failed: " 573 + newDefaultQuery); 574 if (rs2.next()) { 575 // Yes there are other LSIDs associated with this LIID, 576 // set the first one we get back as the new default 577 // (hopefully the "order by DESC" will give us the 578 // highest revision) 579 String updateDefaultLSID = "UPDATE " 580 + LibIndex.LIBRARY_INDEX_TABLE_NAME 581 + " SET LSID = '" + rs2.getString(1) 582 + " WHERE LIID = " + liid.intValue(); 583 if (isDebugging) 584 log.debug(updateDefaultLSID); 585 _stmt.executeUpdate(updateDefaultLSID); 586 } else { 587 // No there are no more LSIDs associated with this LIID 588 // so let's remove this LIID if it is a leaf 589 LibItem li = _libraryManager.getPopulatedLibItem(liid); 590 // double check that this is a leaf node 591 if ((li.getRight() - li.getLeft()) == 1) { 592 li.delete(_stmt); 593 liidsThatGotRemoved.add(li.getLiid()); 594 } else { 595 // theoretically we never run into this BUT 596 // if we do let's go ahead and null out the 597 // default lsid 598 String updateDefaultLSID = "UPDATE " 599 + LibIndex.LIBRARY_INDEX_TABLE_NAME 600 + " SET LSID = NULL" + " WHERE LIID = " 601 + liid.intValue(); 602 _stmt.executeUpdate(updateDefaultLSID); 603 log 604 .warn("Nulled default LSID because the node is not a leaf"); 605 } 606 } 607 } else { 608 // This is not the default LSID so we're done with this one 609 } 610 } 611 } finally { 612 if(rs1 != null) { 613 rs1.close(); 614 } 615 if(rs2 != null) { 616 rs2.close(); 617 } 618 } 619 } 620 _stmt.getConnection().commit(); 621 return liidsThatGotRemoved; 622 } 623 624 /** 625 * Assures that the LibIndex row under the folder hierarchy exists for the 626 * given KARCacheContent. This method shouldn't really be used. It is only 627 * public so the LibraryManager.addKar() method can use it. 628 * 629 * @param content 630 * @throws SQLException 631 */ 632 public LibItem assureKarEntry(KARCacheContent content) throws SQLException { 633 if (isDebugging) 634 log.debug("assureKarEntry(" + content.getName() + ")"); 635 636 // add the object to the folders hierarchy 637 File karFile = content.getKarFile(); 638 String entry = content.getName(); 639 640 LibItem li = findKarEntry(karFile, entry); 641 if (li == null) { 642 LibItem liParent = null; 643 String[] entryPath = entry.split("/"); 644 if (entryPath.length > 1) { 645 // entry is in a subfolder 646 String folderPath = new String(); 647 for (int i = 0; i < (entryPath.length - 1); i++) { 648 folderPath = entryPath[i] + "/"; 649 } 650 folderPath = folderPath.substring(0, folderPath.length() - 1); 651 liParent = assureKarFolder(content.getKarCached(), folderPath); 652 } else { 653 liParent = assureKar(content.getKarCached()); 654 } 655 656 CacheContent cc = content.getCacheContent(); 657 String actorName = cc.getName(); 658 659 li = new LibItem(); 660 li.setName(actorName); 661 662 int t = determineLibIndexType(content); 663 if (t > 0) { 664 li.setType(t); 665 } else { 666 log 667 .error("Could not determine the LibIndex type for KARCacheContent"); 668 return null; 669 } 670 671 li.setParent(liParent.getLiid()); 672 li.setLevel(liParent.getLevel() + 1); 673 li.setLsid(content.getLsid()); 674 li.addAttribute(ATT_KARENTRYPATH, getKarEntryPath(karFile, entry)); 675 String className = content.getCacheContent().getClassName(); 676 if (className != null) { 677 li.addAttribute(ATT_CLASSNAME, className); 678 transferAttributes(li, content); 679 } 680 insertNoOrder(li); 681 682 } else { 683 // it is already there 684 // this is probably an unnecessary check 685 } 686 return li; 687 } 688 689 private static Map<KeplerLSID, Map<String, String>> cachedItemAttributes = new HashMap<KeplerLSID, Map<String, String>>(); 690 691 private void transferAttributes(LibItem li, KARCacheContent content) { 692 693 if (cachedItemAttributes.containsKey(li.getLsid())) { 694 Map<String, String> attributes = cachedItemAttributes.get(li.getLsid()); 695 for (String name : attributes.keySet()) { 696 li.addAttribute(name, attributes.get(name)); 697 } 698 return; 699 } 700 701 KARFile karFile = null; 702 try { 703 karFile = new KARFile(content.getKarFile()); 704 } 705 catch(IOException ex) { 706 ex.printStackTrace(); 707 } 708 709 KAREntry karEntry = new KAREntry(content.getName()); 710 ActorMetadataKAREntryHandler keh = new ActorMetadataKAREntryHandler(); 711 ActorCacheObject aco; 712 try { 713 aco = (ActorCacheObject) keh.cache(karFile, karEntry); 714 } 715 catch(Exception ex) { 716 ex.printStackTrace(); 717 return; 718 } 719 720 Map<String, String> attributes = new HashMap<String, String>(); 721 for (String attributeName : aco.getAttributeNames()) { 722 String attributeValue = aco.getAttribute(attributeName); 723 attributes.put(attributeName, attributeValue); 724 li.addAttribute(attributeName, attributeValue); 725 } 726 727 cachedItemAttributes.put(li.getLsid(), attributes); 728 } 729 730 /** 731 * Determine the appropriate LibIndex type of the given KARCacheContent 732 * 733 * @param kcc 734 * @return 735 */ 736 public int determineLibIndexType(KARCacheContent content) { 737 int theType = -1; 738 String cacheObjectType = content.getCacheContent().getType(); 739 boolean isActorCacheObject = false; 740 try { 741 String actorCacheObjectType = "org.kepler.objectmanager.cache.ActorCacheObject"; 742 if (cacheObjectType.equals(actorCacheObjectType)) { 743 isActorCacheObject = true; 744 } else if(cacheObjectType.equals("org.kepler.objectmanager.cache.TextFileCacheObject")) { 745 isActorCacheObject = false; 746 return LibIndex.TYPE_OBJECT; 747 } else { 748 isActorCacheObject = KARFile.isSubclass(actorCacheObjectType, 749 cacheObjectType); 750 } 751 } catch (ClassNotFoundException e) { 752 e.printStackTrace(); 753 } 754 if (isActorCacheObject) { 755 theType = LibIndex.TYPE_COMPONENT; 756 } else { 757 String entryObjectType = content.getType(); 758 boolean isGenericNamedObjType = false; 759 try { 760 String namedObjectType = "ptolemy.kernel.util.NamedObj"; 761 if (entryObjectType.equals(namedObjectType)) { 762 isGenericNamedObjType = true; 763 } else { 764 isGenericNamedObjType = KARFile.isSubclass(namedObjectType, 765 entryObjectType); 766 } 767 } catch (ClassNotFoundException e) { 768 e.printStackTrace(); 769 } 770 if (isGenericNamedObjType) { 771 theType = LibIndex.TYPE_NAMED_OBJ; 772 } else { 773 theType = LibIndex.TYPE_OBJECT; 774 } 775 } 776 return theType; 777 } 778 779 /** 780 * Assures that the LibIndex rows for the KARCacheContent object exist under 781 * the Ontology tree. This method shouldn't really be used. It is only 782 * public so the LibraryManager.addKar() method can use it. 783 * 784 * @param content 785 */ 786 public Vector<LibItem> assureOntologyComponent(KARCacheContent content) { 787 Vector<LibItem> items = new Vector<LibItem>(); 788 789 OntologyCatalog oc = OntologyCatalog.instance(); 790 791 // add the object in the ontology class hierarchy 792 for (KeplerLSID st : content.getSemanticTypes()) { 793 794 NamedOntClass noc = oc.getNamedOntClass(st.toString()); 795 if (noc != null) { 796 797 // First determine if the NamedOntClass belongs to 798 // an Ontology that is supposed to be showing up 799 // in the library. 800 boolean includeInOntologies = false; 801 Iterator<NamedOntModel> libraryModels = oc 802 .getLibraryNamedOntModels(); 803 while (libraryModels.hasNext()) { 804 if (libraryModels.next().equals(noc.getModel())) { 805 includeInOntologies = true; 806 break; 807 } 808 } 809 // If this NamedOntClass belongs to an Ontology Model 810 // that is configured to be included in the library 811 // then add it, otherwise just skip it 812 if (includeInOntologies) { 813 814 // Recurse up the tree 815 Vector<LibItem> parents = assureOntClass(noc); 816 for (LibItem parent : parents) { 817 818 CacheContent cc = content.getCacheContent(); 819 String actorName = cc.getName(); 820 821 LibItem li = new LibItem(); 822 li.setName(actorName); 823 li.setParent(parent.getLiid()); 824 KeplerLSID lsid = content.getLsid(); 825 if (lsid != null) { 826 li.setLsid(lsid); 827 } 828 829 // Figure out what LibIndex type this KARCacheContent is 830 int t = determineLibIndexType(content); 831 if (t > 0) { 832 li.setType(t); 833 } else { 834 log 835 .error("Could not determine the LibIndex type for KARCacheContent"); 836 continue; 837 } 838 839 li.setLevel(parent.getLevel() + 1); 840 841 String className = content.getCacheContent() 842 .getClassName(); 843 if (className != null) { 844 li.addAttribute(ATT_CLASSNAME, className); 845 transferAttributes(li, content); 846 } 847 try { 848 849 // See if this LibItem will collide with an existing LibItem 850 int liidOfExistingChild = childExists(li.getParent(),li.getName()); 851 if (liidOfExistingChild > -1) { 852 // A LIID with this name and parent already exists 853 // just add the LSID to the existing LIID item 854 insertLiidLsid(liidOfExistingChild, li.getLsid()); 855 } else { 856 // create a new item in the library 857 insertNoOrder(li); 858 items.add(li); 859 } 860 } catch (SQLException e) { 861 e.printStackTrace(); 862 } 863 } 864 } 865 } 866 } 867 return items; 868 } 869 870 /** 871 * Count how many rows there are in the LIBRARY_INDEX table. 872 * 873 * @return 874 */ 875 public int countItems() { 876 int count = 0; 877 try { 878 ResultSet rs = null; 879 try { 880 rs = _getNumRowsInLibraryIndexPrepStmt.executeQuery(); 881 if (rs == null) 882 return count; 883 if (rs.next()) { 884 count = rs.getInt(1); 885 if (rs.next()) { 886 // should never happen 887 throw new SQLException( 888 "Multiple rows found in countItems()"); 889 } 890 } 891 } finally { 892 if(rs != null) { 893 rs.close(); 894 } 895 } 896 } catch (SQLException sqle) { 897 sqle.printStackTrace(); 898 } 899 return count; 900 901 } 902 903 /** 904 * Returns a Vector of LibItems that are the parents of the given LibItem. 905 * 906 * @param li 907 * @return Vector<LibItem> representing all parents of the given LibItem 908 * @throws SQLException 909 */ 910 public Vector<LibItem> getPath(LibItem li) throws SQLException { 911 Vector<LibItem> pathItems = new Vector<LibItem>(); 912 913 _getLIIDOfParentsPrepStmt.setInt(1, li.getLeft()); 914 _getLIIDOfParentsPrepStmt.setInt(2, li.getRight()); 915 if (isDebugging) 916 log.debug(_getLIIDOfParentsPrepStmt); 917 ResultSet rs = null; 918 try { 919 rs = _getLIIDOfParentsPrepStmt.executeQuery(); 920 if (rs == null) 921 throw new SQLException("Query Failed: " + _getLIIDOfParentsPrepStmt); 922 while (rs.next()) { 923 int liid = rs.getInt(1); 924 LibItem parentItem = _libraryManager.getPopulatedLibItem(liid); 925 pathItems.add(parentItem); 926 } 927 } finally { 928 if(rs != null) { 929 rs.close(); 930 } 931 } 932 pathItems.add(li); 933 return pathItems; 934 } 935 936 /** 937 * Get all of the items. 938 * 939 * @return 940 */ 941 public Vector<LibItem> getItems() { 942 return getItemsOfType(-1, -1); 943 } 944 945 /** 946 * Get all items of the given type. 947 * 948 * @param type 949 * @return 950 */ 951 public Vector<LibItem> getItemsOfType(int type) { 952 return getItemsOfType(type, -1); 953 } 954 955 /** 956 * Return items of the given type that are somewhere under the given root. 957 * 958 * @param type 959 * @param root 960 * @return 961 */ 962 public Vector<LibItem> getItemsOfType(int type, int root) { 963 Vector<LibItem> items = new Vector<LibItem>(countItems()); 964 965 // TODO: actually select all the values instead of just the liid 966 String query = "SELECT LIID " + " FROM " + LIBRARY_INDEX_TABLE_NAME; 967 968 if (type <= 0 && root <= 0) { 969 // get everything 970 } else { 971 if (root > 0) { 972 // get items under the specified root node 973 try { 974 query += " WHERE " + getRange(root); 975 } catch (SQLException sqle) { 976 log.warn(root + " library item not found"); 977 return items; 978 } 979 if (type > 0) { 980 query += " AND TYPE = " + type; 981 } 982 } else { 983 // root <= 0 984 if (type > 0) { 985 // get everything with the specified type 986 query += " WHERE TYPE = " + type; 987 } 988 } 989 } 990 991 query += " ORDER BY LFT"; 992 993 try { 994 if (isDebugging) 995 log.debug(query); 996 ResultSet rs = null; 997 try { 998 rs = _stmt.executeQuery(query); 999 if (rs == null) 1000 throw new SQLException("Query Failed: " + query); 1001 while (rs.next()) { 1002 int liid = rs.getInt(1); 1003 // Doing it this way is kinda slow, but works for now 1004 LibItem li = _libraryManager.getPopulatedLibItem(liid); 1005 items.add(li); 1006 } 1007 } finally { 1008 if(rs != null) { 1009 rs.close(); 1010 } 1011 } 1012 } catch (SQLException sqle) { 1013 log.warn(root + " library item not found"); 1014 return items; 1015 } 1016 if (isDebugging) 1017 log.debug(items.size() + " library items found"); 1018 return items; 1019 } 1020 1021 /** 1022 * Convenience method for building the SQL string for queries needing the 1023 * range between an LIIDs LFT and RGT preorder values. 1024 * 1025 * @param liid 1026 * @return 1027 * @throws SQLException 1028 */ 1029 private String getRange(int liid) throws SQLException { 1030 String rangeString = new String(); 1031 _getRangeForLIIDPrepStmt.setInt(1, liid); 1032 ResultSet rs = null; 1033 try { 1034 rs = _getRangeForLIIDPrepStmt.executeQuery(); 1035 if (rs == null) 1036 throw new SQLException("Query Failed: " + _getRangeForLIIDPrepStmt); 1037 if (rs.next()) { 1038 int l = rs.getInt(1); 1039 int r = rs.getInt(2); 1040 rangeString += " LFT >= " + l + " AND "; 1041 rangeString += " RGT <= " + r; 1042 } 1043 } finally { 1044 if(rs != null) { 1045 rs.close(); 1046 } 1047 } 1048 return rangeString; 1049 1050 } 1051 1052 /** 1053 * Take a LibItem and check to see if there is already an entry 1054 * in the sql table for it depending on the type,name,and parent. 1055 * If there is already an item in the table, return the LIID for 1056 * the existing item. 1057 * 1058 * @param li 1059 * @return long LIID of existing item or -1 if no duplicate is found 1060 */ 1061 public int checkIfDuplicate(LibItem li) throws SQLException { 1062 int liid = -1; 1063 1064 _getLIIDForParentAndNamePrepStmt.setInt(1, li.getParent()); 1065 _getLIIDForParentAndNamePrepStmt.setString(2, li.getName()); 1066 ResultSet rs = null; 1067 try { 1068 rs = _getLIIDForParentAndNamePrepStmt.executeQuery(); 1069 if (rs == null) 1070 throw new SQLException("Query failed: " + _getLIIDForParentAndNamePrepStmt); 1071 if (rs.next()) { 1072 liid = rs.getInt(1); 1073 if (rs.wasNull()) { 1074 // bad news. 1075 liid = -1; 1076 } 1077 if (rs.next()) { 1078 // also bad news 1079 } 1080 } 1081 } finally { 1082 if(rs != null) { 1083 rs.close(); 1084 } 1085 } 1086 return liid; 1087 } 1088 1089 /** 1090 * Insert this LibItem into the table, make sure it doesn't already 1091 * exist. If it does try to add the LSID to the LIBRARY_LSIDS table. 1092 * 1093 * @param li 1094 * @throws SQLException 1095 */ 1096 private void insert(LibItem li) throws SQLException { 1097 if (isDebugging) 1098 log.debug("insert(" + li.getName() + ")"); 1099 1100 // Make sure there isn't an existing entry for this item 1101 int liidOfExistingChild = childExists(li.getParent(), li.getName()); 1102 if (liidOfExistingChild > -1) { 1103 try { 1104 // Add the lsid to the Library_lsids table if the item already exists 1105 insertLiidLsid(liidOfExistingChild, li.getLsid()); 1106 } catch (SQLException sqle) { 1107 throw new SQLException("Unable to insert LIID for existing child."); 1108 } 1109 } else { 1110 /** 1111 * Insert a new row for this LibItem under the parent liid or at level 1 if 1112 * parent is null. 1113 * 1114 */ 1115 String insert = "INSERT INTO " + LibIndex.LIBRARY_INDEX_TABLE_NAME 1116 + " (PARENT,LFT,RGT,LEVEL,LSID,TYPE,NAME) values ("; 1117 1118 int index = getAlphabeticInsertIndex(li); 1119 if (index < 0) 1120 return; 1121 1122 li.setLeft(index); 1123 li.setRight(index + 1); 1124 1125 if (li.getParent() == null) { 1126 insert += "NULL"; // parent 1127 } else { 1128 insert += "" + li.getParent(); // parent 1129 } 1130 1131 insert += "," + li.getLeft(); // left 1132 insert += "," + li.getRight(); // right 1133 insert += "," + li.getLevel(); // level 1134 1135 if (li.getLsid() != null) { 1136 insert += ",'" + li.getLsid().toString() + "'"; // lsid 1137 } else { 1138 insert += ",NULL"; 1139 } 1140 insert += "," + li.getType(); // type 1141 insert += ",'" + li.getName() + "'"; // name 1142 insert += ")"; 1143 1144 String updateLeft = "UPDATE " + LibIndex.LIBRARY_INDEX_TABLE_NAME 1145 + " SET LFT = LFT + 2 WHERE LFT >= " + li.getLeft(); 1146 String updateRight = "UPDATE " + LibIndex.LIBRARY_INDEX_TABLE_NAME 1147 + " SET RGT = RGT + 2 WHERE RGT >= " + li.getLeft(); 1148 1149 if (isDebugging) { 1150 log.debug("\n" + updateLeft + "\n" + updateRight + "\n" + insert); 1151 } 1152 1153 _stmt.executeUpdate(updateLeft); 1154 _stmt.executeUpdate(updateRight); 1155 _stmt.executeUpdate(insert); 1156 1157 // find out the auto assigned liid 1158 String queryNewLiid = "CALL IDENTITY();"; 1159 ResultSet rs = null; 1160 try { 1161 rs = _stmt.executeQuery(queryNewLiid); 1162 if (rs != null && rs.next()) { 1163 int newLiid = rs.getInt(1); 1164 if (!rs.wasNull()) { 1165 li.setLiid(newLiid); 1166 if (isDebugging) 1167 log.debug("IDENTITY: " + li.getLiid()); 1168 } else { 1169 log.error("Failed to retrieve auto assigned identity"); 1170 } 1171 } 1172 } finally { 1173 if(rs != null) { 1174 rs.close(); 1175 } 1176 } 1177 1178 // add the lsid to the LiidLsid table 1179 insertLiidLsid(li.getLiid(), li.getLsid()); 1180 insertAttributes(li); 1181 1182 LibraryManager.getInstance().getIndex().addToSearchIndex(li); 1183 1184 _stmt.getConnection().commit(); 1185 } 1186 } 1187 1188 private void insertAttributes(LibItem li) throws SQLException { 1189 1190 final int liid = li.getLiid(); 1191 1192 _deleteLIIDFromLibraryAttributesPrepStmt.setInt(1, liid); 1193 1194 if (isDebugging) log.debug(_deleteLIIDFromLibraryAttributesPrepStmt); 1195 _deleteLIIDFromLibraryAttributesPrepStmt.executeUpdate(); 1196 _stmt.getConnection().commit(); 1197 1198 for(Entry<String, String> entry : li.getAttributes().entrySet()) { 1199 final String attName = entry.getKey(); 1200 final String attValue = entry.getValue(); 1201 _insertIntoLibraryAttributesPrepStmt.setInt(1,liid); 1202 _insertIntoLibraryAttributesPrepStmt.setString(2, attName); 1203 _insertIntoLibraryAttributesPrepStmt.setString(3, attValue); 1204 if (isDebugging) log.debug(_insertIntoLibraryAttributesPrepStmt); 1205 _insertIntoLibraryAttributesPrepStmt.executeUpdate(); 1206 } 1207 _stmt.getConnection().commit(); 1208 } 1209 1210 /** 1211 * Figure out what the LEFT integer should be for a new row that is to be 1212 * inserted in alphabetical order for the current getParent() value. Or for 1213 * Level 1 if getParent() == null 1214 * 1215 * @param stmt 1216 * @return 1217 * @throws SQLException 1218 */ 1219 private int getAlphabeticInsertIndex(LibItem li) throws SQLException { 1220 int insertIndex = -1; 1221 1222 int parentLevel = 0; 1223 String query = "select LIID,RGT,LEVEL,LSID,NAME from " 1224 + LibIndex.LIBRARY_INDEX_TABLE_NAME; 1225 if (li.getParent() == null) { 1226 query += " where LEVEL = 1"; 1227 } else { 1228 query += " where PARENT = " + li.getParent(); 1229 } 1230 query += " order by NAME "; 1231 if (isDebugging) { 1232 log.debug(query); 1233 } 1234 ResultSet rs = null; 1235 int cnt = 0; 1236 try { 1237 rs = _stmt.executeQuery(query); 1238 if (rs == null) 1239 log.error("Query Failed: " + query); 1240 int prevRight = -1; 1241 while (rs.next()) { 1242 int liid = rs.getInt(1); // LIID 1243 int r = rs.getInt(2); // RGT 1244 parentLevel = rs.getInt(3) - 1; // LEVEL 1245 String lsid = rs.getString(4); // LSID 1246 String n = rs.getString(5); // NAME 1247 1248 int comparison = n.compareToIgnoreCase(li.getName()); 1249 if (comparison == 0) { 1250 log.debug(lsid); 1251 log.debug(li.getLsid()); 1252 if (lsid.equals(li.getLsid())) { 1253 log.debug("LSID matches"); 1254 throw new SQLException(li.getName() 1255 + " already exists as child of parent " 1256 + li.getParent()); 1257 } else { 1258 log.debug("LSID does not match"); 1259 try { 1260 // Add the lsid to the Library_lsids table 1261 insertLiidLsid(liid, li.getLsid()); 1262 return -1; 1263 } catch (SQLException sqle) { 1264 throw new SQLException("bummer"); 1265 } 1266 } 1267 } 1268 if (comparison > 0) { 1269 // we want to insert before this item 1270 if (cnt == 0) { 1271 // this is the first child 1272 // use the parents' left index 1273 break; 1274 } else { 1275 // use the right index of the previous row plus 1 1276 insertIndex = prevRight + 1; 1277 } 1278 } 1279 if (comparison < 0) { 1280 // Go on to the next child, unless there is no next child 1281 // for that case we'll set this to be the current right plus 1 1282 // every pass through the loop 1283 insertIndex = r + 1; 1284 } 1285 prevRight = r; 1286 cnt++; 1287 } 1288 } finally { 1289 if(rs != null) { 1290 rs.close(); 1291 } 1292 } 1293 1294 if (cnt == 0) { 1295 if (isDebugging) 1296 log.debug("No children found for parent " + li.getParent()); 1297 // Or we're inserting at the top of the list 1298 if (li.getParent() == null) { 1299 // we're inserting at the very beginning 1300 insertIndex = 0; 1301 } else { 1302 String parentQuery = "SELECT LFT,LEVEL from " 1303 + LibIndex.LIBRARY_INDEX_TABLE_NAME + " WHERE LIID = " 1304 + li.getParent(); 1305 if (isDebugging) { 1306 log.debug(parentQuery); 1307 } 1308 ResultSet parentResult = null; 1309 try { 1310 parentResult = _stmt.executeQuery(parentQuery); 1311 if (parentResult == null) 1312 log.error("Query Failed: " + parentQuery); 1313 if (parentResult.next()) { 1314 insertIndex = parentResult.getInt(1) + 1; 1315 parentLevel = parentResult.getInt(2); 1316 } 1317 } finally { 1318 if(parentResult != null) { 1319 parentResult.close(); 1320 } 1321 } 1322 } 1323 } 1324 if (isDebugging) 1325 log.debug("return: " + insertIndex); 1326 li.setLevel(parentLevel + 1); 1327 return insertIndex; 1328 } 1329 1330 1331 /** 1332 * Insert a LibItem row but do not update the lft and rgt ordering columns. 1333 * This method is useful only for doing bulk inserts of many rows at a time. 1334 * Then after a bunch of inserts the ordering must be updated by calling the 1335 * refreshPreorderValues() method. For only inserting one row and having the 1336 * ordering updated use the LibItem.insert() method. 1337 * 1338 * You can setOrderedInsert(true) to force insert by insert ordering in this 1339 * method. 1340 * 1341 * @param li 1342 */ 1343 private void insertNoOrder(LibItem li) throws SQLException { 1344 if (isDebugging) 1345 log.debug("insertNoOrder(" + li.getName() + ")"); 1346 1347 if (isOrderedInsert()) { 1348 if (isDebugging) 1349 log.debug("Do Ordered Insert"); 1350 insert(li); 1351 return; 1352 } 1353 1354 // else we insert without updating the preorder values 1355 if (isDebugging) 1356 log.debug("Do Unordered Insert"); 1357 1358 String insert = "INSERT INTO " + LibIndex.LIBRARY_INDEX_TABLE_NAME 1359 + " (PARENT,LFT,RGT,LEVEL,LSID,TYPE,NAME) values ("; 1360 1361 if (li.getParent() == null) { 1362 insert += "NULL"; // parent 1363 } else { 1364 insert += "" + li.getParent(); // parent 1365 } 1366 1367 insert += "," + li.getLeft(); // left 1368 insert += "," + li.getRight(); // right 1369 insert += "," + li.getLevel(); // level 1370 1371 if (li.getLsid() != null) { 1372 insert += ",'" + li.getLsid().toString() + "'"; // lsid 1373 } else { 1374 insert += ",NULL"; 1375 } 1376 insert += "," + li.getType(); // type 1377 insert += ",'" + li.getName() + "'"; // name 1378 insert += ")"; 1379 1380 if (isDebugging) 1381 log.debug(insert); 1382 1383 boolean itemInserted = false; 1384 try { 1385 int rows = _stmt.executeUpdate(insert); 1386 if (rows == 1) { 1387 itemInserted = true; 1388 } else { 1389 log.error("item was not inserted"); 1390 } 1391 } catch (SQLException sqle) { 1392 if (isDebugging) { 1393 log.debug("ERROR CODE: " + sqle.getErrorCode()); 1394 log.debug("ERROR MESSAGE: " + sqle.getMessage()); 1395 } 1396 if (sqle.getErrorCode() == -104) { 1397 // This Name already exists under this parent 1398 if (li.getType() == LibIndex.TYPE_COMPONENT 1399 || li.getType() == LibIndex.TYPE_NAMED_OBJ) { 1400 1401 // Add it to the Library_LSIDS table 1402 KeplerLSID lsid = li.getLsid(); 1403 if (lsid != null) { 1404 1405 int liid = checkIfDuplicate(li); 1406 if (liid < 0) { 1407 // not a duplicate 1408 } else { 1409 insertLiidLsid(liid, li.getLsid()); 1410 } 1411 1412 return; 1413 1414 } else { 1415 if (isDebugging) 1416 log.debug("lsid is null"); 1417 throw sqle; 1418 } 1419 } else { 1420 if (isDebugging) 1421 log.debug("type is " + li.getType()); 1422 throw sqle; 1423 } 1424 } else { 1425 if (isDebugging) 1426 log.debug("different error code"); 1427 throw sqle; 1428 } 1429 } 1430 1431 if (itemInserted) { 1432 // find out the auto assigned liid 1433 String queryNewLiid = "CALL IDENTITY();"; 1434 ResultSet rs = null; 1435 try { 1436 rs = _stmt.executeQuery(queryNewLiid); 1437 if (rs == null) 1438 throw new SQLException("Query Failed: " + queryNewLiid); 1439 if (rs.next()) { 1440 int newLiid = rs.getInt(1); 1441 if (!rs.wasNull()) { 1442 li.setLiid(newLiid); 1443 if (isDebugging) 1444 log.debug("IDENTITY: " + li.getLiid()); 1445 } else { 1446 log.error("Failed to retrieve auto assigned identity"); 1447 } 1448 } 1449 } finally { 1450 if(rs != null) { 1451 rs.close(); 1452 } 1453 } 1454 1455 insertLiidLsid(li.getLiid(), li.getLsid()); 1456 insertAttributes(li); 1457 1458 addToSearchIndex(li); 1459 } 1460 1461 _stmt.getConnection().commit(); 1462 } 1463 1464 /** 1465 * Add a new LSID to the LIBRARY_LSIDS table for the specified LIID. 1466 * 1467 * @param liid 1468 * @param lsid 1469 * @throws SQLException 1470 */ 1471 private void insertLiidLsid(int liid, KeplerLSID lsid) 1472 throws SQLException { 1473 if (lsid == null) { 1474 if (isDebugging) 1475 log.debug("lsid is null, skip insert into LIBRARY_LSIDS"); 1476 return; 1477 } 1478 1479 _getNumLIIDForLIIDAndLSIDPrepStmt.setInt(1, liid); 1480 _getNumLIIDForLIIDAndLSIDPrepStmt.setString(2, lsid.toString()); 1481 if (isDebugging) log.debug(_getNumLIIDForLIIDAndLSIDPrepStmt); 1482 ResultSet rs = null; 1483 try { 1484 rs = _getNumLIIDForLIIDAndLSIDPrepStmt.executeQuery(); 1485 if (rs.next()) { 1486 int cnt = rs.getInt(1); 1487 if (cnt <= 0) { 1488 _insertIntoLibraryLSIDsPrepStmt.setInt(1, liid); 1489 _insertIntoLibraryLSIDsPrepStmt.setString(2, lsid.toString()); 1490 if (isDebugging) log.debug(_insertIntoLibraryLSIDsPrepStmt); 1491 _insertIntoLibraryLSIDsPrepStmt.executeUpdate(); 1492 } else { 1493 // Already in there. ignore 1494 } 1495 } 1496 } finally { 1497 if(rs != null) { 1498 rs.close(); 1499 } 1500 } 1501 _stmt.getConnection().commit(); 1502 } 1503 1504 /** 1505 * Add the given LibItem to the search index. If the OrderedInsert flag is 1506 * set to true then all of the parents of this LibItem will be add to the 1507 * search index for this item. 1508 * 1509 * @param li 1510 * @throws SQLException 1511 */ 1512 public void addToSearchIndex(LibItem li) throws SQLException { 1513 1514 // Add a row for this LibItem 1515 Integer searchType = _searchTypeMap.get(li.getType()); 1516 if (searchType != null) { 1517 _searcher.insertRow(searchType.intValue(), li.getLiid(), li 1518 .getName()); 1519 } 1520 1521 // We can only get the path to this LibItem if it has been inserted AND 1522 // ordered 1523 if (isOrderedInsert()) { 1524 addAllParentsToSearchIndex(li); 1525 } 1526 } 1527 1528 /** 1529 * Add all of the parent LibItems to the search index for the given LibItem. 1530 * 1531 * @param li 1532 * @throws SQLException 1533 */ 1534 private void addAllParentsToSearchIndex(LibItem li) throws SQLException { 1535 // Add a row for every LibItem in the path to this LibItem 1536 Vector<LibItem> parents = getPath(li); 1537 for (LibItem parent : parents) { 1538 Integer searchType = _searchTypeMap.get(parent.getType()); 1539 if (searchType != null) { 1540 _searcher.insertRow(searchType.intValue(), li.getLiid(), parent 1541 .getName()); 1542 } 1543 } 1544 1545 } 1546 1547 /** 1548 * Here we map the LibItem types to the different Search types. 1549 */ 1550 private void initSearchMap() { 1551 _searchTypeMap = new Hashtable<Integer, Integer>(); 1552 _searchTypeMap.put(TYPE_COMPONENT, LibSearch.TYPE_NAME); 1553 _searchTypeMap.put(TYPE_CONCEPT, LibSearch.TYPE_ONTCLASSNAME); 1554 _searchTypeMap.put(TYPE_NAMED_OBJ, LibSearch.TYPE_NAME); 1555 _searchTypeMap.put(TYPE_ONTOLOGY, LibSearch.TYPE_ONTOLOGY); 1556 _searchTypeMap.put(TYPE_FOLDER, LibSearch.TYPE_FOLDERNAME); 1557 _searchTypeMap.put(TYPE_KARFOLDER, LibSearch.TYPE_FOLDERNAME); 1558 _searchTypeMap.put(TYPE_KAR, LibSearch.TYPE_KARNAME); 1559 _searchTypeMap.put(TYPE_LOCALREPO, LibSearch.TYPE_LOCALREPO); 1560 } 1561 1562 public LibSearch getSearcher() { 1563 return _searcher; 1564 } 1565 1566 /** 1567 * Sum the LFT and RGT columns and verify they are continuous integers from 1568 * 1 to (countItems()*2). This function should always return true after 1569 * finishing sql transactions for insert, update, or delete. 1570 * 1571 * @return true if the LFT and RGT columns of the table add up 1572 * @throws SQLException 1573 */ 1574 public boolean verifyPreorderValues() throws SQLException { 1575 if (isDebugging) 1576 log.debug(_getLftRgtSumPrepStmt); 1577 ResultSet rs = null; 1578 try { 1579 rs = _getLftRgtSumPrepStmt.executeQuery(); 1580 if (rs == null) 1581 throw new SQLException("Query Failed: " + _getLftRgtSumPrepStmt); 1582 if (rs.next()) { 1583 int sumLR = rs.getInt(1); 1584 int cnt = countItems() * 2; 1585 int sumCnt = (cnt * (cnt + 1)) / 2; 1586 if (isDebugging) 1587 log.debug(sumLR + " " + sumCnt); 1588 if (sumLR == sumCnt) { 1589 return true; 1590 } 1591 } 1592 } finally { 1593 if(rs != null) { 1594 rs.close(); 1595 } 1596 } 1597 return false; 1598 } 1599 1600 /** 1601 * Refresh the lft and rgt PTT values based on the parent information and 1602 * ordering by name. 1603 */ 1604 private void refreshPreorderValues() { 1605 try { 1606 int left = 1; 1607 ResultSet rs = null; 1608 try { 1609 rs = _getLIIDRootsPrepStmt.executeQuery(); 1610 if (rs == null) 1611 throw new SQLException("Query Failed: " + _getLIIDRootsPrepStmt); 1612 while (rs.next()) { 1613 int liid = rs.getInt(1); 1614 left = refreshPreorderValues(liid, left); 1615 } 1616 } finally { 1617 if(rs != null) { 1618 rs.close(); 1619 } 1620 } 1621 } catch (SQLException sqle) { 1622 sqle.printStackTrace(); 1623 } 1624 } 1625 1626 /** 1627 * Recursive function for refreshing the lft and rgt PTT values of a given 1628 * parent LIID starting at the given LEFT value. 1629 * 1630 * @param parent 1631 * @param left 1632 * @return 1633 * @throws SQLException 1634 */ 1635 private int refreshPreorderValues(int parent, int left) throws SQLException { 1636 int right = left + 1; 1637 1638 // get all children of this node 1639 _getLIIDForParentPrepStmt.setInt(1, parent); 1640 ResultSet rs = null; 1641 try { 1642 rs = _getLIIDForParentPrepStmt.executeQuery(); 1643 while (rs.next()) { 1644 int p = rs.getInt(1); 1645 right = refreshPreorderValues(p, right); 1646 } 1647 } finally { 1648 if(rs != null) { 1649 rs.close(); 1650 } 1651 } 1652 1653 // UPDATE LIBRARY_INDEX SET LFT=?, RGT=? WHERE LIID=? 1654 _updateOrderPrepStmt.clearParameters(); 1655 _updateOrderPrepStmt.setInt(1, left); 1656 _updateOrderPrepStmt.setInt(2, right); 1657 _updateOrderPrepStmt.setInt(3, parent); 1658 _updateOrderPrepStmt.executeUpdate(); 1659 1660 // return the right value of this node + 1 1661 return right + 1; 1662 } 1663 1664 /** 1665 * Returns a string that uniquely identifies a KAR entry using the full path 1666 * to the KAR file and the name of the entry as it appears in the KAR 1667 * manifest. 1668 * 1669 * @param karFile 1670 * @param entry 1671 * @return 1672 */ 1673 private String getKarEntryPath(File karFile, String entry) { 1674 String fullPath = karFile.toString(); 1675 if (!fullPath.endsWith(File.separator) 1676 && !entry.startsWith(File.separator)) { 1677 fullPath += File.separator + entry; 1678 } else { 1679 fullPath += entry; 1680 } 1681 return fullPath; 1682 } 1683 1684 /** 1685 * This will find any folder or file kar entry. 1686 * 1687 * @param karFile 1688 * @param path 1689 * @return 1690 */ 1691 private LibItem findKarEntry(File karFile, String path) throws SQLException { 1692 LibItem li = null; 1693 1694 _getLIIDForKarEntryPrepStmt.setString(1, getKarEntryPath(karFile, path)); 1695 if (isDebugging) 1696 log.debug(_getLIIDForKarEntryPrepStmt); 1697 ResultSet rs = null; 1698 try { 1699 rs = _getLIIDForKarEntryPrepStmt.executeQuery(); 1700 if (rs == null) 1701 throw new SQLException("Query Failed: " + _getLIIDForKarEntryPrepStmt); 1702 if (rs.next()) { 1703 int liid = rs.getInt(1); 1704 if (!rs.wasNull()) { 1705 li = _libraryManager.getPopulatedLibItem(liid); 1706 } 1707 if (rs.next()) { 1708 log.error("LIBRARY_INDEX table is corrupt: " 1709 + "Multiples of KAREntry " + path + " found"); 1710 } 1711 } 1712 } finally { 1713 if(rs != null) { 1714 rs.close(); 1715 } 1716 } 1717 return li; 1718 } 1719 1720 /** 1721 * Given the KARCached object and the 1722 * 1723 * @param kc 1724 * @param path 1725 * @return 1726 */ 1727 private LibItem assureKarFolder(KARCached kc, String path) { 1728 File karFile = kc.getFile(); 1729 LibItem li = null; 1730 try { 1731 li = findKarEntry(karFile, path); 1732 if (li == null) { 1733 LibItem parent = null; 1734 String[] pathRep = path.split("/"); 1735 if (pathRep.length > 1) { 1736 String parentPath = new String(); 1737 for (int i = 0; i < pathRep.length - 1; i++) { 1738 parentPath += pathRep[i] + "/"; 1739 } 1740 parent = assureKarFolder(kc, parentPath); 1741 if (parent == null) { 1742 throw new Exception("Unable to find or create " 1743 + getKarEntryPath(karFile, parentPath)); 1744 } 1745 } else { 1746 parent = assureKar(kc); 1747 if (parent == null) { 1748 throw new Exception("Unable to find or create " 1749 + karFile); 1750 } 1751 } 1752 li = new LibItem(); 1753 li.setName(pathRep[pathRep.length - 1]); 1754 li.setType(LibIndex.TYPE_KARFOLDER); 1755 li.setParent(parent.getLiid()); 1756 li.setLevel(parent.getLevel() + 1); 1757 li.setLsid(null); // folders don't have LSIDs! 1758 li.addAttribute(ATT_KARENTRYPATH, 1759 getKarEntryPath(karFile, path)); 1760 insertNoOrder(li); 1761 } 1762 } catch (Exception e) { 1763 log.error("Unable to assureKarFolder(" + karFile.toString() + "," 1764 + path + ")"); 1765 e.printStackTrace(); 1766 } 1767 return li; 1768 } 1769 1770 /** 1771 * 1772 * @param kce 1773 * @return 1774 * @throws SQLException 1775 */ 1776 private LibItem findKarError(KARCacheError kce) throws SQLException { 1777 LibItem li = null; 1778 1779 File karFile = kce.getFile(); 1780 _getLIIDForKarErrorPrepStmt.setString(1, karFile.toString()); 1781 if (isDebugging) 1782 log.debug(_getLIIDForKarErrorPrepStmt); 1783 ResultSet rs = null; 1784 try { 1785 rs = _getLIIDForKarErrorPrepStmt.executeQuery(); 1786 if (rs == null) 1787 throw new SQLException("Query Failed: " + _getLIIDForKarErrorPrepStmt); 1788 if (rs.next()) { 1789 int liid = rs.getInt(1); 1790 if (rs.wasNull()) { 1791 li = _libraryManager.getPopulatedLibItem(liid); 1792 } 1793 if (rs.next()) { 1794 log.error("LIBRARY_INDEX table is corrupt: " 1795 + "multiples of KAR Error " + karFile + " found"); 1796 } 1797 return li; 1798 } 1799 } finally { 1800 if(rs != null) { 1801 rs.close(); 1802 } 1803 } 1804 1805 return li; 1806 } 1807 1808 /** 1809 * 1810 * @param kce 1811 * @return 1812 */ 1813 private LibItem assureKarError(KARCacheError kce) { 1814 File karFile = kce.getFile(); 1815 LibItem li = null; 1816 try { 1817 li = findKarError(kce); 1818 1819 if (li == null) { 1820 LibItem parent = null; 1821 File parentFile = karFile.getParentFile(); 1822 LocalRepositoryManager lrm = LocalRepositoryManager.getInstance(); 1823 LocalRepository repo = lrm.getRepositoryForFile(parentFile); 1824 if (repo != null) { 1825 parent = assureLocalRepository(repo); 1826 } else { 1827 parent = assureFolder(parentFile); 1828 } 1829 if (parent == null) 1830 throw new Exception(); 1831 1832 li = new LibItem(); 1833 li.setName(kce.getName()); 1834 li.setType(LibIndex.TYPE_KAR_ERROR); 1835 li.setParent(parent.getLiid()); 1836 li.setLevel(parent.getLevel() + 1); 1837 li.setLsid(kce.getLsid()); 1838 li.addAttribute(ATT_KARFILE, karFile.toString()); 1839 insertNoOrder(li); 1840 } 1841 1842 } catch (Exception e) { 1843 log.error("Unable to assureKarError(" + kce.getFile().toString() 1844 + ")"); 1845 e.printStackTrace(); 1846 } 1847 return li; 1848 } 1849 1850 /** 1851 * @param karFile 1852 * @return LibItem that represents the given KAR File or null if the given 1853 * KAR File does not correspond to an entry in the Library Index. 1854 * @throws SQLException 1855 */ 1856 public LibItem findKar(File karFile) throws SQLException { 1857 LibItem li = null; 1858 _getLIIDForKarPrepStmt.setString(1, karFile.toString()); 1859 if (isDebugging) 1860 log.debug(_getLIIDForKarPrepStmt); 1861 ResultSet rs = null; 1862 try { 1863 rs = _getLIIDForKarPrepStmt.executeQuery(); 1864 if (rs == null) 1865 throw new SQLException("Query Failed: " + _getLIIDForKarPrepStmt); 1866 if (rs.next()) { 1867 int liid = rs.getInt(1); 1868 if (!rs.wasNull()) { 1869 li = _libraryManager.getPopulatedLibItem(liid); 1870 } 1871 if (rs.next()) { 1872 log.error("LIBRARY_INDEX table is corrupt: " 1873 + " multiples of KAR " + karFile + " found"); 1874 } 1875 } 1876 } finally { 1877 if(rs != null) { 1878 rs.close(); 1879 } 1880 } 1881 return li; 1882 } 1883 1884 /** 1885 * 1886 * @param kc 1887 * @return 1888 */ 1889 private LibItem assureKar(KARCached kc) { 1890 File karFile = kc.getFile(); 1891 LibItem li = null; 1892 try { 1893 li = findKar(karFile); 1894 if (li != null) { 1895 return li; 1896 } 1897 1898 LibItem parent = null; 1899 File parentFile = karFile.getParentFile(); 1900 LocalRepositoryManager lrm = LocalRepositoryManager.getInstance(); 1901 LocalRepository repo = lrm.getRepositoryForFile(parentFile); 1902 if (repo != null) { 1903 parent = assureLocalRepository(repo); 1904 } else { 1905 parent = assureFolder(parentFile); 1906 } 1907 if (parent == null) 1908 throw new Exception(); 1909 1910 li = new LibItem(); 1911 li.setName(kc.getName()); 1912 li.setType(LibIndex.TYPE_KAR); 1913 li.setParent(parent.getLiid()); 1914 li.setLevel(parent.getLevel() + 1); 1915 li.setLsid(kc.getLsid()); 1916 li.addAttribute(ATT_KARFILE, karFile.toString()); 1917 insertNoOrder(li); 1918 1919 // see if this kar belongs to a demo 1920 ModuleTree tree = ModuleTree.instance(); 1921 DotKeplerManager dkm = DotKeplerManager.getInstance(); 1922 for(Module module : tree.getModuleList()) { 1923 String moduleName = module.getName(); 1924 String moduleWorkflowsDir = dkm.getPersistentModuleWorkflowsDir(moduleName).getAbsolutePath(); 1925 String moduleDemosDir = moduleWorkflowsDir + File.separator + "demos"; 1926 1927 if(karFile.getAbsolutePath().startsWith(moduleDemosDir)) { 1928 1929 parent = assureDemoFolder(parentFile); 1930 li = new LibItem(); 1931 li.setName(kc.getName()); 1932 li.setType(TYPE_KAR); 1933 li.setParent(parent.getLiid()); 1934 li.setLevel(parent.getLevel() + 1); 1935 li.setLsid(kc.getLsid()); 1936 li.addAttribute(ATT_KARFILE, karFile.toString()); 1937 insertNoOrder(li); 1938 } 1939 } 1940 1941 } catch (Exception e) { 1942 log.error("Unable to assureKar(" + kc.getFile().toString() + ")"); 1943 e.printStackTrace(); 1944 } 1945 return li; 1946 } 1947 1948 /** 1949 * @param file 1950 * @return LibItem that represents the given XML File or null if the given 1951 * XML File does not correspond to an entry in the Library Index. 1952 * @throws SQLException 1953 */ 1954 public LibItem findXML(File file) throws SQLException { 1955 LibItem li = null; 1956 _getLIIDForXMLPrepStmt.setString(1, file.toString()); 1957 if (isDebugging) 1958 log.debug(_getLIIDForXMLPrepStmt); 1959 ResultSet rs = null; 1960 try { 1961 rs = _getLIIDForXMLPrepStmt.executeQuery(); 1962 if (rs == null) 1963 throw new SQLException("Query Failed: " + _getLIIDForXMLPrepStmt); 1964 if (rs.next()) { 1965 int liid = rs.getInt(1); 1966 if (!rs.wasNull()) { 1967 li = _libraryManager.getPopulatedLibItem(liid); 1968 } 1969 if (rs.next()) { 1970 log.error("LIBRARY_INDEX table is corrupt: " 1971 + " multiples of XML " + file + " found"); 1972 } 1973 } 1974 } finally { 1975 if(rs != null) { 1976 rs.close(); 1977 } 1978 } 1979 return li; 1980 } 1981 1982 /** 1983 * 1984 * @param kc 1985 * @return 1986 */ 1987 public LibItem assureXML(File file) { 1988 LibItem li = null; 1989 try { 1990 li = findXML(file); 1991 if (li != null) { 1992 return li; 1993 } 1994 1995 LibItem parent = null; 1996 File parentFile = file.getParentFile(); 1997 LocalRepositoryManager lrm = LocalRepositoryManager.getInstance(); 1998 LocalRepository repo = lrm.getRepositoryForFile(parentFile); 1999 if (repo != null) { 2000 parent = assureLocalRepository(repo); 2001 } else { 2002 parent = assureFolder(parentFile); 2003 } 2004 if (parent == null) 2005 throw new Exception(); 2006 2007 KeplerActorMetadata metadata = null; 2008 KeplerLSID lsid = null; 2009 try { 2010 metadata = KeplerMetadataExtractor.extractActorMetadata(file, false); 2011 } catch(Exception e) { 2012 System.err.println("Error parsing " + file + ": " + e.getMessage()); 2013 return null; 2014 } 2015 if(metadata == null) { 2016 return null; 2017 } 2018 2019 String className = metadata.getClassName(); 2020 2021 li = new LibItem(); 2022 li.setName(file.getName()); 2023 li.setType(TYPE_COMPONENT); 2024 li.setParent(parent.getLiid()); 2025 li.setLevel(parent.getLevel() + 1); 2026 li.setLsid(lsid); 2027 li.addAttribute(ATT_XMLFILE, file.toString()); 2028 if(className != null) { 2029 li.addAttribute(ATT_CLASSNAME, className); 2030 } 2031 insertNoOrder(li); 2032 2033 // see if this kar belongs to a demo 2034 ModuleTree tree = ModuleTree.instance(); 2035 DotKeplerManager dkm = DotKeplerManager.getInstance(); 2036 for(Module module : tree.getModuleList()) { 2037 String moduleName = module.getName(); 2038 String moduleWorkflowsDir = dkm.getPersistentModuleWorkflowsDir(moduleName).getAbsolutePath(); 2039 String moduleDemosDir = moduleWorkflowsDir + File.separator + "demos"; 2040 2041 if(file.getAbsolutePath().startsWith(moduleDemosDir)) { 2042 2043 parent = assureDemoFolder(parentFile); 2044 li = new LibItem(); 2045 li.setName(file.getName()); 2046 li.setType(TYPE_COMPONENT); 2047 li.setParent(parent.getLiid()); 2048 li.setLevel(parent.getLevel() + 1); 2049 li.setLsid(lsid); 2050 li.addAttribute(ATT_XMLFILE, file.toString()); 2051 if(className != null) { 2052 li.addAttribute(ATT_CLASSNAME, className); 2053 } 2054 insertNoOrder(li); 2055 } 2056 } 2057 2058 } catch (Exception e) { 2059 log.error("Unable to assureXML(" + file.toString() + ")"); 2060 e.printStackTrace(); 2061 } 2062 return li; 2063 } 2064 2065 private LibItem findFolder(String folder) throws SQLException { 2066 LibItem li = null; 2067 _getLIIDForFolderPrepStmt.setString(1, folder); 2068 if (isDebugging) 2069 log.debug(_getLIIDForFolderPrepStmt); 2070 ResultSet rs = null; 2071 try { 2072 rs = _getLIIDForFolderPrepStmt.executeQuery(); 2073 if (rs == null) 2074 throw new SQLException("Query Failed: " + _getLIIDForFolderPrepStmt); 2075 if (rs.next()) { 2076 int liid = rs.getInt(1); 2077 if (!rs.wasNull()) { 2078 li = _libraryManager.getPopulatedLibItem(liid); 2079 } 2080 if (rs.next()) { 2081 log.error("LIBRARY_INDEX table is corrupt: " 2082 + "multiples of folder " + folder + " found"); 2083 } 2084 return li; 2085 } 2086 } finally { 2087 if(rs != null) { 2088 rs.close(); 2089 } 2090 } 2091 return li; 2092 } 2093 2094 private LibItem assureDemoFolder(File folder) { 2095 LibItem li = null; 2096 try { 2097 2098 li = findFolder(_demosFolderItem + ":" + folder.toString()); 2099 if(li == null) { 2100 2101 if(_demosFolderItem == null) { 2102 _demosFolderItem = new LibItem(); 2103 _demosFolderItem.setName("Demos"); 2104 _demosFolderItem.setType(TYPE_FOLDER); 2105 _demosFolderItem.setParent(null); 2106 _demosFolderItem.setLevel(ROOT_LEVEL); 2107 _demosFolderItem.setLsid(null); 2108 insertNoOrder(_demosFolderItem); 2109 } 2110 2111 LibItem parent = null; 2112 2113 String path = folder.getAbsolutePath(); 2114 Matcher matcher = _demosFolderPattern.matcher(path); 2115 2116 if(path.equals(DotKeplerManager.getInstance() 2117 .getPersistentModuleWorkflowsDir().getPath())) { 2118 return _demosFolderItem; 2119 } else if (matcher.find() && path.endsWith("demos")) { 2120 if(matcher.group(1).startsWith("outreach")) { 2121 return _demosFolderItem; 2122 } else { 2123 return assureDemoFolder(folder.getParentFile()); 2124 } 2125 } else { 2126 parent = assureDemoFolder(folder.getParentFile()); 2127 } 2128 2129 // remove the version from the name, if present. 2130 final String unversionedName = Version.stem(folder.getName()); 2131 final String name = LocalRepositoryManager.getLocalRepositoryName(unversionedName); 2132 2133 li = new LibItem(); 2134 li.setName(name); 2135 li.setType(LibIndex.TYPE_FOLDER); 2136 li.setParent(parent.getLiid()); 2137 li.setLevel(parent.getLevel() + 1); 2138 li.setLsid(null); // folders don't have LSIDs! 2139 li.addAttribute(ATT_FOLDER, _demosFolderItem + ":" + folder.toString()); 2140 insertNoOrder(li); 2141 } 2142 } catch (Exception e) { 2143 log.error("Unable to assureFolder(" + folder.toString() + ") rooted at " + _demosFolderItem.getName()); 2144 e.printStackTrace(); 2145 } 2146 return li; 2147 } 2148 2149 /** 2150 * 2151 * @param folder 2152 * @return 2153 */ 2154 private LibItem assureFolder(File folder) { 2155 LibItem li = null; 2156 try { 2157 li = findFolder(folder.toString()); 2158 2159 if (li == null) { 2160 // determine the parent LibItem 2161 LibItem parent = null; 2162 2163 LocalRepositoryManager lrm = LocalRepositoryManager 2164 .getInstance(); 2165 LocalRepository repo = lrm.getRepositoryForFile(folder); 2166 if (repo != null) { 2167 if (isDebugging) 2168 log.debug(folder + " is a repository"); 2169 parent = assureLocalRepository(repo); 2170 } else { 2171 repo = lrm.getContainingLocalRepository(folder); 2172 if (repo == null) { 2173 throw new Exception(folder 2174 + " is not in a local repository"); 2175 } 2176 File parentFile = folder.getParentFile(); 2177 if (isDebugging) 2178 log.debug(repo + " - " + parentFile); 2179 if (repo.isFileRepoDirectory(parentFile)) { 2180 parent = assureLocalRepository(repo); 2181 } else { 2182 parent = assureFolder(parentFile); 2183 } 2184 2185 // insert a new LibItem for this folder 2186 li = new LibItem(); 2187 li.setName(folder.getName()); 2188 li.setType(LibIndex.TYPE_FOLDER); 2189 li.setParent(parent.getLiid()); 2190 li.setLevel(parent.getLevel() + 1); 2191 li.setLsid(null); // folders don't have LSIDs! 2192 li.addAttribute(ATT_FOLDER, folder.toString()); 2193 insertNoOrder(li); 2194 } 2195 } 2196 } catch (Exception e) { 2197 log.error("Unable to assureFolder(" + folder.toString() + ")"); 2198 e.printStackTrace(); 2199 } 2200 return li; 2201 } 2202 2203 private LibItem findLocalRepository(LocalRepository repo) throws SQLException { 2204 LibItem li = null; 2205 _getLIIDForRepositoryPrepStmt.setString(1, repo.toString()); 2206 if (isDebugging) 2207 log.debug(_getLIIDForRepositoryPrepStmt); 2208 ResultSet rs = null; 2209 try { 2210 rs = _getLIIDForRepositoryPrepStmt.executeQuery(); 2211 if (rs == null) 2212 throw new SQLException("Query Failed: " + _getLIIDForRepositoryPrepStmt); 2213 if (rs.next()) { 2214 int liid = rs.getInt(1); 2215 if (!rs.wasNull()) { 2216 li = _libraryManager.getPopulatedLibItem(liid); 2217 } 2218 if (rs.next()) { 2219 log.error("LIBRARY_INDEX table is corrupt: " 2220 + " multiples of local repository " + repo + " found"); 2221 } 2222 return li; 2223 } 2224 } finally { 2225 if(rs != null) { 2226 rs.close(); 2227 } 2228 } 2229 return li; 2230 } 2231 2232 /** 2233 * 2234 * @param repo 2235 * @return 2236 */ 2237 private LibItem assureLocalRepository(LocalRepository repo) { 2238 LibItem li = null; 2239 2240 try { 2241 li = findLocalRepository(repo); 2242 2243 if (li == null) { 2244 // insert a new LibItem row for this Local Repository 2245 LocalRepositoryManager lrm = LocalRepositoryManager 2246 .getInstance(); 2247 String repoName = lrm.getLocalRepositories().get(repo); 2248 2249 li = new LibItem(); 2250 li.setName(repoName); 2251 li.setType(LibIndex.TYPE_LOCALREPO); 2252 li.setParent(null); 2253 li.setLevel(ROOT_LEVEL); 2254 li.setLsid(null); // repos don't have LSIDs! 2255 li.addAttribute(ATT_REPOPATH, repo.toString()); 2256 insertNoOrder(li); 2257 } 2258 } catch (Exception e) { 2259 log.error("Unable to assureLocalRepository(" + repo.toString() 2260 + ")"); 2261 e.printStackTrace(); 2262 } 2263 return li; 2264 } 2265 2266 /** 2267 * 2268 * @param ontologyName 2269 * @return 2270 * @throws SQLException 2271 */ 2272 private LibItem findOntology(String ontologyName) throws SQLException { 2273 LibItem li = null; 2274 _getLIIDForOntologyNamePrepStmt.setString(1, ontologyName); 2275 if (isDebugging) 2276 log.debug(_getLIIDForOntologyNamePrepStmt); 2277 ResultSet rs = null; 2278 try { 2279 rs = _getLIIDForOntologyNamePrepStmt.executeQuery(); 2280 if (rs == null) 2281 throw new SQLException("Query Failed: " + _getLIIDForOntologyNamePrepStmt); 2282 if (rs.next()) { 2283 int liid = rs.getInt(1); 2284 if (isDebugging) 2285 log.debug(liid + " is already in the index table"); 2286 if (!rs.wasNull()) { 2287 li = _libraryManager.getPopulatedLibItem(liid); 2288 } 2289 if (rs.next()) { 2290 log.error("LIBRARY_INDEX table is corrupt: " 2291 + "multiples of ontology " + ontologyName + " found"); 2292 } 2293 } 2294 } finally { 2295 if(rs != null) { 2296 rs.close(); 2297 } 2298 } 2299 return li; 2300 } 2301 2302 /** 2303 * Return the LibItem for the given Ontology Name. If no LibItem exists in 2304 * the LIBRARY_INDEX then insert a new row for it and return a LibItem 2305 * representation of the row. 2306 * 2307 * @param ontologyName 2308 * @return 2309 */ 2310 private LibItem assureOntology(String ontologyName) { 2311 LibItem li = null; 2312 2313 try { 2314 li = findOntology(ontologyName); 2315 2316 if (li == null) { 2317 if (isDebugging) 2318 log.debug(ontologyName + " is not in the index table"); 2319 li = new LibItem(); 2320 li.setName(ontologyName); 2321 li.setType(LibIndex.TYPE_ONTOLOGY); 2322 li.setParent(null); 2323 li.setLevel(1); 2324 insertNoOrder(li); 2325 } 2326 } catch (Exception e) { 2327 log.error("Unable to assureOntology(" + ontologyName + ")"); 2328 e.printStackTrace(); 2329 } 2330 return li; 2331 } 2332 2333 /** 2334 * 2335 * @param noc 2336 * @return 2337 * @throws SQLException 2338 */ 2339 private Vector<LibItem> findOntClass(NamedOntClass noc) throws SQLException { 2340 Vector<LibItem> items = new Vector<LibItem>(); 2341 _getLIIDForOntologyClassPrepStmt.setString(1, noc.getConceptId()); 2342 if (isDebugging) 2343 log.debug(_getLIIDForOntologyClassPrepStmt); 2344 ResultSet rs = null; 2345 try { 2346 rs = _getLIIDForOntologyClassPrepStmt.executeQuery(); 2347 if (rs == null) 2348 log.error("Query Failed: " + _getLIIDForOntologyClassPrepStmt); 2349 while (rs.next()) { 2350 int liid = rs.getInt(1); 2351 if (isDebugging) 2352 log.debug(liid + " is already in the index table"); 2353 if (!rs.wasNull()) { 2354 LibItem li = _libraryManager.getPopulatedLibItem(liid); 2355 items.add(li); 2356 } 2357 } 2358 } finally { 2359 if(rs != null) { 2360 rs.close(); 2361 } 2362 } 2363 return items; 2364 } 2365 2366 /** 2367 * Return a Vector of LibItem objects from the Library_Index that correlate 2368 * to the given NamedOntClass. If none exist then insert. 2369 * 2370 * TODO: there is likely a serious flaw here, check into it... 2371 * 2372 * @param noc 2373 * @return 2374 */ 2375 private Vector<LibItem> assureOntClass(NamedOntClass noc) { 2376 if (isDebugging) 2377 log.debug(noc.getName()); 2378 Vector<LibItem> items = null; 2379 try { 2380 2381 items = findOntClass(noc); 2382 2383 if (items.size() <= 0) { 2384 if (isDebugging) 2385 log.debug("needs to be added to the index table"); 2386 Iterator<NamedOntClass> parents = noc 2387 .getNamedSuperClasses(false); 2388 while (parents.hasNext()) { 2389 NamedOntClass parent = parents.next(); 2390 Vector<LibItem> parentItems = assureOntClass(parent); 2391 for (LibItem parentItem : parentItems) { 2392 LibItem newli = new LibItem(); 2393 newli.setName(noc.getName()); 2394 newli.setLsid(new KeplerLSID(noc.getConceptId())); 2395 newli.setParent(parentItem.getLiid()); 2396 newli.setType(LibIndex.TYPE_CONCEPT); 2397 newli.setLevel(parentItem.getLevel() + 1); 2398 insertNoOrder(newli); 2399 items.add(newli); 2400 } 2401 } 2402 if (items.size() <= 0) { 2403 if (isDebugging) 2404 log.debug("no super classes, add the ontology"); 2405 LibItem parentOnt = assureOntology(noc.getOntologyName()); 2406 2407 LibItem newli = new LibItem(); 2408 newli.setName(noc.getName()); 2409 newli.setLsid(new KeplerLSID(noc.getConceptId())); 2410 newli.setParent(parentOnt.getLiid()); 2411 newli.setType(LibIndex.TYPE_CONCEPT); 2412 newli.setLevel(parentOnt.getLevel() + 1); 2413 insertNoOrder(newli); 2414 items.add(newli); 2415 } 2416 } 2417 } catch (Exception e) { 2418 log.error("Unable to assureOntClass(" + noc.toString() + ")"); 2419 e.printStackTrace(); 2420 } 2421 return items; 2422 } 2423 2424 /** 2425 * Return true if there is a child of the parent in the index with the given 2426 * name. 2427 * 2428 * @param parentLiid 2429 * @param childName 2430 * @return 2431 */ 2432 public int childExists(Integer parentLiid, String childName) { 2433 int liidOfExistingChild = -1; 2434 try { 2435 PreparedStatement query; 2436 if (parentLiid == null) { 2437 query = _getLIIDForNullParentAndNamePrepStmt; 2438 query.setString(1, childName); 2439 } else { 2440 query = _getLIIDForParentAndNamePrepStmt; 2441 query.setInt(1, parentLiid.intValue()); 2442 query.setString(2, childName); 2443 } 2444 2445 if (isDebugging) 2446 log.debug(query); 2447 ResultSet rs = null; 2448 try { 2449 rs = query.executeQuery(); 2450 if (rs == null) 2451 throw new SQLException("Query Failed: " + query); 2452 if (rs.next()) { 2453 liidOfExistingChild = rs.getInt(1); 2454 } 2455 } finally { 2456 if(rs != null) { 2457 rs.close(); 2458 } 2459 } 2460 } catch (SQLException e) { 2461 e.printStackTrace(); 2462 } 2463 return liidOfExistingChild; 2464 } 2465 2466}