Coverage Report - org.apache.ojb.broker.util.dbhandling.TorqueDBHandling
 
Classes in this File Line Coverage Branch Coverage Complexity
TorqueDBHandling
N/A
N/A
3.714
 
 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;
 20  
 import java.util.Iterator;
 21  
 import java.util.StringTokenizer;
 22  
 import java.util.zip.GZIPInputStream;
 23  
 import java.util.zip.GZIPOutputStream;
 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 TORQUE_PLATFORM_DB2        = "db2";
 44  
     protected static final String TORQUE_PLATFORM_HYPERSONIC = "hypersonic";
 45  
     protected static final String TORQUE_PLATFORM_INTERBASE  = "interbase";
 46  
     protected static final String TORQUE_PLATFORM_MSSQL      = "mssql";
 47  
     protected static final String TORQUE_PLATFORM_MYSQL      = "mysql";
 48  
     protected static final String TORQUE_PLATFORM_ORACLE     = "oracle";
 49  
     protected static final String TORQUE_PLATFORM_POSTGRESQL = "postgresql";
 50  
     protected static final String TORQUE_PLATFORM_SAPDB      = "sapdb";
 51  
     protected static final String TORQUE_PLATFORM_SYBASE     = "sybase";
 52  
 
 53  
     /** The name of the db-creation script */
 54  
     private static final String CREATION_SCRIPT_NAME = "create-db.sql";
 55  
     /** The name of the torque database mapping file */
 56  
     private static final String SQL_DB_MAP_NAME      = "sqldb.map";
 57  
 
 58  
     /** Mapping from ojb dbms to torque database setting */
 59  
     private static HashMap _dbmsToTorqueDb = new HashMap();
 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 _targetDatabase;
 81  
     /** The directory where we work in */
 82  
     private File _workDir;
 83  
     /** The compressed contents of the torque schemata */
 84  
     private HashMap _torqueSchemata = new HashMap();
 85  
     /** The compressed content of the creation script */
 86  
     private byte[] _creationScript;
 87  
     /** The compressed contents of the db initialization scripts */
 88  
     private HashMap _initScripts = new HashMap();
 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 targetDatabase = (String)_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 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 srcDir, String listOfFilenames) throws IOException
 147  
     {
 148  
         StringTokenizer tokenizer = new StringTokenizer(listOfFilenames, ",");
 149  
         File            dir       = new File(srcDir);
 150  
         String          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 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 writeSchemata(File dir) throws IOException
 183  
     {
 184  
         writeCompressedTexts(dir, _torqueSchemata);
 185  
 
 186  
         StringBuffer includes = new StringBuffer();
 187  
 
 188  
         for (Iterator it = _torqueSchemata.keySet().iterator(); it.hasNext();)
 189  
         {
 190  
             includes.append((String)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 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 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 ex)
 299  
         {
 300  
             // clean-up
 301  
             if ((tmpDir != null) && tmpDir.exists())
 302  
             {
 303  
                 try
 304  
                 {
 305  
                     scriptFile.delete();
 306  
                 }
 307  
                 catch (NullPointerException 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 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 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 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 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 dbAliasPrefix = jcd.getDbAlias();
 454  
             String 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 dbAliasPrefix = jcd.getDbAlias();
 477  
             String 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 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 stream) throws IOException
 543  
     {
 544  
         ByteArrayOutputStream bao    = new ByteArrayOutputStream();
 545  
         GZIPOutputStream      gos    = new GZIPOutputStream(bao);
 546  
         OutputStreamWriter    output = new OutputStreamWriter(gos);
 547  
         BufferedReader        input  = new BufferedReader(new InputStreamReader(stream));
 548  
         String                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 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      gis    = new GZIPInputStream(bais);
 600  
         BufferedReader       input  = new BufferedReader(new InputStreamReader(gis));
 601  
         BufferedWriter       output = new BufferedWriter(new FileWriter(file));
 602  
         String               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 contents) throws IOException
 624  
     {
 625  
         String filename;
 626  
 
 627  
         for (Iterator nameIt = contents.keySet().iterator(); nameIt.hasNext();)
 628  
         {
 629  
             filename = (String)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 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 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  
 }