001/*
002 * Copyright (c) 2010 The Regents of the University of California.
003 * All rights reserved.
004 *
005 * '$Author: welker $'
006 * '$Date: 2010-05-06 05:21:26 +0000 (Thu, 06 May 2010) $' 
007 * '$Revision: 24234 $'
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
030package org.ecoinformatics.seek.dataquery;
031
032import java.sql.SQLException;
033
034import org.apache.commons.logging.Log;
035import org.apache.commons.logging.LogFactory;
036import org.kepler.objectmanager.data.db.Entity;
037
038/**
039 * This class will try to generate a unique table name base on a given
040 * TableEntity object.
041 * 
042 * @author Jing Tao
043 * 
044 */
045public class DBTableNameResolver {
046        private static final String PREFIX = "T";
047
048        private static Log log;
049        private static boolean isDebugging;
050
051        static {
052                log = LogFactory.getLog("org.ecoinformatics.seek.dataquery");
053                isDebugging = log.isDebugEnabled();
054        }
055
056        /**
057         * If the url in this TableEntity is null, we will use the TableEntity name
058         * as url. First we will check if the url is already in the system table
059         * which store the url and table mapping. If the url already existed, the
060         * table name will be set as the table name stored in system table. If the
061         * url doesn't exited, the hashcode of this url (add profix "T") as table
062         * name.
063         * 
064         * @param table
065         *            TableEntity
066         * @throws SQLException
067         * @throws ClassNotFoundException
068         * @return TableEntity
069         */
070        public Entity resolveTableName(Entity table) throws SQLException,
071                        ClassNotFoundException {
072                String newTableName = null;
073                String url = table.getURL();
074                if (url == null) {
075                        url = table.getName();
076                }
077                // check if the url already existed in system table
078                DBTableExistenceChecker checker = new DBTableExistenceChecker();
079                // if the table already existed, we don't need
080                // generate table name again(url is the key)
081                if (checker.isURLExisted(url)) {
082                        // to do get the table name and set to table entity
083                        newTableName = checker.getTableName(url);
084                        if (isDebugging) {
085                                log
086                                                .debug("Get the table name for system table "
087                                                                + newTableName);
088                        }
089                        table.setDBTableName(newTableName);
090                        return table;
091                }
092                // if this is a record we need to generate the tablename
093                newTableName = generateTableName(table);
094                table.setDBTableName(newTableName);
095                return table;
096        }
097
098        /*
099         * Method to generate a talbe name base a given TableEnity object. Now it
100         * use url to generate hash and add a given letter in first position. If the
101         * generate table name already in persistant table, it will append random
102         * strings
103         */
104        private String generateTableName(Entity table) throws SQLException,
105                        ClassNotFoundException {
106                int maxTime = 5;
107
108                String tableName = null;
109                String url = table.getURL();
110                // if url is null, set url as same as entity name
111                if (url == null) {
112                        url = table.getName();
113                }
114                int hashNumber = url.hashCode();
115                // remove "-" because hsql doesn't allow it in table name
116                hashNumber = removeNegativeSymbolFromHashNumber(hashNumber);
117                if (isDebugging) {
118                        log.debug("The hash number is " + hashNumber);
119                }
120                tableName = PREFIX + hashNumber;
121                // check if the generate table already existed, if exited, append some
122                // random character. If the while loop runs > maxTime times, throw a
123                // exception
124                DBTableExistenceChecker checker = new DBTableExistenceChecker();
125                int times = 0;
126                while (checker.isTableNameExisted(tableName)) {
127                        String random = generateRandomString();
128                        tableName = tableName + random;
129                        times++;
130                        if (times > maxTime) {
131                                throw new SQLException(
132                                                "Couldn't generate a non duplicate table name");
133                        }
134                }
135                if (isDebugging) {
136                        log.debug("The table name is " + tableName);
137                }
138                return tableName;
139        }// generateTableName
140
141        /*
142         * method to generate a random string which lenght is between 1 to 10.
143         */
144        private String generateRandomString() {
145                String randomString = "";
146                char[] letters = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
147                                'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
148                                'w', 'x', 'y', 'z' };
149                int length = (new Double(Math.random() * 10)).intValue() + 1;
150                if (isDebugging) {
151                        log.debug("The appendix string lenghth is " + length);
152                }
153                for (int i = 0; i < length; i++) {
154                        int random = (new Double(Math.random() * 26)).intValue();
155                        if (random >= 25) {
156                                random = 25;
157                        }
158                        char selectChar = letters[random];
159                        randomString = randomString + selectChar;
160                }
161                if (isDebugging) {
162                        log.debug("the random string is " + randomString);
163                }
164                return randomString;
165        }// generateRandomString
166
167        /*
168         * Method to remove negative symbol for hash number. Table name doesn't
169         * allow "-" in hsql
170         */
171        private int removeNegativeSymbolFromHashNumber(int hashNumber) {
172                int newHashNumber = hashNumber;
173                String hashNumberString = (new Integer(hashNumber)).toString();
174                if (isDebugging) {
175                        log.debug("transform hashnumber from int " + hashNumber
176                                        + " to string " + hashNumberString);
177                }
178                if (hashNumberString != null && hashNumberString.startsWith("-")) {
179                        hashNumberString = hashNumberString.substring(1);
180                        if (isDebugging) {
181                                log.debug("The new string after removing negative symbol is "
182                                                + hashNumberString);
183                        }
184                        newHashNumber = (new Integer(hashNumberString)).intValue();
185
186                }
187                if (isDebugging) {
188                        log.debug("The new hash number after removing netative symbol is "
189                                        + newHashNumber);
190                }
191                return newHashNumber;
192        }// removeNegativeSymbolFromHashNumber
193
194}