KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > ojb > broker > util > dbhandling > TorqueDBHandling


1 package org.apache.ojb.broker.util.dbhandling;
2
3 /* Copyright 2004-2005 The Apache Software Foundation
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */

17
18 import java.io.*;
19 import java.util.HashMap JavaDoc;
20 import java.util.Iterator JavaDoc;
21 import java.util.StringTokenizer JavaDoc;
22 import java.util.zip.GZIPInputStream JavaDoc;
23 import java.util.zip.GZIPOutputStream JavaDoc;
24
25 import org.apache.ojb.broker.metadata.JdbcConnectionDescriptor;
26 import org.apache.ojb.broker.platforms.PlatformException;
27 import org.apache.ojb.broker.util.logging.LoggerFactory;
28 import org.apache.tools.ant.Project;
29 import org.apache.tools.ant.taskdefs.SQLExec;
30 import org.apache.tools.ant.types.FileSet;
31 import org.apache.torque.task.TorqueDataModelTask;
32 import org.apache.torque.task.TorqueSQLExec;
33 import org.apache.torque.task.TorqueSQLTask;
34
35 /**
36  * Provides basic database handling (drop, create, init) via torque.
37  *
38  * @author Thomas Dudziak
39  */

40 public class TorqueDBHandling implements DBHandling
41 {
42     /** Torque db platforms */
43     protected static final String JavaDoc TORQUE_PLATFORM_DB2 = "db2";
44     protected static final String JavaDoc TORQUE_PLATFORM_HYPERSONIC = "hypersonic";
45     protected static final String JavaDoc TORQUE_PLATFORM_INTERBASE = "interbase";
46     protected static final String JavaDoc TORQUE_PLATFORM_MSSQL = "mssql";
47     protected static final String JavaDoc TORQUE_PLATFORM_MYSQL = "mysql";
48     protected static final String JavaDoc TORQUE_PLATFORM_ORACLE = "oracle";
49     protected static final String JavaDoc TORQUE_PLATFORM_POSTGRESQL = "postgresql";
50     protected static final String JavaDoc TORQUE_PLATFORM_SAPDB = "sapdb";
51     protected static final String JavaDoc TORQUE_PLATFORM_SYBASE = "sybase";
52
53     /** The name of the db-creation script */
54     private static final String JavaDoc CREATION_SCRIPT_NAME = "create-db.sql";
55     /** The name of the torque database mapping file */
56     private static final String JavaDoc SQL_DB_MAP_NAME = "sqldb.map";
57
58     /** Mapping from ojb dbms to torque database setting */
59     private static HashMap JavaDoc _dbmsToTorqueDb = new HashMap JavaDoc();
60     
61     static
62     {
63         _dbmsToTorqueDb.put("db2", TORQUE_PLATFORM_DB2);
64         _dbmsToTorqueDb.put("hsqldb", TORQUE_PLATFORM_HYPERSONIC);
65         _dbmsToTorqueDb.put("firebird", TORQUE_PLATFORM_INTERBASE);
66         _dbmsToTorqueDb.put("mssqlserver", TORQUE_PLATFORM_MSSQL);
67         _dbmsToTorqueDb.put("mysql", TORQUE_PLATFORM_MYSQL);
68         _dbmsToTorqueDb.put("oracle", TORQUE_PLATFORM_ORACLE);
69         _dbmsToTorqueDb.put("oracle9i", TORQUE_PLATFORM_ORACLE);
70         _dbmsToTorqueDb.put("postgresql", TORQUE_PLATFORM_POSTGRESQL);
71         _dbmsToTorqueDb.put("sapdb", TORQUE_PLATFORM_SAPDB);
72         _dbmsToTorqueDb.put("sybaseasa", TORQUE_PLATFORM_SYBASE);
73         _dbmsToTorqueDb.put("sybasease", TORQUE_PLATFORM_SYBASE);
74         _dbmsToTorqueDb.put("sybase", TORQUE_PLATFORM_SYBASE);
75     }
76     
77     /** The jdbc connection for communicating with the db */
78     private JdbcConnectionDescriptor _jcd;
79     /** The target database */
80     private String JavaDoc _targetDatabase;
81     /** The directory where we work in */
82     private File _workDir;
83     /** The compressed contents of the torque schemata */
84     private HashMap JavaDoc _torqueSchemata = new HashMap JavaDoc();
85     /** The compressed content of the creation script */
86     private byte[] _creationScript;
87     /** The compressed contents of the db initialization scripts */
88     private HashMap JavaDoc _initScripts = new HashMap JavaDoc();
89
90     /**
91      * Creates a new handling object.
92      */

93     public TorqueDBHandling()
94     {}
95
96     /**
97      * Sets the jdbc connection to use.
98      *
99      * @param jcd The connection to use
100      * @throws PlatformException If the target database cannot be handled with torque
101      */

102     public void setConnection(JdbcConnectionDescriptor jcd) throws PlatformException
103     {
104         _jcd = jcd;
105
106         String JavaDoc targetDatabase = (String JavaDoc)_dbmsToTorqueDb.get(_jcd.getDbms().toLowerCase());
107
108         if (targetDatabase == null)
109         {
110             throw new PlatformException("Database "+_jcd.getDbms()+" is not supported by torque");
111         }
112         if (!targetDatabase.equals(_targetDatabase))
113         {
114             _targetDatabase = targetDatabase;
115             _creationScript = null;
116             _initScripts.clear();
117         }
118     }
119
120     /**
121      * Returns the connection descriptor used by this handling object.
122      *
123      * @return The connection descriptor
124      */

125     public JdbcConnectionDescriptor getConnection()
126     {
127         return _jcd;
128     }
129
130     /**
131      * Returns the torque database platform used.
132      *
133      * @return The target db platform
134      */

135     public String JavaDoc getTargetTorquePlatform()
136     {
137         return _targetDatabase;
138     }
139
140     /**
141      * Adds the input files (in our case torque schema files) to use.
142      *
143      * @param srcDir The directory containing the files
144      * @param listOfFilenames The filenames in a comma-separated list
145      */

146     public void addDBDefinitionFiles(String JavaDoc srcDir, String JavaDoc listOfFilenames) throws IOException
147     {
148         StringTokenizer JavaDoc tokenizer = new StringTokenizer JavaDoc(listOfFilenames, ",");
149         File dir = new File(srcDir);
150         String JavaDoc filename;
151         
152         while (tokenizer.hasMoreTokens())
153         {
154             filename = tokenizer.nextToken().trim();
155             if (filename.length() > 0)
156             {
157                  _torqueSchemata.put("schema"+_torqueSchemata.size()+".xml",
158                                      readTextCompressed(new File(dir, filename)));
159             }
160         }
161     }
162
163     /**
164      * Adds an input stream of a db definition (in our case of a torque schema file).
165      *
166      * @param schemaStream The input stream
167      */

168     public void addDBDefinitionFile(InputStream JavaDoc schemaStream) throws IOException
169     {
170         _torqueSchemata.put("schema"+_torqueSchemata.size()+".xml",
171                             readStreamCompressed(schemaStream));
172     }
173
174     /**
175      * Writes the torque schemata to files in the given directory and returns
176      * a comma-separated list of the filenames.
177      *
178      * @param dir The directory to write the files to
179      * @return The list of filenames
180      * @throws IOException If an error occurred
181      */

182     private String JavaDoc writeSchemata(File dir) throws IOException
183     {
184         writeCompressedTexts(dir, _torqueSchemata);
185
186         StringBuffer JavaDoc includes = new StringBuffer JavaDoc();
187
188         for (Iterator JavaDoc it = _torqueSchemata.keySet().iterator(); it.hasNext();)
189         {
190             includes.append((String JavaDoc)it.next());
191             if (it.hasNext())
192             {
193                 includes.append(",");
194             }
195         }
196         return includes.toString();
197     }
198     
199     /**
200      * Creates the db-creation sql script (but does not perform it).
201      *
202      * @throws PlatformException If some error occurred
203      */

204     public void createCreationScript() throws PlatformException
205     {
206         Project project = new Project();
207         TorqueDataModelTask modelTask = new TorqueDataModelTask();
208         File tmpDir = null;
209         File scriptFile = null;
210         
211         _creationScript = null;
212         try
213         {
214             tmpDir = new File(getWorkDir(), "schemas");
215             tmpDir.mkdir();
216
217             String JavaDoc includes = writeSchemata(tmpDir);
218             
219             scriptFile = new File(tmpDir, CREATION_SCRIPT_NAME);
220
221             project.setBasedir(tmpDir.getAbsolutePath());
222
223             // populating with defaults
224
modelTask.setProject(project);
225             modelTask.setUseClasspath(true);
226             modelTask.setControlTemplate("sql/db-init/Control.vm");
227             modelTask.setOutputDirectory(tmpDir);
228             modelTask.setOutputFile(CREATION_SCRIPT_NAME);
229             modelTask.setTargetDatabase(_targetDatabase);
230
231             FileSet files = new FileSet();
232
233             files.setDir(tmpDir);
234             files.setIncludes(includes);
235             modelTask.addFileset(files);
236             modelTask.execute();
237
238             _creationScript = readTextCompressed(scriptFile);
239
240             deleteDir(tmpDir);
241         }
242         catch (Exception JavaDoc ex)
243         {
244             // clean-up
245
if ((tmpDir != null) && tmpDir.exists())
246             {
247                 deleteDir(tmpDir);
248             }
249             throw new PlatformException(ex);
250         }
251     }
252     
253     /**
254      * Creates the database.
255      *
256      * @throws PlatformException If some error occurred
257      */

258     public void createDB() throws PlatformException
259     {
260         if (_creationScript == null)
261         {
262             createCreationScript();
263         }
264
265         Project project = new Project();
266         TorqueDataModelTask modelTask = new TorqueDataModelTask();
267         File tmpDir = null;
268         File scriptFile = null;
269         
270         try
271         {
272             tmpDir = new File(getWorkDir(), "schemas");
273             tmpDir.mkdir();
274
275             scriptFile = new File(tmpDir, CREATION_SCRIPT_NAME);
276
277             writeCompressedText(scriptFile, _creationScript);
278
279             project.setBasedir(tmpDir.getAbsolutePath());
280
281             // we use the ant task 'sql' to perform the creation script
282
SQLExec sqlTask = new SQLExec();
283             SQLExec.OnError onError = new SQLExec.OnError();
284     
285             onError.setValue("continue");
286             sqlTask.setProject(project);
287             sqlTask.setAutocommit(true);
288             sqlTask.setDriver(_jcd.getDriver());
289             sqlTask.setOnerror(onError);
290             sqlTask.setUserid(_jcd.getUserName());
291             sqlTask.setPassword(_jcd.getPassWord() == null ? "" : _jcd.getPassWord());
292             sqlTask.setUrl(getDBCreationUrl());
293             sqlTask.setSrc(scriptFile);
294             sqlTask.execute();
295
296             deleteDir(tmpDir);
297         }
298         catch (Exception JavaDoc ex)
299         {
300             // clean-up
301
if ((tmpDir != null) && tmpDir.exists())
302             {
303                 try
304                 {
305                     scriptFile.delete();
306                 }
307                 catch (NullPointerException JavaDoc e)
308                 {
309                     LoggerFactory.getLogger(this.getClass()).error("NPE While deleting scriptFile [" + scriptFile.getName() + "]", e);
310                 }
311             }
312             throw new PlatformException(ex);
313         }
314     }
315
316     /**
317      * Creates the initialization scripts (creation of tables etc.) but does
318      * not perform them.
319      *
320      * @throws PlatformException If some error occurred
321      */

322     public void createInitScripts() throws PlatformException
323     {
324         Project project = new Project();
325         TorqueSQLTask sqlTask = new TorqueSQLTask();
326         File schemaDir = null;
327         File sqlDir = null;
328         
329         _initScripts.clear();
330         try
331         {
332             File tmpDir = getWorkDir();
333
334             schemaDir = new File(tmpDir, "schemas");
335             sqlDir = new File(tmpDir, "sql");
336             schemaDir.mkdir();
337             sqlDir.mkdir();
338
339             String JavaDoc includes = writeSchemata(schemaDir);
340             File sqlDbMapFile = new File(sqlDir, SQL_DB_MAP_NAME);
341
342             sqlDbMapFile.createNewFile();
343             project.setBasedir(sqlDir.getAbsolutePath());
344             
345             // populating with defaults
346
sqlTask.setProject(project);
347             sqlTask.setUseClasspath(true);
348             sqlTask.setBasePathToDbProps("sql/base/");
349             sqlTask.setControlTemplate("sql/base/Control.vm");
350             sqlTask.setOutputDirectory(sqlDir);
351             // we put the report in the parent directory as we don't want
352
// to read it in later on
353
sqlTask.setOutputFile("../report.sql.generation");
354             sqlTask.setSqlDbMap(SQL_DB_MAP_NAME);
355             sqlTask.setTargetDatabase(_targetDatabase);
356
357             FileSet files = new FileSet();
358             
359             files.setDir(schemaDir);
360             files.setIncludes(includes);
361             sqlTask.addFileset(files);
362             sqlTask.execute();
363
364             readTextsCompressed(sqlDir, _initScripts);
365             deleteDir(schemaDir);
366             deleteDir(sqlDir);
367         }
368         catch (Exception JavaDoc ex)
369         {
370             // clean-up
371
if ((schemaDir != null) && schemaDir.exists())
372             {
373                 deleteDir(schemaDir);
374             }
375             if ((sqlDir != null) && sqlDir.exists())
376             {
377                 deleteDir(sqlDir);
378             }
379             throw new PlatformException(ex);
380         }
381     }
382
383     /**
384      * Creates the tables according to the schema files.
385      *
386      * @throws PlatformException If some error occurred
387      */

388     public void initDB() throws PlatformException
389     {
390         if (_initScripts.isEmpty())
391         {
392             createInitScripts();
393         }
394
395         Project project = new Project();
396         TorqueSQLTask sqlTask = new TorqueSQLTask();
397         File outputDir = null;
398         
399         try
400         {
401             outputDir = new File(getWorkDir(), "sql");
402
403             outputDir.mkdir();
404             writeCompressedTexts(outputDir, _initScripts);
405
406             project.setBasedir(outputDir.getAbsolutePath());
407
408             // executing the generated sql, but this time with a torque task
409
TorqueSQLExec sqlExec = new TorqueSQLExec();
410             TorqueSQLExec.OnError onError = new TorqueSQLExec.OnError();
411
412             sqlExec.setProject(project);
413             onError.setValue("continue");
414             sqlExec.setAutocommit(true);
415             sqlExec.setDriver(_jcd.getDriver());
416             sqlExec.setOnerror(onError);
417             sqlExec.setUserid(_jcd.getUserName());
418             sqlExec.setPassword(_jcd.getPassWord() == null ? "" : _jcd.getPassWord());
419             sqlExec.setUrl(getDBManipulationUrl());
420             sqlExec.setSrcDir(outputDir.getAbsolutePath());
421             sqlExec.setSqlDbMap(SQL_DB_MAP_NAME);
422             sqlExec.execute();
423             
424             deleteDir(outputDir);
425         }
426         catch (Exception JavaDoc ex)
427         {
428             // clean-up
429
if (outputDir != null)
430             {
431                 deleteDir(outputDir);
432             }
433             throw new PlatformException(ex);
434         }
435     }
436
437     /**
438      * Template-and-Hook method for generating the url required by the jdbc driver
439      * to allow for creating a database (as opposed to accessing an already-existing
440      * database).
441      *
442      */

443     protected String JavaDoc getDBCreationUrl()
444     {
445         JdbcConnectionDescriptor jcd = getConnection();
446
447         // currently I only know about specifics for mysql
448
if (TORQUE_PLATFORM_MYSQL.equals(getTargetTorquePlatform()))
449         {
450             // we have to remove the db name as the jdbc driver would try to connect to
451
// a non-existing db
452
// the db-alias has this form: [host&port]/[dbname]?[options]
453
String JavaDoc dbAliasPrefix = jcd.getDbAlias();
454             String JavaDoc dbAliasSuffix = "";
455             int questionPos = dbAliasPrefix.indexOf('?');
456
457             if (questionPos > 0)
458             {
459                 dbAliasSuffix = dbAliasPrefix.substring(questionPos);
460                 dbAliasPrefix = dbAliasPrefix.substring(0, questionPos);
461             }
462
463             int slashPos = dbAliasPrefix.lastIndexOf('/');
464
465             if (slashPos > 0)
466             {
467                 // it is important that the slash at the end is present
468
dbAliasPrefix = dbAliasPrefix.substring(0, slashPos + 1);
469             }
470             return jcd.getProtocol()+":"+jcd.getSubProtocol()+":"+dbAliasPrefix+dbAliasSuffix;
471         }
472         else if (TORQUE_PLATFORM_POSTGRESQL.equals(getTargetTorquePlatform()))
473         {
474             // we have to replace the db name with 'template1'
475
// the db-alias has this form: [host&port]/[dbname]?[options]
476
String JavaDoc dbAliasPrefix = jcd.getDbAlias();
477             String JavaDoc dbAliasSuffix = "";
478             int questionPos = dbAliasPrefix.indexOf('?');
479
480             if (questionPos > 0)
481             {
482                 dbAliasSuffix = dbAliasPrefix.substring(questionPos);
483                 dbAliasPrefix = dbAliasPrefix.substring(0, questionPos);
484             }
485
486             int slashPos = dbAliasPrefix.lastIndexOf('/');
487
488             if (slashPos > 0)
489             {
490                 // it is important that the slash at the end is present
491
dbAliasPrefix = dbAliasPrefix.substring(0, slashPos + 1);
492             }
493             else
494             {
495                 dbAliasPrefix += "/";
496             }
497             dbAliasPrefix += "template1";
498             if (dbAliasSuffix.length() > 0)
499             {
500                 dbAliasPrefix += "/";
501             }
502             return jcd.getProtocol()+":"+jcd.getSubProtocol()+":"+dbAliasPrefix+dbAliasSuffix;
503             
504         }
505         else
506         {
507             return jcd.getProtocol()+":"+jcd.getSubProtocol()+":"+jcd.getDbAlias();
508         }
509     }
510
511     /**
512      * Template-and-Hook method for generating the url required by the jdbc driver
513      * to allow for modifying an existing database.
514      *
515      */

516     protected String JavaDoc getDBManipulationUrl()
517     {
518         JdbcConnectionDescriptor jcd = getConnection();
519
520         return jcd.getProtocol()+":"+jcd.getSubProtocol()+":"+jcd.getDbAlias();
521     }
522
523     /**
524      * Reads the given text file and compressed its content.
525      *
526      * @param file The file
527      * @return A byte array containing the GZIP-compressed content of the file
528      * @throws IOException If an error ocurred
529      */

530     private byte[] readTextCompressed(File file) throws IOException
531     {
532         return readStreamCompressed(new FileInputStream(file));
533     }
534
535     /**
536      * Reads the given text stream and compressed its content.
537      *
538      * @param stream The input stream
539      * @return A byte array containing the GZIP-compressed content of the stream
540      * @throws IOException If an error ocurred
541      */

542     private byte[] readStreamCompressed(InputStream JavaDoc stream) throws IOException
543     {
544         ByteArrayOutputStream bao = new ByteArrayOutputStream();
545         GZIPOutputStream JavaDoc gos = new GZIPOutputStream JavaDoc(bao);
546         OutputStreamWriter output = new OutputStreamWriter(gos);
547         BufferedReader input = new BufferedReader(new InputStreamReader(stream));
548         String JavaDoc line;
549
550         while ((line = input.readLine()) != null)
551         {
552             output.write(line);
553             output.write('\n');
554         }
555         input.close();
556         stream.close();
557         output.close();
558         gos.close();
559         bao.close();
560         return bao.toByteArray();
561     }
562
563     /**
564      * Reads the text files in the given directory and puts their content
565      * in the given map after compressing it. Note that this method does not
566      * traverse recursivly into sub-directories.
567      *
568      * @param dir The directory to process
569      * @param results Map that will receive the contents (indexed by the relative filenames)
570      * @throws IOException If an error ocurred
571      */

572     private void readTextsCompressed(File dir, HashMap JavaDoc results) throws IOException
573     {
574         if (dir.exists() && dir.isDirectory())
575         {
576             File[] files = dir.listFiles();
577
578             for (int idx = 0; idx < files.length; idx++)
579             {
580                 if (files[idx].isDirectory())
581                 {
582                     continue;
583                 }
584                 results.put(files[idx].getName(), readTextCompressed(files[idx]));
585             }
586         }
587     }
588
589     /**
590      * Uncompresses the given textual content and writes it to the given file.
591      *
592      * @param file The file to write to
593      * @param compressedContent The content
594      * @throws IOException If an error occurred
595      */

596     private void writeCompressedText(File file, byte[] compressedContent) throws IOException
597     {
598         ByteArrayInputStream bais = new ByteArrayInputStream(compressedContent);
599         GZIPInputStream JavaDoc gis = new GZIPInputStream JavaDoc(bais);
600         BufferedReader input = new BufferedReader(new InputStreamReader(gis));
601         BufferedWriter output = new BufferedWriter(new FileWriter(file));
602         String JavaDoc line;
603
604         while ((line = input.readLine()) != null)
605         {
606             output.write(line);
607             output.write('\n');
608         }
609         input.close();
610         gis.close();
611         bais.close();
612         output.close();
613     }
614     
615     /**
616      * Uncompresses the textual contents in the given map and and writes them to the files
617      * denoted by the keys of the map.
618      *
619      * @param dir The base directory into which the files will be written
620      * @param contents The map containing the contents indexed by the filename
621      * @throws IOException If an error occurred
622      */

623     private void writeCompressedTexts(File dir, HashMap JavaDoc contents) throws IOException
624     {
625         String JavaDoc filename;
626
627         for (Iterator JavaDoc nameIt = contents.keySet().iterator(); nameIt.hasNext();)
628         {
629             filename = (String JavaDoc)nameIt.next();
630             writeCompressedText(new File(dir, filename), (byte[])contents.get(filename));
631         }
632     }
633     
634     /**
635      * Sets the working directory.
636      *
637      * @param dir The directory
638      * @throws IOException If the directory does not exist or cannot be written/read
639      */

640     public void setWorkDir(String JavaDoc dir) throws IOException
641     {
642         File workDir = new File(dir);
643
644         if (!workDir.exists() || !workDir.canWrite() || !workDir.canRead())
645         {
646             throw new IOException("Cannot access directory "+dir);
647         }
648         _workDir = workDir;
649     }
650
651     /**
652      * Returns the temporary directory used by java.
653      *
654      * @return The temporary directory
655      * @throws IOException If an io error occurred
656      */

657     private File getWorkDir() throws IOException
658     {
659         if (_workDir == null)
660         {
661             File dummy = File.createTempFile("dummy", ".log");
662             String JavaDoc workDir = dummy.getPath().substring(0, dummy.getPath().lastIndexOf(File.separatorChar));
663     
664             if ((workDir == null) || (workDir.length() == 0))
665             {
666                 workDir = ".";
667             }
668             dummy.delete();
669             _workDir = new File(workDir);
670         }
671         return _workDir;
672     }
673
674     /**
675      * Little helper function that recursivly deletes a directory.
676      *
677      * @param dir The directory
678      */

679     private void deleteDir(File dir)
680     {
681         if (dir.exists() && dir.isDirectory())
682         {
683             File[] files = dir.listFiles();
684
685             for (int idx = 0; idx < files.length; idx++)
686             {
687                 if (!files[idx].exists())
688                 {
689                     continue;
690                 }
691                 if (files[idx].isDirectory())
692                 {
693                     deleteDir(files[idx]);
694                 }
695                 else
696                 {
697                     files[idx].delete();
698                 }
699             }
700             dir.delete();
701         }
702     }
703 }
704
Popular Tags