View Javadoc

1   /*
2    * Copyright 2006 - 2012 Christina Bohk and Roland Ewald
3    *  
4    * Licensed under the Apache License, Version 2.0 (the "License"); 
5    * you may not use this file except in compliance with the License. 
6    * You may obtain a copy of the License at 
7    *  
8    *  http://www.apache.org/licenses/LICENSE-2.0
9    *  
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
13   * See the License for the specific language governing permissions and 
14   * limitations under the License. 
15   */
16  package p3j.database;
17  
18  import james.SimSystem;
19  import james.core.data.DBConnectionData;
20  
21  import java.sql.Connection;
22  import java.sql.DriverManager;
23  import java.sql.ResultSet;
24  import java.sql.SQLException;
25  import java.util.Properties;
26  import java.util.logging.Level;
27  
28  import org.hibernate.cfg.Configuration;
29  
30  import p3j.database.hibernate.P3MDatabase;
31  import p3j.gui.P3J;
32  import p3j.gui.misc.P3JConfigFile;
33  import p3j.misc.Misc;
34  import p3j.misc.gui.GUI;
35  
36  /**
37   * A factory for the database layer. Not implemented properly yet.
38   * 
39   * Created on January 11, 2007
40   * 
41   * @author Christina Bohk
42   * @author Roland Ewald
43   * 
44   */
45  public final class DatabaseFactory {
46  
47    /**
48     * The name of the index that is manually created for the 'matrices' table in
49     * case a MySQL database is used.
50     */
51    private static final String MYSQL_MATRIX_INDEX_NAME = "hash_index";
52  
53    /**
54     * This class should not be instantiated.
55     */
56    private DatabaseFactory() {
57    }
58  
59    /** Implementing singleton pattern. */
60    private static IP3MDatabase sqlDatabase;
61  
62    /** Connection data to be used. */
63    private static DBConnectionData dbConnData = Misc.DEFAULT_DB_CONN;
64  
65    /**
66     * Get database interface.
67     * 
68     * @return database interface
69     */
70    public static IP3MDatabase getDatabaseSingleton() {
71      if (sqlDatabase == null) {
72        sqlDatabase = createDatabase(P3J.getInstance().getConfigFile());
73      }
74      return sqlDatabase;
75    }
76  
77    /**
78     * Creates a new Database object.
79     * 
80     * @param configFile
81     *          the config file
82     * @return the newly created database interface object
83     */
84    public static IP3MDatabase createDatabase(P3JConfigFile configFile) {
85      P3MDatabase database = new P3MDatabase();
86      database.init(dbConnData, configFile);
87      try {
88        database.open();
89        attemptDBSpecificOptimizations(database.getConfig(), dbConnData);
90      } catch (Exception ex) {
91        SimSystem.report(ex);
92      }
93      return database;
94    }
95  
96    /**
97     * Attempt some db-specific optimizations that cannot be easily covered by
98     * (the used version of) hibernate. Establishes a JDBC connection with the
99     * driver that is also used by hibernate and executes some raw SQL statements,
100    * e.g. to create multi-column indices.
101    * 
102    * @param config
103    *          the hibernate configuration
104    * @param connData
105    *          the connection data
106    */
107   private static void attemptDBSpecificOptimizations(Configuration config,
108       DBConnectionData connData) {
109     if (config.getProperty(Misc.PREF_HIBERNATE_DIALECT_PROPERTY).equals(
110         Misc.HIBERNATE_DIALECTS.get(DatabaseType.MYSQL))) {
111       createMatrixIndex(connData);
112     }
113   }
114 
115   /**
116    * Creates an index on the matrix table of a MySQL database schema (unless it
117    * already exists). The index is defined on the id (pk) and the hash code, to
118    * make retrieving matrices with certain hash codes faster.
119    * 
120    * @param connData
121    *          the database connection data
122    */
123   private static void createMatrixIndex(DBConnectionData connData) {
124 
125     Properties connectionProps = new Properties();
126     connectionProps.put("user", connData.getUser());
127     connectionProps.put("password", connData.getPassword());
128 
129     try (Connection conn = DriverManager.getConnection(dbConnData.getUrl(),
130         connectionProps)) {
131       ResultSet rs = conn.createStatement().executeQuery(
132           "SHOW INDEX FROM matrices WHERE KEY_NAME = '"
133               + MYSQL_MATRIX_INDEX_NAME + "'");
134       if (!rs.first()) {
135         SimSystem.report(Level.INFO, "Attempting to create index '"
136             + MYSQL_MATRIX_INDEX_NAME + "'");
137         conn.createStatement()
138             .executeUpdate(
139                 "CREATE INDEX " + MYSQL_MATRIX_INDEX_NAME
140                     + " ON matrices(ID,hash)");
141         SimSystem.report(Level.INFO, "Index creation successful.");
142       }
143     } catch (SQLException e) {
144       SimSystem.report(e);
145     }
146   }
147 
148   /**
149    * Creates a new Database object, given a certain hibernate configuration
150    * file.
151    * 
152    * @param hibernateConfigFile
153    *          the hibernate config file
154    * 
155    * @return the database
156    */
157   public static IP3MDatabase createDatabase(String hibernateConfigFile) {
158     P3MDatabase.setHibernateConfigFile(hibernateConfigFile);
159     return createDatabase(P3J.getInstance().getConfigFile());
160   }
161 
162   /**
163    * Gets the DB connection data.
164    * 
165    * @return the DB connection data
166    */
167   public static DBConnectionData getDbConnData() {
168     return dbConnData;
169   }
170 
171   /**
172    * Sets the DB connection data.
173    * 
174    * @param dbConnData
175    *          the new DB connection data
176    */
177   public static void setDbConnData(DBConnectionData dbConnData) {
178     try {
179       reset();
180     } catch (Exception ex) {
181       GUI.printErrorMessage("Error closing database connection", ex);
182     }
183     DatabaseFactory.dbConnData = dbConnData;
184   }
185 
186   /**
187    * Reset.
188    */
189   public static void reset() {
190     if (sqlDatabase != null) {
191       sqlDatabase.close();
192     }
193     sqlDatabase = null;
194   }
195 
196 }