001    /*
002     * CRIMSON
003     * Copyright (c) 2006, Stephen Fisher, Susan Davidson, and Junhyong Kim, 
004     * University of Pennsylvania.
005     *
006     * This program is free software; you can redistribute it and/or
007     * modify it under the terms of the GNU General Public License as
008     * published by the Free Software Foundation; either version 2 of the
009     * License, or (at your option) any later version.
010     *
011     * This program is distributed in the hope that it will be useful, but
012     * WITHOUT ANY WARRANTY; without even the implied warranty of
013     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014     * General Public License for more details.
015     *
016     * You should have received a copy of the GNU General Public License
017     * along with this program; if not, write to the Free Software
018     * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
019     * 02110-1301 USA.
020     *
021     * @(#)Trees.java
022     */
023    
024    package edu.upenn.crimson.io;
025    
026    import edu.upenn.crimson.*;
027    import java.util.ArrayList;
028    import java.util.Iterator;
029    
030    /**
031     * Functions related to the TREES table.
032     *
033     * @author  Stephen Fisher
034     * @version $Id: Trees.java,v 1.28 2009/07/16 16:19:52 fisher Exp $
035     */
036    
037    public class Trees {
038    
039        //--------------------------------------------------------------------------
040        // Miscellaneous Methods
041    
042             /** This will load all trees from the TREES table. */
043             public static void loadAll() {
044                      // make sure a database is open. We don't need to check for
045                      // the existance of the TREES database because this was done
046                      // when the database was opened.
047                      if (! Database.isOpen()) {
048                                    CrimsonUtils.printError("Unable to build tree list, no open database.");
049                                    return;
050                      }
051    
052                      // clear the lists before we start
053                      ObjectHandles.clearTreeLists();
054                      
055                      CrimsonUtils.printMsg("Loading tree info...");
056    
057                      // get the list of trees in the TREES table.
058                      String sql = "SELECT id, model_id, notes, num_species, num_leaves, ";
059                      sql += "is_binary, is_ultrametric, min_level, max_level, min_temp_depth, max_temp_depth, ";
060                      sql += "min_stem_length, max_stem_length FROM TREES";
061                      ArrayList results = Database.sqlToArray(sql);
062                      
063                      // if the query failed then exit
064                      if (results == null) {
065                                    CrimsonUtils.printError("Unable to build tree lists, error accessing TREES table.");
066                                    return;
067                      }
068    
069                      // convert each row in the results to a Tree
070                      for (Iterator rows = results.iterator(); rows.hasNext();) {
071                                    ArrayList row = (ArrayList) rows.next();
072    
073                                    // we load the stats from the table so we don't need
074                                    // to build the tree and compute the stats.
075                                    new Tree(String.valueOf(row.get(0)), null, 
076                                                            ObjectHandles.getModel(String.valueOf(row.get(1))), 
077                                                            String.valueOf(row.get(2)),
078                                                            Integer.parseInt(String.valueOf(row.get(3))),
079                                                            Integer.parseInt(String.valueOf(row.get(4))),
080                                                            (String.valueOf(row.get(5)).equals("1") ? true : false),
081                                                            (String.valueOf(row.get(6)).equals("1") ? true : false),
082                                                            Integer.parseInt(String.valueOf(row.get(7))),
083                                                            Integer.parseInt(String.valueOf(row.get(8))),
084                                                            Double.parseDouble(String.valueOf(row.get(9))),
085                                                            Double.parseDouble(String.valueOf(row.get(10))),
086                                                            Double.parseDouble(String.valueOf(row.get(11))),
087                                                            Double.parseDouble(String.valueOf(row.get(12))));
088                      }
089             }
090    
091             /** 
092              * Removes a tree from the database. When trees are deleted, the
093              * database will automatically remove the related entries in the
094              * PARTITIONS and PART_DATA table.  If delQueries is true then
095              * remove any queries that reference this tree.  If delQueries is
096              * false, then quit on error if any queries reference this tree.
097              * @XXX We aren't relying on the database sutomatic cascade
098              * deleting of records because the version of MySQL prior to 5.1
099              * do not support this fuction for MyISAM tables, which are the
100              * tables we are using.
101              */
102             public static boolean delete(String id, boolean delQueries) { 
103                      if (! ObjectHandles.containsTree(id)) {
104                                    CrimsonUtils.printWarning("Tree '" + id + "' doesn't exist and thus can't be deleted.");
105                                    return false;
106                      }
107    
108                      id = id.toUpperCase();
109                      String queries = "";
110                      ArrayList qToDelete = new ArrayList();
111                      for (Iterator i = ObjectHandles.queryIterator(); i.hasNext();) {
112                                    Query query = (Query) i.next();
113                                    if (id.equals(query.getTreeID())) {
114                                             if (delQueries) {
115                                                      CrimsonUtils.printWarning("Query '" + query.getID() + "' being deleted.");
116                                                      qToDelete.add(query.getID());
117                                             } else {
118                                                      queries += "   Query: " + query.getID() + "\n";
119                                             }                                                
120                                    }
121                      }
122    
123                      if (! CrimsonUtils.isEmpty(queries)) {
124                                    CrimsonUtils.printError("Queries exist that reference the tree '" + id + "'.");
125                                    CrimsonUtils.printError("These queries must be changed to reference other trees before this tree can be deleted.");
126                                    CrimsonUtils.printError("If these queries are in the database, then the changes must be published to the database.\n" + queries);
127                                    return false;
128                      } else if (qToDelete.size() > 0) {
129                                    for (Iterator i = qToDelete.iterator(); i.hasNext();) {
130                                             Queries.delete((String) i.next());
131                                    }
132                      }
133    
134                      Tree tree = ObjectHandles.getTree(id);
135                      for (Iterator i = tree.getPartitions().iterator(); i.hasNext();) {
136                                    Partition partition = (Partition) i.next();
137                                    if (! Partitions.delete(partition.getID())) return false;
138                      }
139    
140                      // if successfully delete all partitions, then delete the tree
141                      if (! Database.delete("TREES", id)) return false;
142    
143                      // rebuild tree and partition list
144                      loadAll();
145                      Partitions.loadAll();
146    
147                      return true;
148             }
149    
150             /** 
151              * This will return true if a tree exists in TREES with an id
152              * equal to 'id'.
153              */
154             public static boolean dbContains(String id) {
155                      ArrayList out = Database.sqlToArray("SELECT id FROM TREES WHERE id = '" + id.toUpperCase() + "'");
156                      if ((out == null) || (out.size() == 0)) return false;
157                      else return true;
158             }
159    
160             /** 
161              * Returns the non-Blob columns in the TREES table. Each table
162              * record will be separated by a '\n' in the output.
163              */
164             public String toString() {
165                      // SELECT id, species, max_temp_depth, notes FROM trees;
166                      String sql = "SELECT ID, MODEL_ID, NOTES FROM TREES";
167                      ArrayList results = Database.sqlToArray(sql);
168    
169                      if (results == null) {
170                                    CrimsonUtils.printError("Error printing TREES table.");
171                                    return "";
172                      }
173    
174                      StringBuffer out = new StringBuffer("");
175                      out.append("ID \t MODEL_ID \t NOTES\n");
176                      for (Iterator rows = results.iterator(); rows.hasNext();) {
177                                    ArrayList row = (ArrayList) rows.next();
178                                    for (int i = 0; i < 2; i++) out.append(String.valueOf(row.get(i)) + " \t ");
179                                    out.append(String.valueOf(row.get(2)) + "\n");
180                      }
181    
182                      return out.toString().trim();
183             }
184    
185    } // Trees.java