/* * RHQ Management Platform * Copyright (C) 2005-2008 Red Hat, Inc. * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation version 2 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ package org.rhq.core.db.ant.dbupgrade; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.sql.Connection; import java.sql.SQLException; import java.sql.Types; import java.util.HashMap; import java.util.Map; import mazz.i18n.Msg; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Task; import org.rhq.core.db.DatabaseType; import org.rhq.core.db.TypeMap; import org.rhq.core.db.ant.DbAntI18NFactory; import org.rhq.core.db.ant.DbAntI18NResourceKeys; /** * A task that performs an individual step to help upgrade a schema to a particular version. */ public abstract class SchemaSpecTask extends Task { private static final Msg MSG = DbAntI18NFactory.getMsg(); private Connection connection = null; private DBUpgrader upgrader = null; // each schema spec can be targeted to a specific database vendor and a specific DB version private String targetDBVendor; private String targetDBVersion; private String ignoreError; // cache all known JDBC SQL data types private static Map<String, Integer> SQL_TYPES = new HashMap<String, Integer>(); static { Field[] fields = Types.class.getDeclaredFields(); for (Field field : fields) { int mods = field.getModifiers(); if (Modifier.isPublic(mods) && Modifier.isStatic(mods) && Modifier.isFinal(mods)) { try { SQL_TYPES.put(field.getName(), new Integer(field.getInt(null))); } catch (IllegalAccessException iae) { throw new IllegalStateException(iae); } } } } /** * Sets the vendor name of the target DB where this SQL should run. Any other DB should not have this SQL executed * on it. * * @param vendor database vendor */ public void setTargetDBVendor(String vendor) { targetDBVendor = vendor; } /** * Sets the version string of the target DB where this SQL should run. Any other DB version should not have this SQL * executed on it. * * @param version database version */ public void setTargetDBVersion(String version) { targetDBVersion = version; } /** * Sets the vendor name of the target DB where this SQL should run. Any other DB should not have this SQL executed * on it. * * @return vendor string */ public String getTargetDBVendor() { return targetDBVendor; } /** * Gets the version string of the target DB where this SQL should run. Any other DB version should not have this SQL * executed on it. * * @return version string */ public String getTargetDBVersion() { return targetDBVersion; } public String getIgnoreError() { return ignoreError; } public void setIgnoreError(String ignoreError) { this.ignoreError = ignoreError; } public boolean isIgnoreError() { return new Boolean(this.ignoreError); } /** * Returns <code>true</code> if this task's database is targeted for this schema spec. Note that if * {@link #getTargetDBVendor()} is not specified, then any specified {@link #getTargetDBVersion()} will cause a * build exception to occur. You cannot specific a version string without indicating which vendor's database you are * talking about. * * @return <code>true</code> if this schema spec task should run; <code>false</code> if this task's database is not * targeted and thus this task should not execute * * @see #getTargetDBVendor() * @see #getTargetDBVersion() */ public boolean isDBTargeted() { if ((targetDBVersion != null) && (targetDBVendor == null)) { throw new BuildException(MSG.getMsg(DbAntI18NResourceKeys.SCHEMA_SPEC_TASK_TARGET_VERSION_WITHOUT_VENDOR, getTaskName(), targetDBVersion)); } if (targetDBVendor != null) { DatabaseType db_type = getDatabaseType(); if (!targetDBVendor.equalsIgnoreCase(db_type.getVendor())) { log(MSG.getMsg(DbAntI18NResourceKeys.SCHEMA_SPEC_TASK_VENDOR_MISMATCH, targetDBVendor, db_type .getVendor())); return false; } if ((targetDBVersion != null) && !targetDBVersion.equalsIgnoreCase(db_type.getVersion())) { log(MSG.getMsg(DbAntI18NResourceKeys.SCHEMA_SPEC_TASK_VERSION_MISMATCH, targetDBVendor, targetDBVersion, db_type.getVersion())); return false; } } return true; } /** * Initializes this task with a database connection and a {@link DBUpgrader} object. * * @param db_conn * @param db_upgrader */ public void initialize(Connection db_conn, DBUpgrader db_upgrader) { this.connection = db_conn; this.upgrader = db_upgrader; } /** * Returns a database connection this task can use. * * @return db connection */ public Connection getConnection() { return connection; } /** * Get a new connection from this task's owning {@link DBUpgrader} object. * * @return db connection * * @throws SQLException */ public Connection getNewConnection() throws SQLException { return upgrader.getConnection(); } /** * Returns the type of database being upgraded. * * @return database type */ public DatabaseType getDatabaseType() { return upgrader.getDatabaseType(); } /** * Given a generic type name, this returns the {@link java.sql.Types} integer value of that type. In effect, it maps * the generic type name with the JDBC SQL type ID. * * @param generic_type_name * * @return the JDBC SQL type ID of the given generic type * * @throws BuildException if the type is not a known or supported type */ public int translateSqlType(String generic_type_name) throws BuildException { String mapped_type = TypeMap.getMappedType(upgrader.getTypeMaps(), generic_type_name, null); Integer sql_type = SQL_TYPES.get(mapped_type); if (sql_type == null) { throw new BuildException(MSG.getMsg(DbAntI18NResourceKeys.INVALID_JDBC_SQL_TYPE, generic_type_name)); } return sql_type.intValue(); } /** * Returns the database-specific type name for the given generic type. * * @param generic_type_name * * @return the database specific type name that correlates to the generic type name * * @throws BuildException no database specific type name was defined */ public String getDBSpecificTypeName(String generic_type_name) throws BuildException { String mapped_type = TypeMap.getMappedType(TypeMap.loadKnownTypeMaps(), generic_type_name, getDatabaseType()); if (mapped_type == null) { throw new BuildException(MSG.getMsg(DbAntI18NResourceKeys.NO_DB_SPECIFIC_TYPE_MAPPING, generic_type_name, getDatabaseType())); } return mapped_type; } }