001package com.randomnoun.common.db;
002
003/* (c) 2013 randomnoun. All Rights Reserved. This work is licensed under a
004 * BSD Simplified License. (http://www.randomnoun.com/bsd-simplified.html)
005 */
006
007import java.util.HashMap;
008
009import javax.sql.DataSource;
010
011import org.springframework.jdbc.core.JdbcTemplate;
012
013import com.randomnoun.common.db.to.SchemaTO;
014import com.randomnoun.common.db.to.TableColumnTO;
015import com.randomnoun.common.db.to.TableTO;
016
017/** Container class for database metadata.
018 * 
019 * <p>Rewrite of DatabaseTO to be marginally more structured
020 * 
021 * <p>Contains methods for populating metadata from the data dictionaries of
022 * Oracle and MySQL, for the purposes of whatever it is that I'm doing at the time.
023 *
024 *  
025 *  NB: does not set default values for oracle
026 *  
027 */
028public abstract class DatabaseReader {
029
030        protected com.randomnoun.common.db.to.DatabaseTO db;
031    
032        // only required for online DB metadata
033        public DataSource ds;
034        public JdbcTemplate jt;
035        
036        /* these aren't used yet
037        public static class SourceTypeTO {
038                public SchemaTO schema;
039                public List packages;
040                public List packageBodies;
041                public List procedures;
042                public List functions;
043                public List triggers;
044        }
045        
046        public static class UserTypeTO {
047                public SchemaTO schema;
048                public List arrayTypes;
049                public List objectTypes;
050                public List tableTypes;
051                public List xmlSchema;
052        }
053        
054        public static class SecurityTO {
055                public SchemaTO schema;
056                public List users;
057                public List roles;
058                public List profiles;
059        }
060        
061        public static class StorageTO {
062                public SchemaTO schema;
063                public Map<String, TableTO> tablespaces;
064                public List datafiles;
065                public List rollbackSegments;
066                public List redoLogGroups;
067                public List archiveLogs;
068        }
069        
070        public static class DistributedTO {
071                public SchemaTO schema;
072                public List inDoubtTransactions;
073                public List databaseLinks;
074                public List streams;
075                public List advancedQueues;
076                public List advancedReplication;
077        }
078        */
079        
080        /** Database metadata container. Will load reference data on demand */
081        // @TODO look up correct Reader instance and use that 
082        public DatabaseReader(DataSource dataSource /*, DatabaseType dbType*/) {
083                this.ds = dataSource;
084                this.jt = new JdbcTemplate(dataSource);
085                this.db = new com.randomnoun.common.db.to.DatabaseTO();
086                db.setDatabaseType(null);
087                db.setSchemaMap(new HashMap<String, SchemaTO>());
088        }
089        
090        
091        // this only works for MYSQL. so that's odd.
092        public SchemaTO getSchema(String schemaName) {
093                
094                // default schema name
095                if (schemaName==null) {
096                        switch (db.getDatabaseType()) {
097                                case ORACLE:
098                                        throw new UnsupportedOperationException("Not supported for this database type");
099                                
100                                case MYSQL:
101                                        schemaName = (String) jt.queryForObject("SELECT DATABASE();", java.lang.String.class);
102                                        break;
103                        
104                                case SQLSERVER:
105                                        throw new UnsupportedOperationException("Not supported for this database type");
106                                        
107                                default:
108                                        throw new IllegalStateException("Unknown database type " + db.getDatabaseType());
109                        }
110                }
111                
112                SchemaTO schema = db.getSchemaMap().get(db.upper(schemaName));
113                if (schema == null) {
114                        schema = readSchema(db.upper(schemaName));
115                        db.getSchemaMap().put(db.upper(schemaName), schema); 
116                }
117                return schema;
118        }
119        
120        abstract public SchemaTO readSchema(String schemaName);  // SchemaTO schema
121        
122        
123        // @TODO pass in current schema/table for context resolution
124        public TableColumnTO getColumn(com.randomnoun.common.db.to.DatabaseTO db, String identifier) {
125                String schemaName = null;
126                String tableName = null;
127                String columnName = null;
128                String[] bits = identifier.split("\\.");
129                if (bits.length > 3) { throw new IllegalArgumentException("Too many components in column identifier '" + identifier + "'"); }
130                if (bits.length < 1) { throw new IllegalArgumentException("Too few components in column identifier '" + identifier + "'"); }
131                if (bits.length > 2) { schemaName = bits[bits.length - 3]; }
132                if (bits.length > 1) { tableName = bits[bits.length - 2]; }
133                columnName = bits[bits.length - 1];
134                SchemaTO schema = db.getSchemaMap().get(schemaName); 
135                TableTO table = schema.getTable(tableName);
136                return table.getTableColumn(columnName);
137        }
138        
139}