001    /**
002     *  Licensed to the Apache Software Foundation (ASF) under one or more
003     *  contributor license agreements.  See the NOTICE file distributed with
004     *  this work for additional information regarding copyright ownership.
005     *  The ASF licenses this file to You under the Apache License, Version 2.0
006     *  (the "License"); you may not use this file except in compliance with
007     *  the License.  You may obtain a copy of the License at
008     *
009     *     http://www.apache.org/licenses/LICENSE-2.0
010     *
011     *  Unless required by applicable law or agreed to in writing, software
012     *  distributed under the License is distributed on an "AS IS" BASIS,
013     *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     *  See the License for the specific language governing permissions and
015     *  limitations under the License.
016     */
017    
018    package org.apache.geronimo.console.internaldb;
019    
020    import java.sql.Connection;
021    import java.sql.DriverManager;
022    import java.sql.SQLException;
023    import java.util.Set;
024    
025    import javax.sql.DataSource;
026    
027    import org.apache.commons.logging.Log;
028    import org.apache.commons.logging.LogFactory;
029    import org.apache.geronimo.console.util.KernelManagementHelper;
030    import org.apache.geronimo.console.util.ManagementHelper;
031    import org.apache.geronimo.derby.DerbySystemGBean;
032    import org.apache.geronimo.gbean.AbstractName;
033    import org.apache.geronimo.gbean.AbstractNameQuery;
034    import org.apache.geronimo.j2ee.j2eeobjectnames.NameFactory;
035    import org.apache.geronimo.kernel.Kernel;
036    import org.apache.geronimo.kernel.KernelRegistry;
037    import org.apache.geronimo.management.JCAManagedConnectionFactory;
038    import org.apache.geronimo.management.geronimo.ResourceAdapterModule;
039    
040    /**
041     * A static class to handle retreiving connections. This class is built to
042     * handle lookups to the SystemDatabase as a special case. If a connection is
043     * requested for the SystemDatabase this class gets a DataSource from an admin
044     * object registered in the geronimo kernel otherwise the DataSource is looked
045     * up via JNDI.
046     *
047     * @version $Rev: 706640 $ $Date: 2008-10-21 14:44:05 +0000 (Tue, 21 Oct 2008) $
048     */
049    public class DerbyConnectionUtil {
050    
051        private final static Log log = LogFactory.getLog(DerbyConnectionUtil.class);
052    
053            public static final String CREATE_DB_PROP = ";create=true";
054    
055        public static final String SHUTDOWN_DB_PROP = ";shutdown=true";
056    
057        private static final int RDBMS_DERBY = 1;
058    
059        private static final int RDBMS_MSSQL = 2;
060    
061        private static final String SYSTEM_DB = "SYSTEMDATABASE";
062    
063        private static final String DERBY_DRIVER = "org.apache.derby.jdbc.EmbeddedDriver";
064    
065        private static final String PROTOCOL = "jdbc:derby:";
066    
067        private static final String EMPTY_PROPS = "";
068        
069        private static AbstractName SYSTEM_DATASOURCE_NAME = null;
070        
071        static {
072            try {
073                log.debug("Looking up system datasource name...");
074    
075                // cache the name for the system data source
076                AbstractNameQuery query = new AbstractNameQuery(JCAManagedConnectionFactory.class.getName());
077                Set<AbstractName> names = KernelRegistry.getSingleKernel().listGBeans(query);
078                for (AbstractName name : names) {
079                    String nameProperty = name.getNameProperty("name");
080                    if ("SystemDatasource".equals(nameProperty)) {
081                        SYSTEM_DATASOURCE_NAME = name;
082                        log.debug("Using system datasource name: " + SYSTEM_DATASOURCE_NAME);
083                    }
084                }
085                
086                if (SYSTEM_DATASOURCE_NAME == null) {
087                    log.warn("Failed to lookup system datasource name");
088                }
089            }
090            catch (Throwable t) {
091                //
092                // HACK: Log any errors which occur when this is loading...
093                //       the system is not logging the full detail, which it should
094                //       but for now lets show the details here
095                //
096                log.error("Failed to initialize", t);
097                throw new Error(t);
098            }
099        }
100        
101        private static String derbyHome = null;
102        
103        /**
104         * Get the Derby home directory path.
105         */
106        public static String getDerbyHome() {
107            if (derbyHome == null) {
108                try {
109                    derbyHome = (String)KernelRegistry.getSingleKernel().getAttribute(DerbySystemGBean.class, "derbyHome");
110                }
111                catch (Exception e) {
112                    throw new RuntimeException("Failed to query derbyHome", e);
113                }
114            }
115            return derbyHome;
116        }
117        
118        /**
119         * Get database connection.
120         *
121         * @param dbName
122         * @return
123         * @throws SQLException
124         */
125        private static Connection getConnection(String dbName, String properties,
126                String protocol, String driver) throws SQLException {
127            try {
128                Class.forName(driver).newInstance();
129            } catch (Exception e) {
130                    log.error("Problem loading driver class", e);
131            }
132            // If we are looking for the SystemDatabase get it from the kernel
133            // because it is not binded to our JNDI Context.
134            if (SYSTEM_DB.equalsIgnoreCase(dbName)) {
135                return getSystemDBConnection();
136            } else {
137                return DriverManager.getConnection(protocol + dbName + properties);
138            }
139        }
140    
141        /**
142         * Get a connection to derby.
143         *
144         * @param dbName
145         *            the name of the database to connect to.
146         * @param properties
147         *            the properties to pass to the connection string.
148         * @return connection
149         */
150        public static Connection getDerbyConnection(String dbName, String properties)
151                throws SQLException {
152            return getConnection(dbName, properties, PROTOCOL, DERBY_DRIVER);
153        }
154    
155        public static Connection getDerbyConnection(String dbName)
156                throws SQLException {
157            return getDerbyConnection(dbName, EMPTY_PROPS);
158        }
159    
160        /**
161         * Get a connection to the SystemDatabase.
162         *
163         * @return
164         * @throws SQLException
165         */
166        public static Connection getSystemDBConnection() throws SQLException {
167            DataSource ds = null;
168            try {
169                ds = getDataSource(SYSTEM_DB);
170                return ds.getConnection();
171            } catch (Exception e) {
172                throw new SQLException(e.getMessage());
173            }
174        }
175    
176        /**
177         * Get the datasource if dbName is == SYSTEM_DB, otherwise returns null.
178         *
179         * @param dbName
180         * @return datasource
181         */
182        public static DataSource getDataSource(String dbName) {
183            try {
184                if (SYSTEM_DATASOURCE_NAME!=null && SYSTEM_DB.equalsIgnoreCase(dbName)) {
185                    return (DataSource) KernelRegistry.getSingleKernel().invoke(
186                                    SYSTEM_DATASOURCE_NAME, "$getResource");
187                }
188            } catch (Exception e) {
189                    log.error("Problem getting datasource " + dbName, e);
190            }
191            
192            Kernel kernel = KernelRegistry.getSingleKernel();
193            ManagementHelper helper = new KernelManagementHelper(kernel);
194            ResourceAdapterModule[] modules = helper.getOutboundRAModules(helper.getDomains()[0].getServerInstances()[0], "javax.sql.DataSource");
195            for (ResourceAdapterModule module : modules) {
196                org.apache.geronimo.management.geronimo.JCAManagedConnectionFactory[] databases = helper.getOutboundFactories(module, "javax.sql.DataSource");
197                for (org.apache.geronimo.management.geronimo.JCAManagedConnectionFactory db : databases) {
198                    try {
199                        Object databaseName = db.getConfigProperty("DatabaseName");
200                        if(dbName.equalsIgnoreCase((String) databaseName)) {
201                            AbstractName tempDbName = helper.getNameFor(db);
202                            return (DataSource) KernelRegistry.getSingleKernel().invoke(
203                                    tempDbName, "$getResource");
204                        }
205                    } catch (Exception ignored) {
206                    }
207                }
208            }
209            
210            return null;
211        }
212    
213    }