/* * Copyright (c) 2008, SQL Power Group Inc. * * This file is part of Wabit. * * Wabit is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * Wabit is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package ca.sqlpower.query; import java.awt.geom.Point2D; import java.util.ArrayList; import java.util.List; import javax.annotation.Nonnull; import org.apache.log4j.Logger; import ca.sqlpower.sqlobject.SQLColumn; import ca.sqlpower.sqlobject.SQLDatabase; import ca.sqlpower.sqlobject.SQLObject; import ca.sqlpower.sqlobject.SQLObjectException; import ca.sqlpower.sqlobject.SQLTable; /** * A model that stores SQLTable elements. This will store objects of a defined type and * can be grouped when adding the items to the model. * * @param <C> The type of object this model will store. */ public class TableContainer extends ItemContainer implements Container { private static final Logger logger = Logger.getLogger(TableContainer.class); private SQLTable table; /** * The list contains all of the columns of the table. */ private final List<SQLObjectItem> itemList; /** * The catalog that the SQLTable contained in this container belongs to. */ private final String catalog; /** * The schema that the SQLTable contained in this container belongs to. */ private final String schema; /** * This is the database the table is stored in so we can load the table or * refresh it as necessary. */ private final SQLDatabase database; public TableContainer(@Nonnull SQLDatabase db, @Nonnull SQLTable t) { super(t.getName()); if (db == null) { throw new NullPointerException("Database mustn't be null when providing a live SQLTable."); } database = db; table = t; schema = table.getSchemaName(); catalog = table.getCatalogName(); setAlias(""); itemList = new ArrayList<SQLObjectItem>(); loadColumnsFromTable(t); } /** * This constructor creates a table that will be loaded from the database when a part of the * container is accessed. To load the table the table's name, schema and catalog will be used * to retrieve the table from the database. The items of this container will have it's object * set when the table is loaded. */ public TableContainer(String uuid, SQLDatabase db, String name, String schema, String catalog, List<SQLObjectItem> items) { this(uuid, db, name, schema, catalog, items, false); } /** * This constructor creates a table that will be loaded from the database * when a part of the container is accessed if the populated flag is set to * false. To load the table the table's name, schema and catalog will be * used to retrieve the table from the database. The items of this container * will have it's object set when the table is loaded. * * @param doPopulate * If set to false the objects will be considered populated and * will not try to populate again. This is useful for places like * the session on the server that can just accept the objects * given to it, it does not need to manipulate the objects * further. If true the object named in this container will be * populated when accessed. */ public TableContainer(String uuid, SQLDatabase db, String name, String schema, String catalog, List<SQLObjectItem> items, boolean doPopulate) { super(name, uuid); if (db == null) { logger.debug("Database connection for table " + name + " is missing. Although " + "this is non-fatal, it should only happen if the actual database " + "connection was unavailable at the time the workspace was loaded", new Exception("Don't panic. Just a stack trace")); } database = db; if (schema != null) { this.schema = schema; } else { this.schema = ""; } if (catalog != null) { this.catalog = catalog; } else { this.catalog = ""; } setName(name); if (doPopulate) { table = null; } else { try { table = new SQLTable(db, true); table.setName(name); } catch (SQLObjectException e) { throw new RuntimeException("Cannot happen", e); } } super.setAlias(""); itemList = new ArrayList<SQLObjectItem>(); for (SQLObjectItem item : items) { item.setParent(this); itemList.add(item); fireChildAdded(item, itemList.indexOf(item)); } } /** * This will create the items from the columns for the table. This * needs to be called right after the table gets set. */ private void loadColumnsFromTable(SQLTable t) { try { for (SQLColumn child : t.getColumns()) { boolean itemFound = false; for (Item item : itemList) { if (item.getName().equals(child.getName())) { ((SQLObjectItem) item).setItem(child); itemFound = true; break; } } if (itemFound) { continue; } SQLObjectItem item = new SQLObjectItem(child); item.setParent(this); itemList.add(item); fireChildAdded(item, itemList.indexOf(item)); } } catch (SQLObjectException e) { throw new RuntimeException(e); } } public List<Item> getItems() { loadTableByQualifiedName(); return new ArrayList<Item>(itemList); } public String getName() { loadTableByQualifiedName(); if (table != null) { return table.getName(); } else { return super.getName(); } } public Item getItem(Object item) { loadTableByQualifiedName(); for (Item i : itemList) { if (i.getItem() == item) { return i; } } return null; } public SQLDatabase getDatabase() { return database; } public Object getContainedObject() { loadTableByQualifiedName(); return table; } public void addItem(Item item) { throw new IllegalStateException("Cannot add arbitrary items to a SQLObject."); } public void removeItem(Item item) { throw new IllegalStateException("Cannot remove arbitrary items from a SQLObject."); } public void removeItem(int i) { throw new IllegalStateException("Cannot remove arbitrary items from a SQLObject."); } public String getSchema() { return schema; } public String getCatalog() { return catalog; } /** * This will load the table from the query's data source as necessary * if it is null and the qualified name is not null. * <p> * This is package private to allow the container's items to load their * parent table and theirselves. */ void loadTableByQualifiedName() { if (table == null) { SQLDatabase db = database; logger.debug("Cache has database " + db); if (db == null) { logger.info("Skipping table " + super.getName() + " because its database connection is missing"); return; } try { table = db.getTableByName(catalog, schema, super.getName()); } catch (SQLObjectException e) { logger.info("Skipping table " + super.getName() + " due to failure in populate:", e); return; } if (table == null) { logger.info("Skipping table " + super.getName() + " because it doesn't exist in the database"); return; } loadColumnsFromTable(table); } } @Override public Container createCopy() { final TableContainer copy; if (database != null && table != null) { copy = new TableContainer(database, table); } else { copy = new TableContainer(getUUID(), database, getName(), schema, catalog, itemList); } for (Item item : itemList) { Item newItem = copy.getItem(item.getItem()); newItem.setAlias(item.getAlias()); newItem.setColumnWidth(item.getColumnWidth()); newItem.setGroupBy(item.getGroupBy()); newItem.setHaving(item.getHaving()); newItem.setOrderBy(item.getOrderBy()); newItem.setOrderByOrdering(item.getOrderByOrdering()); newItem.setSelected(item.getSelected()); newItem.setWhere(item.getWhere()); } copy.setAlias(getAlias()); copy.setPosition(new Point2D.Double(getPosition().getX(), getPosition().getY())); return copy; } @Override public boolean equals(Object obj) { if (obj instanceof TableContainer && ((TableContainer) obj).getUUID().equals(getUUID())) { return true; } return false; } @Override public int hashCode() { return 31 * 17 + getUUID().hashCode(); } }