1 /*
2 * PROJECT : DAR Runtime and Tools
3 * COPYRIGHT : Copyright (C) 1999-2004 tim.stephenson@enableit.org
4 * LICENSE : GNU LESSER GENERAL PUBLIC LICENSE
5 * Version 2.1, February 1999
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21 package org.enableit.db.darrt;
22
23 import java.io.File;
24 import java.io.FileReader;
25 import java.io.FileWriter;
26 import java.io.IOException;
27 import java.util.HashMap;
28
29 import org.apache.log4j.Logger;
30 import org.enableit.db.DBException;
31 import org.enableit.db.beans.Database;
32 import org.enableit.db.beans.Provider;
33 import org.enableit.db.beans.ProviderExt;
34 import org.enableit.db.beans.Schema;
35 import org.enableit.db.beans.Table;
36 import org.exolab.castor.xml.CastorException;
37 import org.exolab.castor.xml.Unmarshaller;
38 import org.w3c.dom.Document;
39
40
41 /***
42 * Factory for DBMS table meta data.
43 *
44 * @author Tim Stephenson
45 */
46 public class MetaDataFactory extends AbstractFileHandler {
47 private static MetaDataFactory me;
48
49 /***
50 * The Log4J <code>Logger</code> doing the logging.
51 */
52 private static Logger logger = Logger.getLogger(MetaDataFactory.class);
53
54 /***
55 * CVS info ABOUT this class and its current version
56 */
57 public static final String ABOUT = "$Revision: 1.4 $";
58
59 private static HashMap databases;
60
61 // TODO Make singleton
62
63 /***
64 * Constructor preserves singleton status.
65 */
66 private MetaDataFactory() {
67 synchronized (MetaDataFactory.class) {
68 databases = new HashMap();
69 }
70 }
71
72 public static MetaDataFactory getInstance() {
73 if (me == null) {
74 synchronized (MetaDataFactory.class) {
75 me = new MetaDataFactory();
76 }
77 }
78
79 return me;
80 }
81
82 /***
83 * @param provider Information ABOUT how to obtain connection
84 * to the database.
85 * @return Table instance describing the table, never null.
86 * @throws DBException If meta data cannot be obtained.
87 */
88 public Database getMetaData(Provider provider)
89 throws DBException {
90 Database database = getMetaData(provider, false);
91
92 return database;
93 }
94
95 /***
96 * @param provider Information ABOUT how to obtain connection
97 * to the database.
98 * @param refresh Should cache be refreshed?
99 * @return Table instance describing the table, never null.
100 * @throws DBException If meta data cannot be obtained.
101 */
102 public Database getMetaData(Provider provider, boolean refresh)
103 throws DBException {
104 logger.info("METHOD_ENTRY: getMetaData, provider= "
105 + ProviderExt.toString(provider));
106
107 Database database = null;
108
109 if (refresh) {
110 databases.remove(provider);
111 }
112
113 if (databases.containsKey(provider)) {
114 database = (Database) databases.get(provider);
115 } else {
116 try {
117 SchemaExporter se = new SchemaExporter();
118
119 database = getMetaDataFromPersistentCache(se, provider, refresh);
120
121 if (database == null) {
122 // Go get fresh meta-data
123 //se.setTablePattern("TABLE, VIEW") ;
124 if (provider.getSchemaName() != null) {
125 se.setSchemaName(provider.getSchemaName());
126 }
127
128 Document doc = se.exportToFile(provider,
129 SchemaConstants.OM_SINGLE_FILE_AND_FILE_PER_TABLE);
130
131 database = (Database) Unmarshaller.unmarshal(Database.class,
132 doc);
133
134 // Add to in-memory cache
135 setMetaData(provider, database) ;
136 } else {
137 logger.warn("Found from persistent cache");
138 }
139 } catch (Exception e) {
140 logger.error(e.getMessage(), e);
141 throw new DBException(e.getMessage(), e);
142 }
143 }
144
145 logger.info("METHOD_EXIT: getMetaData");
146
147 return database;
148 }
149
150 /***
151 * @param se
152 * @return
153 */
154 private Database getMetaDataFromPersistentCache(SchemaExporter se,
155 Provider provider, boolean refresh) {
156 Database database = null;
157
158 try {
159 File dbFile = new File(getOperDir(), se.getFileName(provider));
160
161 if (refresh && dbFile.exists()) {
162 dbFile.delete();
163
164 // remove dir that holds per-table files
165 new File(dbFile.getParent(), "schema");
166 } else if (dbFile.exists()) {
167 database = Database.unmarshal(new FileReader(dbFile));
168 } else {
169 // TODO: Check if we have a file in user.dir?
170 // (if user dir is different to oper dir)
171 }
172 } catch (Exception e) {
173 logger.warn("Unable to find persistently cached schema: "
174 + e.getMessage(), e);
175 }
176
177 return database;
178 }
179
180 /***
181 * @param provider Information ABOUT how to obtain connection
182 * to the database.
183 * @param tableName Name of table whose metadata is sought.
184 * @return Table instance describing the table, never null.
185 * @throws DBException If meta data cannot be obtained.
186 */
187 public Table getMetaData(Provider provider, String tableName)
188 throws DBException {
189 logger.info("METHOD_ENTRY: getMetaData, provider= "
190 + ProviderExt.toString(provider) + "tableName=" + tableName);
191
192 File tableHome = null ;
193 Table table = null;
194
195 try {
196 if (databases.get(provider) != null) {
197 Database db = (Database) databases.get(provider) ;
198 for (int i = 0 ; i < db.getSchemaCount() ; i++) {
199 Schema schema = db.getSchema(i) ;
200 for (int j = 0 ; j < schema.getTableCount() ; j++) {
201 Table t = schema.getTable(j) ;
202 if (tableName.equals(t.getName())) {
203 table = t ;
204 break;
205 }
206 }
207 }
208 }
209
210 // TODO: replace with perisitent cache method
211 // Try for cached table file
212 if (table == null) {
213 File darrtHome = getOperDir();
214 SchemaExporter se = new SchemaExporter();
215 String tableHomeName = se.getFileName(provider) ;
216 tableHome = new File(darrtHome,
217 tableHomeName.substring(0, tableHomeName.indexOf(".xml")));
218
219 // Do we have file of this meta data in temp dir?
220 File tableFile = new File(tableHome, tableName + ".xml");
221
222 if (tableFile.exists()) {
223 table = Table.unmarshal(new FileReader(tableFile));
224 }
225 }
226 if (table == null) {
227 // Go get fresh meta-data
228 Database database = getMetaData(provider);
229
230 for (int j = 0; j < database.getSchemaCount(); j++) {
231 Schema schema = database.getSchema(j);
232
233 for (int i = 0; i < schema.getTableCount(); i++) {
234 // TODO: Disregard case of table name?
235 if (tableName.equals(schema.getTable(i).getName())) {
236 table = schema.getTable(i);
237
238 break;
239 }
240 }
241 }
242
243 if (table == null) {
244 throw new DBException("Unable to find meta data for "
245 + tableName);
246 }
247
248 // Save for next time
249 tableHome.mkdirs();
250
251 FileWriter fw = new FileWriter(new File(tableHome,
252 tableName + ".xml"));
253
254 table.marshal(fw);
255 }
256 } catch (DBException e) {
257 throw e ;
258 } catch (IOException e) {
259 logger.error(e.getMessage(), e);
260 throw new DBException(e.getMessage(), e);
261 } catch (CastorException e) {
262 logger.error(e.getMessage(), e);
263 throw new DBException(e.getMessage(), e);
264 }
265
266 logger.info("METHOD_EXIT: getMetaData");
267
268 return table;
269 }
270
271 /***
272 * Allows an external class to specify meta-data rather than forcing it to
273 * be detected from an active connection.
274 *
275 * <p><b>Implementation Note:</p>The requirement for this method comes from
276 * <code>DarHandler</code>, as it seems
277 * JDBC meta data is not available immediately. Not sure why this is since
278 * the schema creation connection has been closed.</p>
279 * @param provider
280 * @param db
281 */
282 protected void setMetaData(Provider provider, Database db) {
283 synchronized (MetaDataFactory.class) {
284 synchronized (databases) {
285 databases.put(provider, db);
286 }
287 }
288 }
289 }
This page was automatically generated by Maven