package net.sourceforge.sqlexplorer.sessiontree.model.utility; /* * Copyright (C) 2002-2004 Andrea Mazzolini * andreamazzolini@users.sourceforge.net * * This program 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 2 * of the License, or any later version. * * This program 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, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.TreeSet; import net.sourceforge.sqlexplorer.Messages; import net.sourceforge.sqlexplorer.dbstructure.nodes.CatalogNode; import net.sourceforge.sqlexplorer.dbstructure.nodes.DatabaseNode; import net.sourceforge.sqlexplorer.dbstructure.nodes.INode; import net.sourceforge.sqlexplorer.dbstructure.nodes.SchemaNode; import net.sourceforge.sqlexplorer.dbstructure.nodes.TableNode; import net.sourceforge.sqlexplorer.sqleditor.SQLCodeScanner; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.eclipse.core.runtime.IProgressMonitor; public class Dictionary { // TODO check if we need to add more types or remove restriction completely? private static final String[] SUPPORTED_CONTENT_ASSIST_TYPES = new String[] {"TABLE_FOLDER", "TABLE_TYPE", "VIEW_FOLDER", "VIEW_TYPE"}; private static final Log _logger = LogFactory.getLog(Dictionary.class); public Dictionary() { } private static TernarySearchTree keywordsTree = new TernarySearchTree(); static { String[] str = SQLCodeScanner.getFgKeywords(); for (int i = 0; i < str.length; i++) keywordsTree.put(str[i], str[i]); } private TernarySearchTree tables = new TernarySearchTree(); private TernarySearchTree catalogSchemaTree = new TernarySearchTree(); private TernarySearchTree externalObjectTree = new TernarySearchTree(); private HashMap realTables = new HashMap(); private HashMap realCatalogSchemas = new HashMap(); private HashMap realExternalObjects = new HashMap(); private HashMap col_map = new HashMap(); private static int ROOT_WORK_UNIT = 1000; public void putTableName(String key, Object value) { tables.put(key.toLowerCase(), value); realTables.put(key.toLowerCase(), key); } public void putCatalogSchemaName(String key, Object value) { catalogSchemaTree.put(key.toLowerCase(), value); realCatalogSchemas.put(key.toLowerCase(), key); } public void putExternalObjectName(String key, Object value) { externalObjectTree.put(key.toLowerCase(), value); realExternalObjects.put(key.toLowerCase(), key); } public Object getByTableName(String key) { return tables.get(key); } public Object getByCatalogSchemaName(String key) { return catalogSchemaTree.get(key); } public Object getByExternalObjectName(String key) { return catalogSchemaTree.get(key); } public void putColumnsByTableName(String key, Object value) { col_map.put(key.toLowerCase(), value); } public Object getColumnListByTableName(String key) { return col_map.get(key); } public Iterator getTableNames() { return realTables.keySet().iterator(); } public Iterator getCatalogSchemaNames() { return realCatalogSchemas.keySet().iterator(); } public Iterator getExternalObjectNames() { return realExternalObjects.keySet().iterator(); } public ArrayList getTableObjectList(String tableName) { return (ArrayList) tables.get(tableName.toLowerCase()); } public String[] matchTablePrefix(String prefix) { String p = prefix.toLowerCase(); DoublyLinkedList linkedList = tables.matchPrefix(p); int size = linkedList.size(); DoublyLinkedList.DLLIterator iterator = linkedList.iterator(); String[] result = new String[size]; int k = 0; while (iterator.hasNext()) { result[k++] = (String) realTables.get(iterator.next()); } return result; } public String[] matchCatalogSchemaPrefix(String prefix) { String p = prefix.toLowerCase(); DoublyLinkedList linkedList = catalogSchemaTree.matchPrefix(p); int size = linkedList.size(); DoublyLinkedList.DLLIterator iterator = linkedList.iterator(); String[] result = new String[size]; int k = 0; while (iterator.hasNext()) { result[k++] = (String) realCatalogSchemas.get(iterator.next()); } return result; } public String[] matchExternalObjectPrefix(String prefix) { String p = prefix.toLowerCase(); DoublyLinkedList linkedList = externalObjectTree.matchPrefix(p); int size = linkedList.size(); DoublyLinkedList.DLLIterator iterator = linkedList.iterator(); String[] result = new String[size]; int k = 0; while (iterator.hasNext()) { result[k++] = (String) realExternalObjects.get(iterator.next()); } return result; } public static String[] matchKeywordsPrefix(String prefix) { String p = prefix.toLowerCase(); DoublyLinkedList linkedList = keywordsTree.matchPrefix(p); int size = linkedList.size(); DoublyLinkedList.DLLIterator iterator = linkedList.iterator(); String[] result = new String[size]; int k = 0; while (iterator.hasNext()) { result[k++] = (String) iterator.next(); } return result; } /** * Loads the persisted dictionary from a previous session. * * @param dbNode DatabaseNode for which to load the dictionary * @return true if dictionary was found and loaded */ public boolean restore(DatabaseNode dbNode, IProgressMonitor monitor) throws InterruptedException { // TODO implement return false; } /** * Persists this dictionary so that it can be reused in next sessions * without having to be reloaded from database. */ public void store() { // TODO implement } /** * Perform full load of dictionary for dbNode * * @param dbNode DatabaseNode of which to load dictionary information * @param monitor ProgressMonitor displayed whilst loading * @throws InterruptedException If user cancelled loading */ public void load(DatabaseNode dbNode, IProgressMonitor monitor) throws InterruptedException { try { // check for cancellation by user if (monitor.isCanceled()) { throw new InterruptedException(Messages.getString("Progress.Dictionary.Cancelled")); } INode[] children = dbNode.getChildNodes(); if (children == null) { return; } // start task with a 1000 work units for every root node monitor.beginTask(dbNode.getSession().toString(), children.length * ROOT_WORK_UNIT); for (int i = 0; i < children.length; i++) { // check for cancellation by user if (monitor.isCanceled()) { throw new InterruptedException(Messages.getString("Progress.Dictionary.Cancelled")); } INode node = (INode) children[i]; if (node instanceof SchemaNode || node instanceof CatalogNode) { loadSchemaCatalog(node, monitor); } } // store dictionary immediately so that // we can resuse it if a second session is opened store(); } finally { monitor.done(); } } /** * Load dictionary data for catalog * * @param node catalognode to load * @param monitor ProgressMonitor displayed whilst loading * @throws InterruptedException If user cancelled loading */ private void loadSchemaCatalog(INode iNode, IProgressMonitor monitor) throws InterruptedException { if (_logger.isDebugEnabled()) { _logger.debug("Loading dictionary: " + iNode.getName()); } // check for cancellation by user if (monitor.isCanceled()) { throw new InterruptedException(Messages.getString("Progress.Dictionary.Cancelled")); } putCatalogSchemaName(iNode.toString(), iNode); monitor.subTask(iNode.getName()); INode[] children = iNode.getChildNodes(); if (children != null) { // check for cancellation by user if (monitor.isCanceled()) { throw new InterruptedException(Messages.getString("Progress.Dictionary.Cancelled")); } // divide work equally between type nodes int typeNodeWorkUnit = ROOT_WORK_UNIT / SUPPORTED_CONTENT_ASSIST_TYPES.length; int typeNodeWorkCompleted = 0; for (int i = 0; i < children.length; i++) { INode typeNode = children[i]; if (_logger.isDebugEnabled()) { _logger.debug("Loading dictionary: " + typeNode.getName()); } // only load a few types like tables and view nodes into the // dictionary boolean isIncludedInContentAssist = false; for (int j = 0; j < SUPPORTED_CONTENT_ASSIST_TYPES.length; j++) { if (typeNode.getType().equalsIgnoreCase(SUPPORTED_CONTENT_ASSIST_TYPES[j])) { isIncludedInContentAssist = true; } } if (!isIncludedInContentAssist) { continue; } monitor.subTask(typeNode.getName()); // check for cancellation by user if (monitor.isCanceled()) { throw new InterruptedException(Messages.getString("Progress.Dictionary.Cancelled")); } INode tableNodes[] = typeNode.getChildNodes(); if (tableNodes != null) { // check for cancellation by user if (monitor.isCanceled()) { throw new InterruptedException(Messages.getString("Progress.Dictionary.Cancelled")); } int tableNodeWorkUnit = typeNodeWorkUnit / tableNodes.length; for (int j = 0; j < tableNodes.length; j++) { INode tableNode = tableNodes[j]; if (_logger.isDebugEnabled()) { _logger.debug("Loading dictionary: " + tableNode.getName()); } if (monitor != null) { monitor.worked(tableNodeWorkUnit); typeNodeWorkCompleted = typeNodeWorkCompleted + tableNodeWorkUnit; if (_logger.isDebugEnabled()) { _logger.debug("worked table: " + tableNodeWorkUnit + ", total type work: " + typeNodeWorkCompleted); } monitor.subTask(tableNode.getQualifiedName()); // check for cancellation by user if (monitor.isCanceled()) { throw new InterruptedException(Messages.getString("Progress.Dictionary.Cancelled")); } } // add table name ArrayList tableDetails = (ArrayList) getByTableName(tableNode.getName()); if (tableDetails == null) { tableDetails = new ArrayList(); putTableName(tableNode.getName(), tableDetails); } tableDetails.add(tableNode); // add column names if (tableNode instanceof TableNode) { TreeSet columnNames = new TreeSet(); List columns = ((TableNode) tableNode).getColumnNames(); if (columns != null) { Iterator it = columns.iterator(); while (it.hasNext()) { columnNames.add(it.next()); } } putColumnsByTableName(tableNode.getName(), columnNames); } } } if (typeNodeWorkCompleted < typeNodeWorkUnit) { // consume remainder of work for this type node if (_logger.isDebugEnabled()) { _logger.debug("consuming remainder: " + (typeNodeWorkUnit - typeNodeWorkCompleted)); } monitor.worked(typeNodeWorkUnit - typeNodeWorkCompleted); } typeNodeWorkCompleted = 0; } } } }