Friday, May 28, 2004

Custom Ant Task to Execute SQL DDL Statements And Ignoring Certain Errors.

This Ant task executes any DDL SQL statements. The value of this task over the standard Ant SQL task is that some errors, like 'Table already exists' are ignored. The ReadWimConfiguration class simply sets the Oracle URL, username, and password. The OracleBootstrap class gets an Oracle DataSource object and provides a method to get a connection. I can post that class if needed.

package org.wwre.ant.tasks;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Task;
import org.wwre.common.ReadWimConfiguration;
import org.wwre.datastore.oracle.OracleBootstrap;

public class ExecuteDDLTask extends Task{

    /** A list with text lines that contains the query. */
    private List textLines = new ArrayList();

    public void execute() throws BuildException {
        Connection con = null;
        PreparedStatement ps = null;

        try {
            if (ReadWimConfiguration.isRead() == false) {
                throw new BuildException("Please call the readWimConfiguration task.");
            }

            OracleBootstrap.initialize();

            try {
                con = OracleBootstrap.getConnection();
                ps = con.prepareStatement(toString());
                ps.executeQuery();
            } catch (SQLException e) {
                boolean validError = false;

                if (e.getMessage().startsWith("ORA-01430: column being added already exists in table")) {
                    validError = true;
                }
                if (e.getMessage().startsWith("ORA-00955: name is already used")) {
                    validError = true;
                }
                if (validError == false) {
                    throw new BuildException(toString() + "\n" + e.getMessage());
                }
            } finally {
                // Note: The connection is not closed so that it can be reused!
            }

        } catch (Error e) {
            e.printStackTrace();
            throw new BuildException("Unhandled Error: " + e.getMessage());
        } catch (Exception e) {
            if (e.getMessage() != null && e.getMessage().equals("alreadyLogged") == true) {
                // ignore the already handled exception.
            } else {
                e.printStackTrace();
                throw new BuildException("Unhandled Exception: " + e.getMessage());
            }
        }
    }

    /**
     * Add a line of text to the query. If there are any properties, they will be replaced.
     * 
     * @param text A line of text that should be added to the query.
     */
    public void addText(String text) {
      this.textLines.add(text);
    }

    /**
     * Retrieve the query as a string and replace properties.
     * 
     * @return A string with the query.
     */
    public String toString() {
      StringBuffer query = new StringBuffer();
      for (Iterator iterator = this.textLines.iterator(); iterator.hasNext();) {
        String textLine = (String) iterator.next();
        query.append(textLine);
      }
      return getProject().replaceProperties(query.toString());
    }

}

Custom Ant Task to Throw BuildException if Specified Ant Property is Not Defined

This Ant task throws a BuildException if a specified Ant property is not defined. I use it like this:

    <target name="generateXlnServerPropertyFile">
        <checkDefinedAntProperty propertyName="classpath.delimiter"/>
        <checkDefinedAntProperty propertyName="velocity.template.directory"/>
        <checkDefinedAntProperty propertyName="xlnserver.property.file"/>
        <generateXlnServerPropertyFile .../>
    </target>
package org.wwre.ant.tasks;

import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Task;

/**
 * This class configures the XIS server for WIM use.
 *  
 */
public class CheckDefinedAntPropertyTask extends Task{

    private String propertyName = null;

    /**
     * The method executing the task.
     * 
     * @throws BuildException If srcdir or classname are null. This exception is also thrown 
     * if the variable cannot be found, The java file does not exist,
     */
    public void execute() throws BuildException {

        if (getPropertyName() == null) {
            throw new BuildException("Please set the propertyName attribute.");
        }

        String propertyValue = getProject().getProperty(getPropertyName());

        if (propertyValue == null) {
            throw new BuildException("Please define property[" + getPropertyName() + "].");
        }

    }

    /**
     * @return Returns the propertyName.
     */
    public String getPropertyName() {
        return this.propertyName;
    }

    /**
     * @param _propertyName The propertyName to set.
     */
    public void setPropertyName(String _propertyName) {
        this.propertyName = _propertyName;
    }
}

Custom Ant Task to Add Column To Oracle Database Table

This Ant task adds a column to an Oracle database table if it does not already exist. The ReadWimConfiguration class simply sets the Oracle URL, username, and password. The OracleBootstrap class gets an Oracle DataSource object and provides a method to get a connection. I can post that class if needed.

package org.wwre.ant.tasks;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import org.apache.log4j.Logger;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Task;
import org.wwre.common.ReadWimConfiguration;
import org.wwre.datastore.oracle.OracleBootstrap;

/**
 * This class adds a column to a database table. The column is only
 * added if it does not already exist.
 *  
 */
public class AddDatabaseColumnTask extends Task {

    private String          table  = null;

    private String          column = null;

    private String          format = null;

    /**
     * The method executing the task.
     */
    public void execute() throws BuildException {
        Connection con = null;
        PreparedStatement ps = null;
        ResultSet rs = null;

        try {
            if (ReadWimConfiguration.isRead() == false) {
                throw new BuildException("Please call the readWimConfiguration task.");
            }

            if (getTable() == null) {
                throw new BuildException("Please specify the table attribute.");
            }

            if (getColumn() == null) {
                throw new BuildException("Please specify the column attribute.");
            }

            String sql = "SELECT column_name FROM user_tab_columns WHERE table_name = '" + getTable() + "' AND column_name = '" + getColumn() + "'";

            OracleBootstrap.initialize();

            try {
                con = OracleBootstrap.getConnection();
                ps = con.prepareStatement(sql);
                rs = ps.executeQuery();
                if (rs.next() == false) {
                    ps = con.prepareStatement("ALTER TABLE " + getTable() + " ADD (" + getColumn() + " " + this.format + ")");
                    rs = ps.executeQuery();
                }

            } catch (SQLException e) {
                boolean validError = false;

                if (validError == false) {
                    throw new BuildException(toString() + "\n" + e.getMessage());
                }
            } finally {
                // Note: The connection is not closed so that it can be reused!
            }

        } catch (Error e) {
            e.printStackTrace();
            throw new BuildException("Unhandled Error: " + e.getMessage());
        } catch (Exception e) {
            e.printStackTrace();
            throw new BuildException("Unhandled Exception: " + e.getMessage());
        }
    }

    /**
     * @return Returns the column.
     */
    private String getColumn() {
        if (this.column == null)
            return null;
        else
            return this.column.trim().toUpperCase();
    }

    /**
     * @param _format The format to set.
     */
    public void setFormat(String _format) {
        this.format = _format;
    }

    /**
     * @return Returns the table.
     */
    private String getTable() {
        if (this.table == null)
            return null;
        else
            return this.table.trim().toUpperCase();
    }

    /**
     * @param _table The table to set.
     */
    public void setTable(String _table) {
        this.table = _table;
    }
}

Documentation Error; Sonic XIS XML Database; Setting Address Size and Cache Size should be KB not MB.

public void setAddressSpaceSize(long size) - The documentation says that size is 'the size in megabytes.' However, it really needs to be the size in kilobytes.

public void setSize(long size) - The documentation says that size is 'the size in megabytes.' However, it really needs to be the size in kilobytes.

Most of the time, you won't be dynamically changing the sizes so it's probably better to use the com.exln.dxe.defaultcachesize and com.exln.dxe.defaultassize parameters in the xlnserver.properties file. Note that these values should be in bytes!