You are viewing a plain text version of this content. The canonical link for it is here.
Posted to ojb-dev@db.apache.org by to...@apache.org on 2004/01/21 14:47:03 UTC

cvs commit: db-ojb/src/java/org/apache/ojb/broker/platforms TorqueDBHandling.java

tomdz       2004/01/21 05:47:03

  Added:       src/java/org/apache/ojb/broker/platforms
                        TorqueDBHandling.java
  Log:
  Added a class that allows to create/initialize a database using torque.
  
  Revision  Changes    Path
  1.1                  db-ojb/src/java/org/apache/ojb/broker/platforms/TorqueDBHandling.java
  
  Index: TorqueDBHandling.java
  ===================================================================
  package org.apache.ojb.broker.platforms;
  
  /* ====================================================================
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2001 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution,
   *    if any, must include the following acknowledgment:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowledgment may appear in the software itself,
   *    if and wherever such third-party acknowledgments normally appear.
   *
   * 4. The names "Apache" and "Apache Software Foundation" and
   *    "Apache ObjectRelationalBridge" must not be used to endorse or promote products
   *    derived from this software without prior written permission. For
   *    written permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache",
   *    "Apache ObjectRelationalBridge", nor may "Apache" appear in their name, without
   *    prior written permission of the Apache Software Foundation.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  
  import java.io.*;
  import java.util.HashMap;
  import java.util.Iterator;
  import java.util.zip.GZIPInputStream;
  import java.util.zip.GZIPOutputStream;
  
  import org.apache.ojb.broker.metadata.JdbcConnectionDescriptor;
  import org.apache.tools.ant.Project;
  import org.apache.tools.ant.taskdefs.SQLExec;
  import org.apache.tools.ant.types.FileSet;
  import org.apache.torque.task.TorqueDataModelTask;
  import org.apache.torque.task.TorqueSQLExec;
  import org.apache.torque.task.TorqueSQLTask;
  
  /**
   * Provides basic database handling (drop, create, init) via torque.
   * 
   * @author Thomas Dudziak
   */
  public class TorqueDBHandling
  {
      /** Torque db platforms */
      protected static final String TORQUE_PLATFORM_DB2        = "db2";
      protected static final String TORQUE_PLATFORM_HYPERSONIC = "hypersonic";
      protected static final String TORQUE_PLATFORM_INTERBASE  = "interbase";
      protected static final String TORQUE_PLATFORM_MSSQL      = "mssql";
      protected static final String TORQUE_PLATFORM_MYSQL      = "mysql";
      protected static final String TORQUE_PLATFORM_ORACLE     = "oracle";
      protected static final String TORQUE_PLATFORM_POSTGRESQL = "postgresql";
      protected static final String TORQUE_PLATFORM_SAPDB      = "sapdb";
      protected static final String TORQUE_PLATFORM_SYBASE     = "sybase";
  
      /** The name of the db-creation script */
      private static final String CREATION_SCRIPT_NAME = "create-db.sql";
      /** The name of the torque database mapping file */
      private static final String SQL_DB_MAP_NAME      = "sqldb.map";
      
      /** Mapping from ojb dbms to torque database setting */
      private static HashMap _dbmsToTorqueDb = new HashMap();
      
      static
      {
          _dbmsToTorqueDb.put("db2",         TORQUE_PLATFORM_DB2);
          _dbmsToTorqueDb.put("hsqldb",      TORQUE_PLATFORM_HYPERSONIC);
          _dbmsToTorqueDb.put("firebird",    TORQUE_PLATFORM_INTERBASE);
          _dbmsToTorqueDb.put("mssqlserver", TORQUE_PLATFORM_MSSQL);
          _dbmsToTorqueDb.put("mysql",       TORQUE_PLATFORM_MYSQL);
          _dbmsToTorqueDb.put("oracle",      TORQUE_PLATFORM_ORACLE);
          _dbmsToTorqueDb.put("oracle9i",    TORQUE_PLATFORM_ORACLE);
          _dbmsToTorqueDb.put("postgresql",  TORQUE_PLATFORM_POSTGRESQL);
          _dbmsToTorqueDb.put("sapdb",       TORQUE_PLATFORM_SAPDB);
          _dbmsToTorqueDb.put("sybaseasa",   TORQUE_PLATFORM_SYBASE);
          _dbmsToTorqueDb.put("sybasease",   TORQUE_PLATFORM_SYBASE);
          _dbmsToTorqueDb.put("sybase",      TORQUE_PLATFORM_SYBASE);
      }
      
      /** The jdbc connection for communicating with the db */
      private JdbcConnectionDescriptor _jcd;
      /** The target database */
      private String _targetDatabase; 
      /** The source directory */
      private String _srcDir; 
      /** The schema files (relative to the source directory) */
      private String _schemaFiles;
      /** The compressed content of the creation script */
      private byte[] _creationScript;
      /** The compressed contents of the db initialization scripts */
      private HashMap _initScripts = new HashMap();
      
      /**
       * Creates a new handling object.
       * 
       * @param jcd         The connection to use
       * @param srcDir      The source directory
       * @param schemaFiles The schema file to use (relative to the source directory)
       * @throws PlatformException If some error occurred
       */
      public TorqueDBHandling(JdbcConnectionDescriptor jcd, String srcDir, String schemaFiles) throws PlatformException
      {
          _jcd            = jcd;
          _srcDir         = srcDir;
          _schemaFiles    = schemaFiles;
          _targetDatabase = (String)_dbmsToTorqueDb.get(_jcd.getDbms().toLowerCase());
          if (_targetDatabase == null)
          {
              throw new PlatformException("Database "+_jcd.getDbms()+" is not supported by torque");
          }
      }
  
      /**
       * Returns the connection descriptor used by this handling object.
       * 
       * @return The connection descriptor
       */
      public JdbcConnectionDescriptor getConnectionDescriptor()
      {
          return _jcd;
      }
  
      /**
       * Returns the torque database platform used.
       * 
       * @return The target db platform
       */
      public String getTargetTorquePlatform()
      {
          return _targetDatabase;
      }
  
      /**
       * Creates the db-creation sql script (but does not perform it).
       * 
       * @throws PlatformException If some error occurred
       */
      public void createCreationScript() throws PlatformException
      {
          Project             project    = new Project();
          TorqueDataModelTask modelTask  = new TorqueDataModelTask();
          File                scriptFile = null;
          
          _creationScript = null;
          try
          {
              File tmpDir = getTmpDir();
  
              scriptFile = new File(tmpDir, CREATION_SCRIPT_NAME);
  
              project.setBasedir(tmpDir.getAbsolutePath());
  
              // populating with defaults
              modelTask.setProject(project);
              modelTask.setUseClasspath(true);
              modelTask.setControlTemplate("sql/db-init/Control.vm");
              modelTask.setOutputDirectory(tmpDir);
              modelTask.setOutputFile(CREATION_SCRIPT_NAME);
              modelTask.setTargetDatabase(_targetDatabase);
  
              FileSet files = new FileSet();
              
              files.setDir(new File(_srcDir));
              files.setIncludes(_schemaFiles);
              modelTask.addFileset(files);
              modelTask.execute();
  
              _creationScript = readTextCompressed(scriptFile);
  
              scriptFile.delete();
          }
          catch (Exception ex)
          {
              // clean-up
              if ((scriptFile != null) && scriptFile.exists())
              {
                  scriptFile.delete();
              }
              throw new PlatformException(ex);
          }
      }
      
      /**
       * Creates the database.
       * 
       * @throws PlatformException If some error occurred
       */
      public void createDB() throws PlatformException
      {
          if (_creationScript == null)
          {
              createCreationScript();
          }
  
          Project             project    = new Project();
          TorqueDataModelTask modelTask  = new TorqueDataModelTask();
          File                scriptFile = null;
          
          try
          {
              File tmpDir = getTmpDir();
  
              scriptFile = new File(tmpDir, CREATION_SCRIPT_NAME);
  
              writeCompressedText(scriptFile, _creationScript);
  
              project.setBasedir(tmpDir.getAbsolutePath());
  
              // we use the ant task 'sql' to perform the creation script
  	        SQLExec         sqlTask = new SQLExec();
  	        SQLExec.OnError onError = new SQLExec.OnError();
  	
  	        onError.setValue("continue");
  	        sqlTask.setProject(project);
  	        sqlTask.setAutocommit(true);
  	        sqlTask.setDriver(_jcd.getDriver());
  	        sqlTask.setOnerror(onError);
  	        sqlTask.setUserid(_jcd.getUserName());
  	        sqlTask.setPassword(_jcd.getPassWord() == null ? "" : _jcd.getPassWord());
  	        sqlTask.setUrl(getDBCreationUrl());
  	        sqlTask.setSrc(scriptFile);
  	        sqlTask.execute();
  
  	        scriptFile.delete();
          }
          catch (Exception ex)
          {
              // clean-up
              if ((scriptFile != null) && scriptFile.exists())
              {
                  scriptFile.delete();
              }
              throw new PlatformException(ex);
          }
      }
  
      /**
       * Creates the initialization scripts (creation of tables etc.) but does
       * not perform them.
       * 
       * @throws PlatformException If some error occurred
       */
      public void createInitScripts() throws PlatformException
      {
          Project       project   = new Project();
          TorqueSQLTask sqlTask   = new TorqueSQLTask(); 
          File          outputDir = null;
          
          _initScripts.clear();
          try
          {
              outputDir = new File(getTmpDir(), "sql");
  
              File sqlDbMapFile = new File(outputDir, SQL_DB_MAP_NAME);
  
              outputDir.mkdir();
              sqlDbMapFile.createNewFile();
              project.setBasedir(outputDir.getAbsolutePath());
              
              // populating with defaults
              sqlTask.setProject(project);
              sqlTask.setUseClasspath(true);
              sqlTask.setBasePathToDbProps("sql/base/");
              sqlTask.setControlTemplate("sql/base/Control.vm");
              sqlTask.setOutputDirectory(outputDir);
              // we put the report in the parent directory as we don't want
              // to read it in later on
              sqlTask.setOutputFile("../report.sql.generation");
              sqlTask.setSqlDbMap(SQL_DB_MAP_NAME);
              sqlTask.setTargetDatabase(_targetDatabase);
  
              FileSet files = new FileSet();
              
              files.setDir(new File(_srcDir));
              files.setIncludes(_schemaFiles);
              sqlTask.addFileset(files);
              sqlTask.execute();
  
              readTextsCompressed(outputDir, _initScripts);
              deleteDir(outputDir);
          }
          catch (Exception ex)
          {
              // clean-up
              if (outputDir != null)
              {
                  deleteDir(outputDir);
              }
              throw new PlatformException(ex);
          }
      }
  
      /**
       * Creates the tables according to the schema files.
       * 
       * @throws PlatformException If some error occurred
       */
      public void createTables() throws PlatformException
      {
          if (_initScripts.isEmpty())
          {
              createInitScripts();
          }
  
          Project       project   = new Project();
          TorqueSQLTask sqlTask   = new TorqueSQLTask(); 
          File          outputDir = null;
          
          try
          {
              outputDir = new File(getTmpDir(), "sql");
  
              outputDir.mkdir();
              writeCompressedTexts(outputDir, _initScripts);
  
              project.setBasedir(outputDir.getAbsolutePath());
  
              // executing the generated sql, but this time with a torque task 
              TorqueSQLExec         sqlExec = new TorqueSQLExec();
              TorqueSQLExec.OnError onError = new TorqueSQLExec.OnError();
  
              sqlExec.setProject(project);
              onError.setValue("continue");
              sqlExec.setAutocommit(true);
              sqlExec.setDriver(_jcd.getDriver());
              sqlExec.setOnerror(onError);
              sqlExec.setUserid(_jcd.getUserName());
              sqlExec.setPassword(_jcd.getPassWord() == null ? "" : _jcd.getPassWord());
              sqlExec.setUrl(getDBManipulationUrl());
              sqlExec.setSrcDir(outputDir.getAbsolutePath());
              sqlExec.setSqlDbMap(SQL_DB_MAP_NAME);
              sqlExec.execute();
              
              deleteDir(outputDir);
          }
          catch (Exception ex)
          {
              // clean-up
              if (outputDir != null)
              {
                  deleteDir(outputDir);
              }
              throw new PlatformException(ex);
          }
      }
  
      /**
       * Template-and-Hook method for generating the url required by the jdbc driver
       * to allow for creating a database (as opposed to accessing an already-existing
       * database).
       * 
       * @param jcd The jdbc connection descriptor
       */
      protected String getDBCreationUrl()
      {
          JdbcConnectionDescriptor jcd = getConnectionDescriptor();
  
          // currently I only know about specifics for mysql
          if (TORQUE_PLATFORM_MYSQL.equals(getTargetTorquePlatform()))
          {
              // we have to remove the db name as the jdbc driver would try to connect to
              // a non-existing db
              // a mysql db-alias has this form: [host&port]/[dbname]?[options]
              String dbAliasPrefix = jcd.getDbAlias();
              String dbAliasSuffix = "";
              int    questionPos   = dbAliasPrefix.indexOf('?');
  
              if (questionPos > 0)
              {
                  dbAliasSuffix = dbAliasPrefix.substring(questionPos);
                  dbAliasPrefix = dbAliasPrefix.substring(0, questionPos);
              }
  
              int slashPos = dbAliasPrefix.lastIndexOf('/');
  
              if (slashPos > 0)
              {
                  // it is important that the slash at the end is present
                  dbAliasPrefix = dbAliasPrefix.substring(0, slashPos + 1);
              }
              return jcd.getProtocol()+":"+jcd.getSubProtocol()+":"+dbAliasPrefix+dbAliasSuffix;
          }
          else
          {
              return jcd.getProtocol()+":"+jcd.getSubProtocol()+":"+jcd.getDbAlias();
          }
      }
  
      /**
       * Template-and-Hook method for generating the url required by the jdbc driver
       * to allow for modifying an existing database.
       * 
       * @param jcd The jdbc connection descriptor
       */
      protected String getDBManipulationUrl()
      {
          JdbcConnectionDescriptor jcd = getConnectionDescriptor();
  
          return jcd.getProtocol()+":"+jcd.getSubProtocol()+":"+jcd.getDbAlias();
      }
  
      /**
       * Reads the given text file and compressed its content.
       * 
       * @param file The file
       * @return A byte array containing the GZIP-compressed content of the file
       * @throws IOException If an error ocurred
       */
      private byte[] readTextCompressed(File file) throws IOException
      {
          ByteArrayOutputStream bao    = new ByteArrayOutputStream();
          GZIPOutputStream      gos    = new GZIPOutputStream(bao);
          OutputStreamWriter    output = new OutputStreamWriter(gos);
          BufferedReader        input  = new BufferedReader(new FileReader(file));
          String                line;
  
          while ((line = input.readLine()) != null)
          {
              output.write(line);
              output.write('\n');
          }
          input.close();
          output.close();
          gos.close();
          bao.close();
          return bao.toByteArray();
      }
  
      /**
       * Reads the text files in the given directory and puts their content
       * in the given map after compressing it. Note that this method does not
       * traverse recursivly into sub-directories.
       * 
       * @param dir     The directory to process
       * @param results Map that will receive the contents (indexed by the relative filenames)
       * @throws IOException If an error ocurred
       */
      private void readTextsCompressed(File dir, HashMap results) throws IOException
      {
          if (dir.exists() && dir.isDirectory())
          {
              File[] files = dir.listFiles();
  
              for (int idx = 0; idx < files.length; idx++)
              {
                  if (files[idx].isDirectory())
                  {
                      continue;
                  }
                  results.put(files[idx].getName(), readTextCompressed(files[idx]));
              }
          }
      }
  
      /**
       * Uncompresses the given textual content and writes it to the given file.
       * 
       * @param file              The file to write to
       * @param compressedContent The content
       * @throws IOException If an error occurred
       */
      private void writeCompressedText(File file, byte[] compressedContent) throws IOException
      {
          ByteArrayInputStream bais   = new ByteArrayInputStream(compressedContent);
          GZIPInputStream      gis    = new GZIPInputStream(bais);
          BufferedReader       input  = new BufferedReader(new InputStreamReader(gis));
          BufferedWriter       output = new BufferedWriter(new FileWriter(file));
          String               line;
  
          while ((line = input.readLine()) != null)
          {
              output.write(line);
              output.write('\n');
          }
          input.close();
          gis.close();
          bais.close();
          output.close();
      }
      
      /**
       * Uncompresses the textual contents in the given map and and writes them to the files
       * denoted by the keys of the map.
       * 
       * @param dir      The base directory into which the files will be written 
       * @param contents The map containing the contents indexed by the filename
       * @throws IOException If an error occurred
       */
      private void writeCompressedTexts(File dir, HashMap contents) throws IOException
      {
          String filename;
  
          for (Iterator nameIt = contents.keySet().iterator(); nameIt.hasNext();)
          {
              filename = (String)nameIt.next();
              writeCompressedText(new File(dir, filename), (byte[])contents.get(filename));
          }
      }
      
      /**
       * Returns the temporary directory used by java.
       * 
       * @return The temporary directory
       * @throws IOException If an io error occurred
       */
      private File getTmpDir() throws IOException
      {
          File   dummy  = File.createTempFile("dummy", ".log");
          String tmpDir = dummy.getPath().substring(0, dummy.getPath().lastIndexOf(File.separatorChar));
  
          if ((tmpDir == null) || (tmpDir.length() == 0))
          {
              tmpDir = ".";
          }
          dummy.delete();
          return new File(tmpDir);
      }
  
      /**
       * Little helper function that recursivly deletes a directory.
       * 
       * @param dir The directory
       */
      private void deleteDir(File dir)
      {
          if (dir.exists() && dir.isDirectory())
          {
              File[] files = dir.listFiles();
  
              for (int idx = 0; idx < files.length; idx++)
              {
                  if (!files[idx].exists())
                  {
                      continue;
                  }
                  if (files[idx].isDirectory())
                  {
                      deleteDir(files[idx]);
                  }
                  else
                  {
                      files[idx].delete();
                  }
              }
              dir.delete();
          }
      }
  }
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: ojb-dev-unsubscribe@db.apache.org
For additional commands, e-mail: ojb-dev-help@db.apache.org


Re: cvs commit: db-ojb/src/java/org/apache/ojb/broker/platforms TorqueDBHandling.java

Posted by Thomas Dudziak <to...@first.gmd.de>.
On Wed, 21 Jan 2004, Martin Poeschl wrote:

> the torque generator can create repository.xml files and a simple model 
> for ojb ...
> another idea is to generate a model with the same api as the model for 
> torque but based on ojb to make the migration process easier ..
> 
> i have some ideas .. but no time to implement it :-(

So the classes in ...metadata.torque are related to the ojb-target stuff
in torque ? Then we could drop them in the ojb source tree ?
Perhaps it would be useful if you post your ideas about the
ojb-generator to the 1.1 ideas page ?

Tom


---------------------------------------------------------------------
To unsubscribe, e-mail: ojb-dev-unsubscribe@db.apache.org
For additional commands, e-mail: ojb-dev-help@db.apache.org


Re: cvs commit: db-ojb/src/java/org/apache/ojb/broker/platforms TorqueDBHandling.java

Posted by Martin Poeschl <mp...@marmot.at>.
Thomas Dudziak wrote:

>On Wed, 21 Jan 2004, Armin Waibel wrote:
>
>  
>
>>Hi Tom,
>>
>>there is also some torque stuff in
>>src/java/org/apache/ojb/broker/metadata/torque
>>
>>Don't now if we need this classes any longer ;-)
>>    
>>
>
>I've seen them but didn't know what they are for. Perhaps Thomas knows ...
>BTW there are also OJB-related classes in torque, presumably for
>generating ojb-code from torque schemas. Perhaps they are related ?
>  
>

the torque generator can create repository.xml files and a simple model 
for ojb ...
another idea is to generate a model with the same api as the model for 
torque but based on ojb to make the migration process easier ..

i have some ideas .. but no time to implement it :-(

>>Do you think we can summarize all these classes in a ...torque package?
>>    
>>
>
>The TorqueDBHandling class would be the only class using Torque - at least
>for db creation/initialization - so I don't know whether a torque
>subpackage is useful (and I tried to minimize the dependencies by calling
>the ant tasks rather than using torque classes directly) ?
>  
>
+1

martin

>Tom
>
>
>---------------------------------------------------------------------
>To unsubscribe, e-mail: ojb-dev-unsubscribe@db.apache.org
>For additional commands, e-mail: ojb-dev-help@db.apache.org
>
>
>
>  
>


---------------------------------------------------------------------
To unsubscribe, e-mail: ojb-dev-unsubscribe@db.apache.org
For additional commands, e-mail: ojb-dev-help@db.apache.org


Re: cvs commit: db-ojb/src/java/org/apache/ojb/broker/platforms TorqueDBHandling.java

Posted by Thomas Dudziak <to...@first.gmd.de>.
On Wed, 21 Jan 2004, Armin Waibel wrote:

> Hi Tom,
> 
> there is also some torque stuff in
> src/java/org/apache/ojb/broker/metadata/torque
> 
> Don't now if we need this classes any longer ;-)

I've seen them but didn't know what they are for. Perhaps Thomas knows ...
BTW there are also OJB-related classes in torque, presumably for
generating ojb-code from torque schemas. Perhaps they are related ?

> Do you think we can summarize all these classes in a ...torque package?

The TorqueDBHandling class would be the only class using Torque - at least
for db creation/initialization - so I don't know whether a torque
subpackage is useful (and I tried to minimize the dependencies by calling
the ant tasks rather than using torque classes directly) ?

Tom


---------------------------------------------------------------------
To unsubscribe, e-mail: ojb-dev-unsubscribe@db.apache.org
For additional commands, e-mail: ojb-dev-help@db.apache.org


Re: cvs commit: db-ojb/src/java/org/apache/ojb/broker/platforms TorqueDBHandling.java

Posted by Armin Waibel <ar...@code-au-lait.de>.
Hi Tom,

there is also some torque stuff in
src/java/org/apache/ojb/broker/metadata/torque

Don't now if we need this classes any longer ;-)

Do you think we can summarize all these classes in a ...torque package?

regards,
Armin

tomdz@apache.org wrote:

> tomdz       2004/01/21 05:47:03
> 
>   Added:       src/java/org/apache/ojb/broker/platforms
>                         TorqueDBHandling.java
>   Log:
>   Added a class that allows to create/initialize a database using torque.
>   
>   Revision  Changes    Path
>   1.1                  db-ojb/src/java/org/apache/ojb/broker/platforms/TorqueDBHandling.java
>   
>   Index: TorqueDBHandling.java
>   ===================================================================
>   package org.apache.ojb.broker.platforms;
>   
>   /* ====================================================================
>    * The Apache Software License, Version 1.1
>    *
>    * Copyright (c) 2001 The Apache Software Foundation.  All rights
>    * reserved.
>    *
>    * Redistribution and use in source and binary forms, with or without
>    * modification, are permitted provided that the following conditions
>    * are met:
>    *
>    * 1. Redistributions of source code must retain the above copyright
>    *    notice, this list of conditions and the following disclaimer.
>    *
>    * 2. Redistributions in binary form must reproduce the above copyright
>    *    notice, this list of conditions and the following disclaimer in
>    *    the documentation and/or other materials provided with the
>    *    distribution.
>    *
>    * 3. The end-user documentation included with the redistribution,
>    *    if any, must include the following acknowledgment:
>    *       "This product includes software developed by the
>    *        Apache Software Foundation (http://www.apache.org/)."
>    *    Alternately, this acknowledgment may appear in the software itself,
>    *    if and wherever such third-party acknowledgments normally appear.
>    *
>    * 4. The names "Apache" and "Apache Software Foundation" and
>    *    "Apache ObjectRelationalBridge" must not be used to endorse or promote products
>    *    derived from this software without prior written permission. For
>    *    written permission, please contact apache@apache.org.
>    *
>    * 5. Products derived from this software may not be called "Apache",
>    *    "Apache ObjectRelationalBridge", nor may "Apache" appear in their name, without
>    *    prior written permission of the Apache Software Foundation.
>    *
>    * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
>    * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
>    * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
>    * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
>    * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
>    * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
>    * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
>    * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
>    * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
>    * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
>    * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
>    * SUCH DAMAGE.
>    * ====================================================================
>    *
>    * This software consists of voluntary contributions made by many
>    * individuals on behalf of the Apache Software Foundation.  For more
>    * information on the Apache Software Foundation, please see
>    * <http://www.apache.org/>.
>    */
>   
>   import java.io.*;
>   import java.util.HashMap;
>   import java.util.Iterator;
>   import java.util.zip.GZIPInputStream;
>   import java.util.zip.GZIPOutputStream;
>   
>   import org.apache.ojb.broker.metadata.JdbcConnectionDescriptor;
>   import org.apache.tools.ant.Project;
>   import org.apache.tools.ant.taskdefs.SQLExec;
>   import org.apache.tools.ant.types.FileSet;
>   import org.apache.torque.task.TorqueDataModelTask;
>   import org.apache.torque.task.TorqueSQLExec;
>   import org.apache.torque.task.TorqueSQLTask;
>   
>   /**
>    * Provides basic database handling (drop, create, init) via torque.
>    * 
>    * @author Thomas Dudziak
>    */
>   public class TorqueDBHandling
>   {
>       /** Torque db platforms */
>       protected static final String TORQUE_PLATFORM_DB2        = "db2";
>       protected static final String TORQUE_PLATFORM_HYPERSONIC = "hypersonic";
>       protected static final String TORQUE_PLATFORM_INTERBASE  = "interbase";
>       protected static final String TORQUE_PLATFORM_MSSQL      = "mssql";
>       protected static final String TORQUE_PLATFORM_MYSQL      = "mysql";
>       protected static final String TORQUE_PLATFORM_ORACLE     = "oracle";
>       protected static final String TORQUE_PLATFORM_POSTGRESQL = "postgresql";
>       protected static final String TORQUE_PLATFORM_SAPDB      = "sapdb";
>       protected static final String TORQUE_PLATFORM_SYBASE     = "sybase";
>   
>       /** The name of the db-creation script */
>       private static final String CREATION_SCRIPT_NAME = "create-db.sql";
>       /** The name of the torque database mapping file */
>       private static final String SQL_DB_MAP_NAME      = "sqldb.map";
>       
>       /** Mapping from ojb dbms to torque database setting */
>       private static HashMap _dbmsToTorqueDb = new HashMap();
>       
>       static
>       {
>           _dbmsToTorqueDb.put("db2",         TORQUE_PLATFORM_DB2);
>           _dbmsToTorqueDb.put("hsqldb",      TORQUE_PLATFORM_HYPERSONIC);
>           _dbmsToTorqueDb.put("firebird",    TORQUE_PLATFORM_INTERBASE);
>           _dbmsToTorqueDb.put("mssqlserver", TORQUE_PLATFORM_MSSQL);
>           _dbmsToTorqueDb.put("mysql",       TORQUE_PLATFORM_MYSQL);
>           _dbmsToTorqueDb.put("oracle",      TORQUE_PLATFORM_ORACLE);
>           _dbmsToTorqueDb.put("oracle9i",    TORQUE_PLATFORM_ORACLE);
>           _dbmsToTorqueDb.put("postgresql",  TORQUE_PLATFORM_POSTGRESQL);
>           _dbmsToTorqueDb.put("sapdb",       TORQUE_PLATFORM_SAPDB);
>           _dbmsToTorqueDb.put("sybaseasa",   TORQUE_PLATFORM_SYBASE);
>           _dbmsToTorqueDb.put("sybasease",   TORQUE_PLATFORM_SYBASE);
>           _dbmsToTorqueDb.put("sybase",      TORQUE_PLATFORM_SYBASE);
>       }
>       
>       /** The jdbc connection for communicating with the db */
>       private JdbcConnectionDescriptor _jcd;
>       /** The target database */
>       private String _targetDatabase; 
>       /** The source directory */
>       private String _srcDir; 
>       /** The schema files (relative to the source directory) */
>       private String _schemaFiles;
>       /** The compressed content of the creation script */
>       private byte[] _creationScript;
>       /** The compressed contents of the db initialization scripts */
>       private HashMap _initScripts = new HashMap();
>       
>       /**
>        * Creates a new handling object.
>        * 
>        * @param jcd         The connection to use
>        * @param srcDir      The source directory
>        * @param schemaFiles The schema file to use (relative to the source directory)
>        * @throws PlatformException If some error occurred
>        */
>       public TorqueDBHandling(JdbcConnectionDescriptor jcd, String srcDir, String schemaFiles) throws PlatformException
>       {
>           _jcd            = jcd;
>           _srcDir         = srcDir;
>           _schemaFiles    = schemaFiles;
>           _targetDatabase = (String)_dbmsToTorqueDb.get(_jcd.getDbms().toLowerCase());
>           if (_targetDatabase == null)
>           {
>               throw new PlatformException("Database "+_jcd.getDbms()+" is not supported by torque");
>           }
>       }
>   
>       /**
>        * Returns the connection descriptor used by this handling object.
>        * 
>        * @return The connection descriptor
>        */
>       public JdbcConnectionDescriptor getConnectionDescriptor()
>       {
>           return _jcd;
>       }
>   
>       /**
>        * Returns the torque database platform used.
>        * 
>        * @return The target db platform
>        */
>       public String getTargetTorquePlatform()
>       {
>           return _targetDatabase;
>       }
>   
>       /**
>        * Creates the db-creation sql script (but does not perform it).
>        * 
>        * @throws PlatformException If some error occurred
>        */
>       public void createCreationScript() throws PlatformException
>       {
>           Project             project    = new Project();
>           TorqueDataModelTask modelTask  = new TorqueDataModelTask();
>           File                scriptFile = null;
>           
>           _creationScript = null;
>           try
>           {
>               File tmpDir = getTmpDir();
>   
>               scriptFile = new File(tmpDir, CREATION_SCRIPT_NAME);
>   
>               project.setBasedir(tmpDir.getAbsolutePath());
>   
>               // populating with defaults
>               modelTask.setProject(project);
>               modelTask.setUseClasspath(true);
>               modelTask.setControlTemplate("sql/db-init/Control.vm");
>               modelTask.setOutputDirectory(tmpDir);
>               modelTask.setOutputFile(CREATION_SCRIPT_NAME);
>               modelTask.setTargetDatabase(_targetDatabase);
>   
>               FileSet files = new FileSet();
>               
>               files.setDir(new File(_srcDir));
>               files.setIncludes(_schemaFiles);
>               modelTask.addFileset(files);
>               modelTask.execute();
>   
>               _creationScript = readTextCompressed(scriptFile);
>   
>               scriptFile.delete();
>           }
>           catch (Exception ex)
>           {
>               // clean-up
>               if ((scriptFile != null) && scriptFile.exists())
>               {
>                   scriptFile.delete();
>               }
>               throw new PlatformException(ex);
>           }
>       }
>       
>       /**
>        * Creates the database.
>        * 
>        * @throws PlatformException If some error occurred
>        */
>       public void createDB() throws PlatformException
>       {
>           if (_creationScript == null)
>           {
>               createCreationScript();
>           }
>   
>           Project             project    = new Project();
>           TorqueDataModelTask modelTask  = new TorqueDataModelTask();
>           File                scriptFile = null;
>           
>           try
>           {
>               File tmpDir = getTmpDir();
>   
>               scriptFile = new File(tmpDir, CREATION_SCRIPT_NAME);
>   
>               writeCompressedText(scriptFile, _creationScript);
>   
>               project.setBasedir(tmpDir.getAbsolutePath());
>   
>               // we use the ant task 'sql' to perform the creation script
>   	        SQLExec         sqlTask = new SQLExec();
>   	        SQLExec.OnError onError = new SQLExec.OnError();
>   	
>   	        onError.setValue("continue");
>   	        sqlTask.setProject(project);
>   	        sqlTask.setAutocommit(true);
>   	        sqlTask.setDriver(_jcd.getDriver());
>   	        sqlTask.setOnerror(onError);
>   	        sqlTask.setUserid(_jcd.getUserName());
>   	        sqlTask.setPassword(_jcd.getPassWord() == null ? "" : _jcd.getPassWord());
>   	        sqlTask.setUrl(getDBCreationUrl());
>   	        sqlTask.setSrc(scriptFile);
>   	        sqlTask.execute();
>   
>   	        scriptFile.delete();
>           }
>           catch (Exception ex)
>           {
>               // clean-up
>               if ((scriptFile != null) && scriptFile.exists())
>               {
>                   scriptFile.delete();
>               }
>               throw new PlatformException(ex);
>           }
>       }
>   
>       /**
>        * Creates the initialization scripts (creation of tables etc.) but does
>        * not perform them.
>        * 
>        * @throws PlatformException If some error occurred
>        */
>       public void createInitScripts() throws PlatformException
>       {
>           Project       project   = new Project();
>           TorqueSQLTask sqlTask   = new TorqueSQLTask(); 
>           File          outputDir = null;
>           
>           _initScripts.clear();
>           try
>           {
>               outputDir = new File(getTmpDir(), "sql");
>   
>               File sqlDbMapFile = new File(outputDir, SQL_DB_MAP_NAME);
>   
>               outputDir.mkdir();
>               sqlDbMapFile.createNewFile();
>               project.setBasedir(outputDir.getAbsolutePath());
>               
>               // populating with defaults
>               sqlTask.setProject(project);
>               sqlTask.setUseClasspath(true);
>               sqlTask.setBasePathToDbProps("sql/base/");
>               sqlTask.setControlTemplate("sql/base/Control.vm");
>               sqlTask.setOutputDirectory(outputDir);
>               // we put the report in the parent directory as we don't want
>               // to read it in later on
>               sqlTask.setOutputFile("../report.sql.generation");
>               sqlTask.setSqlDbMap(SQL_DB_MAP_NAME);
>               sqlTask.setTargetDatabase(_targetDatabase);
>   
>               FileSet files = new FileSet();
>               
>               files.setDir(new File(_srcDir));
>               files.setIncludes(_schemaFiles);
>               sqlTask.addFileset(files);
>               sqlTask.execute();
>   
>               readTextsCompressed(outputDir, _initScripts);
>               deleteDir(outputDir);
>           }
>           catch (Exception ex)
>           {
>               // clean-up
>               if (outputDir != null)
>               {
>                   deleteDir(outputDir);
>               }
>               throw new PlatformException(ex);
>           }
>       }
>   
>       /**
>        * Creates the tables according to the schema files.
>        * 
>        * @throws PlatformException If some error occurred
>        */
>       public void createTables() throws PlatformException
>       {
>           if (_initScripts.isEmpty())
>           {
>               createInitScripts();
>           }
>   
>           Project       project   = new Project();
>           TorqueSQLTask sqlTask   = new TorqueSQLTask(); 
>           File          outputDir = null;
>           
>           try
>           {
>               outputDir = new File(getTmpDir(), "sql");
>   
>               outputDir.mkdir();
>               writeCompressedTexts(outputDir, _initScripts);
>   
>               project.setBasedir(outputDir.getAbsolutePath());
>   
>               // executing the generated sql, but this time with a torque task 
>               TorqueSQLExec         sqlExec = new TorqueSQLExec();
>               TorqueSQLExec.OnError onError = new TorqueSQLExec.OnError();
>   
>               sqlExec.setProject(project);
>               onError.setValue("continue");
>               sqlExec.setAutocommit(true);
>               sqlExec.setDriver(_jcd.getDriver());
>               sqlExec.setOnerror(onError);
>               sqlExec.setUserid(_jcd.getUserName());
>               sqlExec.setPassword(_jcd.getPassWord() == null ? "" : _jcd.getPassWord());
>               sqlExec.setUrl(getDBManipulationUrl());
>               sqlExec.setSrcDir(outputDir.getAbsolutePath());
>               sqlExec.setSqlDbMap(SQL_DB_MAP_NAME);
>               sqlExec.execute();
>               
>               deleteDir(outputDir);
>           }
>           catch (Exception ex)
>           {
>               // clean-up
>               if (outputDir != null)
>               {
>                   deleteDir(outputDir);
>               }
>               throw new PlatformException(ex);
>           }
>       }
>   
>       /**
>        * Template-and-Hook method for generating the url required by the jdbc driver
>        * to allow for creating a database (as opposed to accessing an already-existing
>        * database).
>        * 
>        * @param jcd The jdbc connection descriptor
>        */
>       protected String getDBCreationUrl()
>       {
>           JdbcConnectionDescriptor jcd = getConnectionDescriptor();
>   
>           // currently I only know about specifics for mysql
>           if (TORQUE_PLATFORM_MYSQL.equals(getTargetTorquePlatform()))
>           {
>               // we have to remove the db name as the jdbc driver would try to connect to
>               // a non-existing db
>               // a mysql db-alias has this form: [host&port]/[dbname]?[options]
>               String dbAliasPrefix = jcd.getDbAlias();
>               String dbAliasSuffix = "";
>               int    questionPos   = dbAliasPrefix.indexOf('?');
>   
>               if (questionPos > 0)
>               {
>                   dbAliasSuffix = dbAliasPrefix.substring(questionPos);
>                   dbAliasPrefix = dbAliasPrefix.substring(0, questionPos);
>               }
>   
>               int slashPos = dbAliasPrefix.lastIndexOf('/');
>   
>               if (slashPos > 0)
>               {
>                   // it is important that the slash at the end is present
>                   dbAliasPrefix = dbAliasPrefix.substring(0, slashPos + 1);
>               }
>               return jcd.getProtocol()+":"+jcd.getSubProtocol()+":"+dbAliasPrefix+dbAliasSuffix;
>           }
>           else
>           {
>               return jcd.getProtocol()+":"+jcd.getSubProtocol()+":"+jcd.getDbAlias();
>           }
>       }
>   
>       /**
>        * Template-and-Hook method for generating the url required by the jdbc driver
>        * to allow for modifying an existing database.
>        * 
>        * @param jcd The jdbc connection descriptor
>        */
>       protected String getDBManipulationUrl()
>       {
>           JdbcConnectionDescriptor jcd = getConnectionDescriptor();
>   
>           return jcd.getProtocol()+":"+jcd.getSubProtocol()+":"+jcd.getDbAlias();
>       }
>   
>       /**
>        * Reads the given text file and compressed its content.
>        * 
>        * @param file The file
>        * @return A byte array containing the GZIP-compressed content of the file
>        * @throws IOException If an error ocurred
>        */
>       private byte[] readTextCompressed(File file) throws IOException
>       {
>           ByteArrayOutputStream bao    = new ByteArrayOutputStream();
>           GZIPOutputStream      gos    = new GZIPOutputStream(bao);
>           OutputStreamWriter    output = new OutputStreamWriter(gos);
>           BufferedReader        input  = new BufferedReader(new FileReader(file));
>           String                line;
>   
>           while ((line = input.readLine()) != null)
>           {
>               output.write(line);
>               output.write('\n');
>           }
>           input.close();
>           output.close();
>           gos.close();
>           bao.close();
>           return bao.toByteArray();
>       }
>   
>       /**
>        * Reads the text files in the given directory and puts their content
>        * in the given map after compressing it. Note that this method does not
>        * traverse recursivly into sub-directories.
>        * 
>        * @param dir     The directory to process
>        * @param results Map that will receive the contents (indexed by the relative filenames)
>        * @throws IOException If an error ocurred
>        */
>       private void readTextsCompressed(File dir, HashMap results) throws IOException
>       {
>           if (dir.exists() && dir.isDirectory())
>           {
>               File[] files = dir.listFiles();
>   
>               for (int idx = 0; idx < files.length; idx++)
>               {
>                   if (files[idx].isDirectory())
>                   {
>                       continue;
>                   }
>                   results.put(files[idx].getName(), readTextCompressed(files[idx]));
>               }
>           }
>       }
>   
>       /**
>        * Uncompresses the given textual content and writes it to the given file.
>        * 
>        * @param file              The file to write to
>        * @param compressedContent The content
>        * @throws IOException If an error occurred
>        */
>       private void writeCompressedText(File file, byte[] compressedContent) throws IOException
>       {
>           ByteArrayInputStream bais   = new ByteArrayInputStream(compressedContent);
>           GZIPInputStream      gis    = new GZIPInputStream(bais);
>           BufferedReader       input  = new BufferedReader(new InputStreamReader(gis));
>           BufferedWriter       output = new BufferedWriter(new FileWriter(file));
>           String               line;
>   
>           while ((line = input.readLine()) != null)
>           {
>               output.write(line);
>               output.write('\n');
>           }
>           input.close();
>           gis.close();
>           bais.close();
>           output.close();
>       }
>       
>       /**
>        * Uncompresses the textual contents in the given map and and writes them to the files
>        * denoted by the keys of the map.
>        * 
>        * @param dir      The base directory into which the files will be written 
>        * @param contents The map containing the contents indexed by the filename
>        * @throws IOException If an error occurred
>        */
>       private void writeCompressedTexts(File dir, HashMap contents) throws IOException
>       {
>           String filename;
>   
>           for (Iterator nameIt = contents.keySet().iterator(); nameIt.hasNext();)
>           {
>               filename = (String)nameIt.next();
>               writeCompressedText(new File(dir, filename), (byte[])contents.get(filename));
>           }
>       }
>       
>       /**
>        * Returns the temporary directory used by java.
>        * 
>        * @return The temporary directory
>        * @throws IOException If an io error occurred
>        */
>       private File getTmpDir() throws IOException
>       {
>           File   dummy  = File.createTempFile("dummy", ".log");
>           String tmpDir = dummy.getPath().substring(0, dummy.getPath().lastIndexOf(File.separatorChar));
>   
>           if ((tmpDir == null) || (tmpDir.length() == 0))
>           {
>               tmpDir = ".";
>           }
>           dummy.delete();
>           return new File(tmpDir);
>       }
>   
>       /**
>        * Little helper function that recursivly deletes a directory.
>        * 
>        * @param dir The directory
>        */
>       private void deleteDir(File dir)
>       {
>           if (dir.exists() && dir.isDirectory())
>           {
>               File[] files = dir.listFiles();
>   
>               for (int idx = 0; idx < files.length; idx++)
>               {
>                   if (!files[idx].exists())
>                   {
>                       continue;
>                   }
>                   if (files[idx].isDirectory())
>                   {
>                       deleteDir(files[idx]);
>                   }
>                   else
>                   {
>                       files[idx].delete();
>                   }
>               }
>               dir.delete();
>           }
>       }
>   }
>   
>   
>   
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: ojb-dev-unsubscribe@db.apache.org
> For additional commands, e-mail: ojb-dev-help@db.apache.org
> 
> 
> 



---------------------------------------------------------------------
To unsubscribe, e-mail: ojb-dev-unsubscribe@db.apache.org
For additional commands, e-mail: ojb-dev-help@db.apache.org