org.kepler.objectmanager.library.LibraryManager.java Source code

Java tutorial

Introduction

Here is the source code for org.kepler.objectmanager.library.LibraryManager.java

Source

/*
 * Copyright (c) 2004-2010 The Regents of the University of California.
 * All rights reserved.
 *
 * '$Author: crawl $'
 * '$Date: 2014-04-09 11:01:44 -0700 (Wed, 09 Apr 2014) $' 
 * '$Revision: 32650 $'
 * 
 * Permission is hereby granted, without written agreement and without
 * license or royalty fees, to use, copy, modify, and distribute this
 * software and its documentation for any purpose, provided that the above
 * copyright notice and the following two paragraphs appear in all copies
 * of this software.
 *
 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
 * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
 * THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
 * PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
 * CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
 * ENHANCEMENTS, OR MODIFICATIONS.
 *
 */

package org.kepler.objectmanager.library;

import java.io.File;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Hashtable;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Vector;
import java.util.WeakHashMap;

import javax.swing.JTree;
import javax.swing.event.TreeExpansionEvent;
import javax.swing.event.TreeExpansionListener;
import javax.swing.tree.TreePath;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.kepler.gui.FilteredVisibleTreeModel;
import org.kepler.icon.ComponentEntityConfig;
import org.kepler.kar.KARCacheContent;
import org.kepler.kar.KARCacheManager;
import org.kepler.kar.KARFile;
import org.kepler.moml.FolderEntityLibrary;
import org.kepler.moml.KAREntityLibrary;
import org.kepler.moml.KARErrorEntityLibrary;
import org.kepler.moml.NamedObjId;
import org.kepler.moml.OntologyEntityLibrary;
import org.kepler.objectmanager.cache.CacheManager;
import org.kepler.objectmanager.lsid.KeplerLSID;
import org.kepler.util.sql.DatabaseFactory;

import ptolemy.actor.gui.TableauFrame;
import ptolemy.data.expr.Parameter;
import ptolemy.kernel.ComponentEntity;
import ptolemy.kernel.CompositeEntity;
import ptolemy.kernel.util.Attribute;
import ptolemy.kernel.util.IllegalActionException;
import ptolemy.kernel.util.NameDuplicationException;
import ptolemy.kernel.util.StringAttribute;
import ptolemy.kernel.util.Workspace;
import ptolemy.moml.EntityLibrary;
import ptolemy.vergil.tree.EntityTreeModel;
import ptolemy.vergil.tree.VisibleTreeModel;

/**
 * The LibraryManager is used for managing the Actor Library. It maintains an
 * index for increased performance. Any code that adds, updates, or removes
 * items in the library should use the LibraryManager class directly.
 * 
 *@author Aaron Schultz
 */
public class LibraryManager implements TreeExpansionListener {
    private static class LibraryManagerHolder {
        private static final LibraryManager INSTANCE = new LibraryManager();
    }

    private static final Log log = LogFactory.getLog(LibraryManager.class.getName());
    private static final boolean isDebugging = log.isDebugEnabled();

    /**
     * The LIID_LABEL is used as the name of the String Attribute that is
     * attached to Tree Items to keep track of their Library Index ID.
     */
    public static final String LIID_LABEL = "_LIID";

    /** A mapping of tree to a list of tree paths that are expanded in it. */
    private static final Map<JTree, List<TreePath>> _treeExpansionMap = new WeakHashMap<JTree, List<TreePath>>();

    /**
     * Method for getting an instance of this singleton class.
     */
    public static LibraryManager getInstance() {
        return LibraryManagerHolder.INSTANCE;
    }

    /**
     * Return the Library Index ID for the given NamedObj or -1 if an ID cannot
     * be found.
     * 
     * @param obj
     *            a NamedObj from the Library tree.
     * @return int Library Index ID or
     */
    public static int getLiidFor(ComponentEntity obj) {
        if (isDebugging)
            log.debug("getLiidFor(" + obj.getName() + ")");
        int liid = -1;
        try {
            Attribute liidAttribute = obj.getAttribute(LibraryManager.LIID_LABEL);
            if (liidAttribute == null) {
                return -1;
            }
            if (liidAttribute instanceof StringAttribute) {
                StringAttribute liidSA = (StringAttribute) liidAttribute;
                liid = Integer.parseInt(liidSA.getExpression());
            } else {
                liid = -1;
            }
        } catch (Exception e) {
            liid = -1;
        }
        return liid;
    }

    /**
     * This is the composite entity version of the library.
     */
    private CompositeEntity _actorLibrary;

    /**
     * This is the workspace passed to us from
     * ptolemy.actor.gui.UserActorLibrary It is the top level workspace.
     */
    private Workspace _actorLibraryWorkspace = null;

    /**
     * The LibIndex is used to build the Actor Library.
     */
    private LibIndex _libIndex;

    /**
     * This is the EntityTreeModel version of the library, used in
     * AnnotatedPTree.
     */
    private VisibleTreeModel _libraryModel;

    /**
     * Convenience reference
     */
    private Connection _conn;

    /**
     * Convenience reference. Make sure to close your ResultSets since we're
     * reusing the Statement.
     */
    private Statement _stmt;

    /**
     * JTrees that contain the library can be added to the library manager so
     * they can be refreshed whenever the library changes.
     */
    //   private Vector<JTree> _trees = new Vector<JTree>();   
    private Vector<WeakReference<JTree>> _trees = new Vector<WeakReference<JTree>>();

    // PreparedStatements
    private PreparedStatement _getPopulateInfoForLIIDPrepStmt;
    private PreparedStatement _getLSIDForLIIDPrepStmt;
    private PreparedStatement _getNameValueForLIIDPrepStmt;

    /**
     * constructor called from getInstance()
     */
    public LibraryManager() {
        if (isDebugging)
            log.debug("Instantiate LibraryManager");

        try {
            _conn = DatabaseFactory.getDBConnection();
            _stmt = _conn.createStatement();

            _getPopulateInfoForLIIDPrepStmt = _conn
                    .prepareStatement("SELECT PARENT,LFT,RGT,LEVEL,LSID,TYPE,NAME FROM "
                            + LibIndex.LIBRARY_INDEX_TABLE_NAME + " WHERE LIID = ?");

            _getLSIDForLIIDPrepStmt = _conn
                    .prepareStatement("SELECT LSID FROM " + LibIndex.LIBRARY_LSIDS_TABLE_NAME + " WHERE LIID = ?");

            _getNameValueForLIIDPrepStmt = _conn.prepareStatement(
                    "SELECT NAME,VALUE FROM " + LibIndex.LIBRARY_ATTRIBUTES_TABLE_NAME + " WHERE LIID = ?");

        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    /**
     * Given the LSID of a KAR that has been successfully cached this method
     * will add all of the contents of that KAR into the Library by first
     * updating the LibIndex and then updating the tree model.
     * 
     * @param f
     * @throws SQLException
     */
    public void addKAR(File karFile) throws SQLException {

        KARCacheManager kcm = KARCacheManager.getInstance();
        Vector<KARCacheContent> contents = kcm.getKARCacheContents(karFile);
        getIndex().setOrderedInsert(true);
        for (KARCacheContent content : contents) {

            // Update the ontologies in the library index
            Vector<LibItem> ontItems = getIndex().assureOntologyComponent(content);
            // update the ontologies in the library tree model
            for (LibItem ontLI : ontItems) {
                ComponentEntity ce = assureTreeItem(ontLI);
                if (ce == null) {
                    // Problem adding item to the tree
                    // Here we could rebuild the library completely...
                    log.error("Component not added to the library properly");
                }
            }

            // Update the folders in the library index
            LibItem folderLI = getIndex().assureKarEntry(content);
            // Update the folders in the library tree model
            assureTreeItem(folderLI);
        }

        getIndex().setOrderedInsert(false);
    }

    /**
     * Update the LibIndex and tree model for a XML file.
      * 
      * @param f
      * @throws SQLException
      */
    public void addXML(File xmlFile) throws SQLException {

        LibIndex index = getIndex();
        index.setOrderedInsert(true);

        LibItem xmlLI = index.assureXML(xmlFile);
        assureTreeItem(xmlLI);

        index.setOrderedInsert(false);
    }

    /**
     * Add a reference to a JTree that is using the Library Tree Model so that
     * it can be updated when the tree model changes. Whenever getTreeModel() is
     * used in a gui component, the JTree reference should be added using this
     * method so that it can get refreshed when the library model changes using
     * the refreshJTrees() method.
     * 
     *@param ptree
     *            The feature to be added to the LibraryComponent attribute
     */
    public void addLibraryJTree(JTree ptree) {
        if (isDebugging) {
            log.debug("addLibraryComponent(" + ptree.getName() + ")");
        }
        if (isDebugging)
            log.debug("addLibraryComponent(" + ptree + ")");
        WeakReference<JTree> ptreeWR = new WeakReference<JTree>(ptree);
        _trees.addElement(ptreeWR);
        if (isDebugging)
            log.debug("_trees size:" + _trees.size());

        // add this tree to the map and register for expansion events
        _treeExpansionMap.put(ptree, new LinkedList<TreePath>());
        ptree.addTreeExpansionListener(this);
    }

    /**
     * Passing a LibItem that has been populated from the database will assure
     * that the appropriate object is represented in the Library Tree. If the
     * item already exists it will be returned. If it does not exist then it
     * will be created along with any parent path components that do not already
     * exist. The newly created ComponentEntity will then be returned.
     * 
     * This method is private because API users should only be using addKAR and
     * deleteKAR methods to modify the Library.
     * 
     * @param li
     * @return
     */
    private ComponentEntity assureTreeItem(LibItem li) {
        if (isDebugging)
            log.debug("assureTreeItem(" + li.getName() + ")");
        ComponentEntity ce = null;
        try {
            CompositeEntity current = (CompositeEntity) getTreeModel().getRoot();
            Vector<LibItem> pathItems = _libIndex.getPath(li);
            for (int i = 0; i < pathItems.size(); i++) {
                LibItem pathItem = pathItems.elementAt(i);

                int pathLiid = pathItem.getLiid();
                if (isDebugging) {
                    log.debug(pathItem.getName());
                    log.debug(current.getName());
                }

                ComponentEntity existingCE = null;
                List children = current.entityList(ComponentEntity.class);
                for (Object child : children) {
                    if (child instanceof ComponentEntity) {
                        ComponentEntity childCE = (ComponentEntity) child;
                        int childLiid = LibraryManager.getLiidFor(childCE);
                        if (childLiid == pathLiid) {
                            existingCE = childCE;
                            break;
                        }
                    } else {
                        log.error("Child was not a ComponentEntity!");
                    }
                }
                if (existingCE == null) {
                    // add this puppy to the tree
                    ComponentEntity newCE = createAndAddTreeItem(current, pathItem);
                    if (newCE != null) {
                        if (newCE instanceof CompositeEntity) {
                            current = (CompositeEntity) newCE;
                            ce = current;
                        } else {
                            // ComponentEntity leaf node
                            ce = newCE;
                            break;
                        }
                    } else {
                        log.debug("fail");
                        ce = null;
                    }
                } else if (existingCE instanceof CompositeEntity) {
                    current = (CompositeEntity) existingCE;
                    ce = current;
                }
            } // end for loop
        } catch (Exception e) {
            e.printStackTrace();
        }
        return ce;
    }

    /** Create an empty library. When KeplerGraphFrame starts, it initializes
     * ComponentLibraryTab, which in turn requires a library. Building the
     * library with buildLibrary() can take a long time, so this method can
     * be used to open a KeplerGraphFrame quickly.
     */
    public void buildEmptyLibrary() {

        EntityLibrary el = new EntityLibrary(_actorLibraryWorkspace);

        LibItem li = new LibItem();
        li.setName("Empty Library");
        li.setType(LibIndex.TYPE_CONCEPT);

        try {
            createAndAddTreeItem(el, li);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        this.setActorLibrary(el);

    }

    /**
     * This method will synchronize the cache with local repositories. Then it
     * will rebuild the LibIndex if needed. Then it will generate the Actor
     * Library from the LibIndex. To force the rebuilding of the LibIndex before
     * calling this method call getIndex().clear()
     */
    public void buildLibrary() {
        if (isDebugging)
            log.debug("buildLibrary()");
        log.info("Building Library...");

        try {

            KARCacheManager kcm = KARCacheManager.getInstance();

            // Synchronize the Cache with Local Repositories
            boolean changed = kcm.synchronizeKARCacheWithLocalRepositories();

            // Rebuild the Library Index if needed
            _libIndex = new LibIndex(_conn);

            long start = System.currentTimeMillis();
            if (_libIndex.countItems() <= 0) {
                // rebuild the index if it is empty
                _libIndex.rebuild();
            } else if (!_libIndex.verifyPreorderValues()) {
                // rebuild the index if the preorder values don't add up
                // correctly
                log.error("\n\nPreorder values are corrupt! Rebuilding index.\n\n");
                _libIndex.rebuild();
            } else if (changed) {
                // rebuild the index if the KARs in the local repositories have
                // changed
                _libIndex.rebuild();
            }
            if (isDebugging)
                log.debug("\n\nTIME " + (System.currentTimeMillis() - start) + "\n\n");

            // Generate the actor library using the library index
            LibraryGenerator lg = new LibraryGenerator();

            // we're using the same workspace so we need to remove the entities
            clearActorLibrary();

            CompositeEntity newLibrary = lg.generate(_actorLibraryWorkspace, _libIndex);
            this.setActorLibrary(newLibrary);

        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    public void removeAllFrameTabs(TableauFrame parent) {
        if (isDebugging) {
            log.debug("parent in _trees is:" + parent);
            for (int i = 0; i < _trees.size(); i++) {
                JTree treeEle = _trees.elementAt(i).get();
                log.debug("treeEle in _trees element at " + i + " is:" + treeEle);
            }
            log.debug("_libraryModel:" + _libraryModel);
        }
    }

    /**
     * Create and add the appropriate type of placeholder object to the parent
     * CompositeEntity that is in the tree model. Return the object when
     * finished.
     * 
     * Only subtypes of ComponentEntity may be returned. However, the tree item
     * can represent any type of object, depending on what the type is in the
     * LibIndex.
     * 
     * @param li
     * @return
     * @throws NameDuplicationException
     * @throws IllegalActionException
     * @throws IOException
     * @throws IllegalArgumentException
     */
    public ComponentEntity createAndAddTreeItem(CompositeEntity parent, LibItem li)
            throws IllegalActionException, NameDuplicationException, IllegalArgumentException, IOException {
        ComponentEntity ce = null;

        // EditorDropTarget in ptolemy requires an entityId so we set one here
        // even though we don't ever use it for anything, the LSID should
        // always be gotten from the LibItem
        NamedObjId lsidSA = null;

        int type = li.getType();
        String displayName = li.getName();

        String name = displayName;
        // remove periods from the name since they are not allowed
        if (name.contains(".")) {
            name = name.replaceAll("\\.", ",");
        }
        li.setName(name);

        switch (type) {
        case LibIndex.TYPE_COMPONENT:
            ce = new ComponentEntity(parent, li.getName());
            ce.setDisplayName(displayName);
            // This is needed for ptolemy at the moment
            KeplerLSID lsid = li.getLsid();
            if (lsid != null) {
                lsidSA = new NamedObjId(ce, NamedObjId.NAME);
                lsidSA.setExpression(li.getLsid());
            }
            // disable drag and drop for MoML files
            if (li.getAttributeValue(LibIndex.ATT_XMLFILE) != null) {
                Parameter parameter = new Parameter(ce, "_notDraggable");
                parameter.setExpression("true");
            }
            ce.setClassName(li.getAttributeValue(LibIndex.ATT_CLASSNAME));
            ComponentEntityConfig.addSVGIconTo(ce);
            copyAttributes(li, ce);
            break;
        case LibIndex.TYPE_NAMED_OBJ:
            ce = new ComponentEntity(parent, li.getName());
            ce.setDisplayName(displayName);
            lsidSA = new NamedObjId(ce, NamedObjId.NAME);
            lsidSA.setExpression(li.getLsid());
            // ce.setClassName(li.getAttributeValue(LibIndex.ATT_CLASSNAME));
            ComponentEntityConfig.addSVGIconTo(ce);
            // To catch WorkflowRuns
            StringAttribute notDraggableAttribute = new StringAttribute(ce, "_notDraggable");
            notDraggableAttribute.setExpression("true");
            copyAttributes(li, ce);
            break;
        case LibIndex.TYPE_ONTOLOGY:
            ce = new OntologyEntityLibrary(parent, li.getName());
            ce.setDisplayName(displayName);
            break;
        case LibIndex.TYPE_CONCEPT:
            ce = new EntityLibrary(parent, li.getName());
            ce.setDisplayName(displayName);
            break;
        case LibIndex.TYPE_FOLDER:
            ce = new FolderEntityLibrary(parent, li.getName());
            ce.setDisplayName(displayName);
            break;
        case LibIndex.TYPE_LOCALREPO:
            ce = new FolderEntityLibrary(parent, li.getName());
            ce.setDisplayName(displayName);
            break;
        case LibIndex.TYPE_KAR:
            ce = new KAREntityLibrary(parent, li.getName());
            ce.setDisplayName(displayName);
            lsidSA = new NamedObjId(ce, NamedObjId.NAME);
            lsidSA.setExpression(li.getLsid());
            break;
        case LibIndex.TYPE_KAR_ERROR:
            ce = new KARErrorEntityLibrary(parent, li.getName());
            ce.setDisplayName(displayName);
            lsidSA = new NamedObjId(ce, NamedObjId.NAME);
            lsidSA.setExpression(li.getLsid());
            break;
        case LibIndex.TYPE_KARFOLDER:
            ce = new FolderEntityLibrary(parent, li.getName());
            ce.setDisplayName(displayName);
            break;
        case LibIndex.TYPE_OBJECT:
            ce = new ComponentEntity(parent, li.getName());
            ce.setDisplayName(displayName);
            lsidSA = new NamedObjId(ce, NamedObjId.NAME);
            lsidSA.setExpression(li.getLsid());
            // ce.setClassName(li.getAttributeValue(LibIndex.ATT_CLASSNAME));
            ComponentEntityConfig.addSVGIconTo(ce);
            notDraggableAttribute = new StringAttribute(ce, "_notDraggable");
            notDraggableAttribute.setExpression("true");
        }
        if (ce != null) {
            StringAttribute liidSA = new StringAttribute(ce, LibraryManager.LIID_LABEL);
            liidSA.setExpression("" + li.getLiid());
        }
        return ce;
    }

    private void copyAttributes(LibItem li, ComponentEntity ce) {
        Hashtable<String, String> attributes = li.getAttributes();
        for (String key : attributes.keySet()) {
            String value = attributes.get(key);
            try {
                StringAttribute sa = new StringAttribute(ce, key);
                sa.setExpression(value);
            } catch (IllegalActionException e) {
                e.printStackTrace();
            } catch (NameDuplicationException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * Remove a KAR file from the Component Library and from the user's Disk.
     * 
     * @param File
     *            aKarFile
     */
    public void deleteKAR(File aKarFile) {

        KARCacheManager kcm = KARCacheManager.getInstance();
        if (!kcm.isCached(aKarFile)) {
            // this file is not in the cache.
            return;
        }

        KARFile karf;
        try {

            karf = new KARFile(aKarFile);
            File karFileLocation = karf.getFileLocation();
            karf.close(); // free up the file pointer

            // remember what was in the kar file before we remove it all
            Vector<KARCacheContent> entries = kcm.getKARCacheContents(karFileLocation);

            // Remove it from the Index
            LibItem karItem = getIndex().findKar(karFileLocation);
            // make sure KAR is in library
            if (karItem != null) {
                getIndex().removeItem(karItem.getLiid());

                // Remove it from the Library
                ComponentEntity item = findTreeItem(karItem.getLiid());
                if (item == null)
                    return;
                item.setContainer(null);
            }

            // Remove it from the cache
            kcm.removeKARFromCache(karFileLocation);

            // verify that it is gone before doing the rest
            if (!kcm.isCached(karFileLocation)) {

                // Remove the kar file from the file system
                boolean success = karFileLocation.delete();
                if (success) {
                    log.info(karFileLocation.toString() + " was deleted.");
                } else {
                    System.out.println("Unable to delete " + karFileLocation.toString());
                }

                // Update the Ontologies if no other KARs contain the entries
                Vector<KeplerLSID> lsidsToRemoveFromOntologies = new Vector<KeplerLSID>();
                CacheManager cache = CacheManager.getInstance();
                for (KARCacheContent entry : entries) {
                    if (isDebugging)
                        log.debug(entry.getLsid());
                    if (cache.isContained(entry.getLsid())) {
                        // Some other KAR has this object in it too
                        // Don't remove it from the ontologies
                    } else {
                        // This LSID is no longer in the cache
                        lsidsToRemoveFromOntologies.add(entry.getLsid());
                    }
                }
                // remove ontology ComponentEntities that are no longer in the
                // cache
                for (KeplerLSID lsid : lsidsToRemoveFromOntologies) {
                    // now we check each Liid to make sure there are no other
                    // LSIDs
                    // that exist for it

                    // Remove it from the Index
                    Vector<Integer> liidsRemovedFromIndex = getIndex().removeItemsByLsid(lsid);

                    // Remove them from the Library too
                    for (Integer removedLiid : liidsRemovedFromIndex) {
                        ComponentEntity ontItem = findTreeItem(removedLiid.intValue());
                        if (ontItem != null) {
                            ontItem.setContainer(null);
                        } else {
                            log.warn("ontItem not found for " + removedLiid);
                        }
                    }
                }
            }

            // update the JTrees
            refreshJTrees();

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * Look only at the children of the given parent to match the given LIID. Do
     * not recurse the children here, use findTreeItemDeep() for that.
     * 
     * @param parent
     * @param liid
     * @return
     */
    public ComponentEntity findTreeItem(CompositeEntity parent, int liid) {
        if (isDebugging)
            log.debug("findTreeItem(" + parent.getName() + "," + liid + ")");
        ComponentEntity ce = null;
        List<ComponentEntity> children = parent.entityList(ComponentEntity.class);
        for (ComponentEntity child : children) {
            int childLiid = LibraryManager.getLiidFor(child);
            if (isDebugging)
                log.debug("   " + childLiid + " " + child.getName());
            if (childLiid == liid) {
                ce = child;
                // break;
            }
        }
        return ce;
    }

    /**
     * Look in the entire tree and return the ComponentEntity that matches the
     * given LIID.
     * 
     * @param liid
     * @return
     */
    public ComponentEntity findTreeItem(int liid) {
        if (isDebugging)
            log.debug("findTreeItem(" + liid + ")");
        CompositeEntity root = (CompositeEntity) getTreeModel().getRoot();
        ComponentEntity ce = findTreeItemDeep(root, liid);
        if (ce == null) {
            log.debug("Unable to find item " + liid + " in Library Tree");
        }
        return ce;
    }

    /**
     * Recurse all children under parent to match the given LIID.
     * 
     * @param parent
     * @param liid
     * @return
     */
    public ComponentEntity findTreeItemDeep(CompositeEntity parent, int liid) {
        if (isDebugging)
            log.debug("findTreeItemDeep(" + parent.getName() + "," + liid + ")");
        // check the children of this parent to see if any of them match the
        // liid
        ComponentEntity ce = findTreeItem(parent, liid);
        if (ce == null) {
            // recurse the children if we don't find it
            List<CompositeEntity> children = parent.entityList(CompositeEntity.class);
            for (CompositeEntity child : children) {
                ce = findTreeItemDeep(child, liid);
                if (ce != null) {
                    break;
                }
            }
        }
        return ce;
    }

    /**
     * generate the EntityTreeModel version of the library
     * 
     *@return Description of the Return Value
     *@exception IllegalActionException
     *                Description of the Exception
     */
    private void generateTreeModel() {
        if (isDebugging) {
            log.debug("generateTreeModel()");
        }

        _libraryModel = new VisibleTreeModel(_actorLibrary);
    }

    private FilteredVisibleTreeModel generateTreeModel(File filterFile) {
        FilteredVisibleTreeModel treeModel = new FilteredVisibleTreeModel(_libraryModel, filterFile);
        return treeModel;
    }

    /**
     * Get the CompositeEntity version of the library.
     * 
     * */
    public CompositeEntity getActorLibrary() {

        return _actorLibrary;
    }

    private void setActorLibrary(CompositeEntity ce) {
        _actorLibrary = ce;
        generateTreeModel();
    }

    /**
     * @return LibIndex object that the manager is using
     */
    public LibIndex getIndex() {
        return _libIndex;
    }

    /**
     * Return the LIIDs for the given set of LSIDs.
     * 
     * @param lsids
     * @return
     */
    public Vector<Integer> getLiidsFor(Vector<KeplerLSID> lsids) {
        Vector<Integer> liids = new Vector<Integer>();

        for (KeplerLSID lsid : lsids) {
            try {
                String query = "SELECT LIID FROM " + LibIndex.LIBRARY_LSIDS_TABLE_NAME + " WHERE LSID = '" + lsid
                        + "'";
                ResultSet rs = _stmt.executeQuery(query);
                if (rs == null)
                    throw new SQLException("Query Failed: " + query);
                while (rs.next()) {
                    int liid = rs.getInt(1);
                    liids.add(new Integer(liid));
                }
                rs.close();
            } catch (SQLException sqle) {
                sqle.printStackTrace();
            }
        }
        return liids;
    }

    /**
     * Return a populated LibItem for the given liid.
     * 
     * @param liid
     * @return LibItem
     */
    public LibItem getTreeItemIndexInformation(int liid) {
        LibItem li = null;
        try {
            li = getPopulatedLibItem(liid);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return li;
    }

    private void clearActorLibrary() {
        CompositeEntity root = getActorLibrary();
        if (root != null) {
            List childen = root.entityList();
            for (Object child : childen) {
                if (child instanceof ComponentEntity) {
                    try {
                        ((ComponentEntity) child).setContainer(null);
                    } catch (IllegalActionException e) {
                        e.printStackTrace();
                    } catch (NameDuplicationException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    /**
     * @return the TreeModel version of the library.
     */
    public EntityTreeModel getTreeModel() {
        if (_libraryModel == null) {
            generateTreeModel();
        }
        return _libraryModel;
    }

    public EntityTreeModel getTreeModel(File filterFile) {
        return generateTreeModel(filterFile);
    }

    /**
     * Refresh and redraw any JTrees that the LibraryManager is keeping track
     * of.
     * 
     *@exception IllegalActionException
     *                Description of the Exception
     */
    public void refreshJTrees() throws IllegalActionException {
        if (isDebugging) {
            log.debug("refresh");
        }

        // Iterate over all the registered JTrees and reset their models.
        //Iterator<WeakReference> treeItt = _trees.iterator();

        int size = _trees.size();
        int i = 0;
        while (i < size) {
            WeakReference<JTree> wf = _trees.elementAt(i);
            JTree ptree = (JTree) wf.get();
            if (ptree == null) {
                _trees.remove(wf);
                size--;
            } else {
                ptree.setModel(getTreeModel());

                // stop listening for expansion events since we are going to
                // expand the paths and do not want to modify the list
                ptree.removeTreeExpansionListener(this);

                // expand all the paths that were previously expanded
                final List<TreePath> expansions = _treeExpansionMap.get(ptree);
                for (TreePath path : expansions) {
                    //System.out.println("expanding " + path);
                    ptree.expandPath(path);
                }

                // start listening again for expansion events
                ptree.addTreeExpansionListener(this);

                /*
                EntityTreeModel etm = (EntityTreeModel) ptree.getModel();
                    
                // Of course this would be easier if
                // ptolemy.vergil.tree.EntityTreeModel
                // had a reload method similar to DefaultTreeModel
                // that did this for us
                // TODO etm.reload()
                    
                ArrayList<NamedObj> path = new ArrayList<NamedObj>();
                path.add(0, (NamedObj) etm.getRoot());
                TreePath tp = new TreePath(path);
                etm.valueForPathChanged(tp, etm.getRoot());
                */
                i++;
            }
        }
    }

    /**
     * Set the workspace for the actor library and regenerate
     * 
     * @param ws
     */
    public void setActorLibraryWorkspace(Workspace ws) {
        if (isDebugging)
            log.debug("setActorLibraryWorkspace(" + ws.getName() + ")");
        _actorLibraryWorkspace = ws;
    }

    /**
    * Populate this LibItem Object from the database using the given Library
    * Index ID.
    * 
    * @param liid
    * @throws SQLException
    */
    public LibItem getPopulatedLibItem(int liid) throws SQLException {

        LibItem li = new LibItem();
        _getPopulateInfoForLIIDPrepStmt.setInt(1, liid);
        ResultSet rs = _getPopulateInfoForLIIDPrepStmt.executeQuery();
        if (rs == null)
            throw new SQLException("Query Failed: " + _getPopulateInfoForLIIDPrepStmt);
        if (rs.next()) {

            li.setLiid(liid);

            int parent = rs.getInt(1);
            if (rs.wasNull()) {
                li.setParent(null);
            } else {
                li.setParent(new Integer(parent));
            }

            li.setLeft(rs.getInt(2));
            li.setRight(rs.getInt(3));
            li.setLevel(rs.getInt(4));

            String lsid = rs.getString(5);
            if (rs.wasNull()) {
                li.setLsid(null);
            } else {
                try {
                    li.setLsid(new KeplerLSID(lsid));
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            li.setType(rs.getInt(6));
            li.setName(rs.getString(7));

            // double check there is only one row returned for this liid
            if (rs.next()) {
                throw new SQLException(LibIndex.LIBRARY_INDEX_TABLE_NAME + " is corrupt"
                        + " more than one row returned for primary key " + li.getLiid());
            }
        }
        rs.close();

        populateAttributes(li, liid);
        populateLsids(li, liid);

        return li;

    }

    /**
     * Populate this LibItem with the corresponding Attributes stored in the
     * LIBRARY_ATTRIBUTES table for the given LIID.
     * 
     * @param liid
     * @param stmt
     * @throws SQLException
     */
    private void populateAttributes(LibItem li, int liid) throws SQLException {

        _getNameValueForLIIDPrepStmt.setInt(1, liid);
        ResultSet rs = _getNameValueForLIIDPrepStmt.executeQuery();
        if (rs != null) {
            while (rs.next()) {
                String name = rs.getString(1);
                String value = rs.getString(2);
                if (value == null) {
                    value = new String();
                }
                li.addAttribute(name, value);
            }
        }
        rs.close();

    }

    /**
     * Populate this LibItem with the corresponding LSID values stored in the
     * LIBRARY_LSIDS table for the given LIID.
     * 
     * @param liid
     * @param stmt
     * @throws SQLException
     */
    private void populateLsids(LibItem li, int liid) throws SQLException {

        _getLSIDForLIIDPrepStmt.setInt(1, liid);
        ResultSet rs = _getLSIDForLIIDPrepStmt.executeQuery();
        if (rs != null) {
            while (rs.next()) {
                String lsidStr = rs.getString(1);
                KeplerLSID lsid;
                try {
                    lsid = new KeplerLSID(lsidStr);
                    li.addLsid(lsid);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        rs.close();

    }

    /** Called whenever an item in the tree is expanded. */
    @Override
    public void treeExpanded(TreeExpansionEvent event) {
        final Object tree = event.getSource();
        final List<TreePath> expansions = _treeExpansionMap.get(tree);
        if (expansions != null) {
            //System.out.println("expanded " + event.getPath());
            expansions.add(event.getPath());
        }
    }

    /** Called whenever an item in the tree is collapsed. */
    @Override
    public void treeCollapsed(TreeExpansionEvent event) {
        final Object tree = event.getSource();
        final List<TreePath> expansions = _treeExpansionMap.get(tree);
        if (expansions != null) {
            //System.out.println("collapsed " + event.getPath());
            expansions.remove(event.getPath());
        }
    }

}