
it.tidalwave.netbeans.persistence.maintenance.MaintainerTask Maven / Gradle / Ivy
The newest version!
/***********************************************************************************************************************
*
* OpenBlueSky - NetBeans Platform Enhancements
* Copyright (C) 2006-2012 by Tidalwave s.a.s. (http://www.tidalwave.it)
*
***********************************************************************************************************************
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
***********************************************************************************************************************
*
* WWW: http://openbluesky.java.net
* SCM: https://bitbucket.org/tidalwave/openbluesky-src
*
**********************************************************************************************************************/
package it.tidalwave.netbeans.persistence.maintenance;
import java.util.Arrays;
import java.sql.SQLException;
import javax.persistence.Entity;
import javax.persistence.Table;
import it.tidalwave.util.logging.Logger;
import it.tidalwave.netbeans.persistence.maintenance.impl.EntityAndTablePair;
import it.tidalwave.netbeans.persistence.maintenance.impl.Maintainer;
import it.tidalwave.netbeans.persistence.maintenance.impl.TableManipulator;
/***********************************************************************************************************************
*
* TODO: implement meaningful operations from http://databaserefactoring.com/
*
* @author Fabrizio Giudici
* @version $Id$
*
**********************************************************************************************************************/
public abstract class MaintainerTask
{
private static final String CLASS = MaintainerTask.class.getName();
private static final Logger logger = Logger.getLogger(CLASS);
/***************************************************************************
*
*
**************************************************************************/
public static interface UpdateAction
{
public void apply (TableManipulator info)
throws SQLException;
}
/***************************************************************************
*
*
**************************************************************************/
private class RenameColumnAction implements UpdateAction
{
private final String oldName;
private final String newName;
public RenameColumnAction (final String oldName, final String newName)
{
// TODO: check validity
this.oldName = oldName;
this.newName = newName;
}
@Override
public void apply (final TableManipulator manipulator)
throws SQLException
{
if (manipulator.tempTableExists())
{
executeupdate(String.format("RENAME COLUMN %s.%s TO %s", manipulator.tempTableName, oldName, newName));
}
manipulator.columns.remove(oldName);
manipulator.columns.add(newName);
}
@Override
public String toString()
{
return String.format("RenameColumnAction[%s -> %s]", oldName, newName);
}
}
/***************************************************************************
*
*
**************************************************************************/
private class DropColumnAction implements UpdateAction
{
private final String name;
public DropColumnAction (final String name)
{
// TODO: check validity
this.name = name;
}
@Override
public void apply (final TableManipulator manipulator)
throws SQLException
{
if (manipulator.tempTableExists())
{
executeupdate(String.format("ALTER TABLE %s DROP COLUMN %s", manipulator.tempTableName, name));
}
manipulator.columns.remove(name);
}
@Override
public String toString()
{
return String.format("DropColumnAction[%s]", name);
}
}
/***************************************************************************
*
*
**************************************************************************/
private class AddColumnAction implements UpdateAction
{
private final String name;
private final String type;
private final Object initialValue;
public AddColumnAction (final String name, final String type, final Object initialValue)
{
// TODO: check validity
this.name = name;
this.type = type;
this.initialValue = initialValue;
}
@Override
public void apply (final TableManipulator manipulator)
throws SQLException
{
if (manipulator.tempTableExists())
{
executeupdate(String.format("ALTER TABLE %s ADD COLUMN %s %s", manipulator.tempTableName, name, type));
if (initialValue != null)
{
final String v = (type.indexOf("VARCHAR") >= 0) ? ("'" + initialValue + "'") : ("" + initialValue);
executeupdate(String.format("UPDATE %s SET %s=%s", manipulator.tempTableName, name, v));
}
}
manipulator.columns.add(name);
}
@Override
public String toString()
{
return String.format("AddColumnAction[%s: %s]", name, type);
}
}
protected final EntityAndTablePair entityAndTablePair;
protected final int fromVersion;
protected final int toVersion;
protected TableManipulator manipulator;
protected Maintainer maintainer;
/***************************************************************************
*
* Ths origTableName is mandatory because it's the only way we have to keep
* track of old table names (since the annotation only gives the current one).
*
**************************************************************************/
public MaintainerTask (final Class> entityClass, final String tableName, final int fromVersion, final int toVersion)
{
if (entityClass == null)
{
throw new IllegalArgumentException("entityClass is mandatory");
}
if (tableName == null)
{
throw new IllegalArgumentException("origTableName is mandatory");
}
if (toVersion <= fromVersion)
{
throw new IllegalArgumentException("toVersion must be > fromVersion");
}
final Entity entity = entityClass.getAnnotation(Entity.class);
final Table table = entityClass.getAnnotation(Table.class);
if (entity == null)
{
throw new IllegalArgumentException("entityClass must be annotated with @Entity");
}
if (table == null)
{
throw new IllegalArgumentException("entityClass must be annotated with @Table");
}
this.entityAndTablePair = new EntityAndTablePair(entityClass, tableName);
this.fromVersion = fromVersion;
this.toVersion = toVersion;
}
/***************************************************************************
*
*
**************************************************************************/
public Class> getEntityClass()
{
return entityAndTablePair.getEntityClass();
}
/***************************************************************************
*
*
**************************************************************************/
public int getFromVersion()
{
return fromVersion;
}
/***************************************************************************
*
*
**************************************************************************/
public int getToVersion()
{
return toVersion;
}
/***************************************************************************
*
*
**************************************************************************/
public EntityAndTablePair getEntityAndTablePair()
{
return entityAndTablePair;
}
/***************************************************************************
*
*
**************************************************************************/
public final void run (final Maintainer maintainer, final TableManipulator manipulator)
throws SQLException
{
this.maintainer = maintainer;
this.manipulator = manipulator;
run();
}
/***************************************************************************
*
*
**************************************************************************/
public abstract void run()
throws SQLException;
/***************************************************************************
*
*
**************************************************************************/
@Override
public String toString()
{
return String.format("%s[%s, %d -> %d]", getClass().getName(), entityAndTablePair, fromVersion, toVersion);
}
/***************************************************************************
*
*
**************************************************************************/
@Override
public boolean equals (final Object object)
{
if (object == null)
{
return false;
}
if (getClass() != object.getClass())
{
return false;
}
final MaintainerTask other = (MaintainerTask) object;
if (!this.entityAndTablePair.equals(other.entityAndTablePair))
{
return false;
}
if (this.fromVersion != other.fromVersion)
{
return false;
}
if (this.toVersion != other.toVersion)
{
return false;
}
return true;
}
/***************************************************************************
*
*
**************************************************************************/
@Override
public int hashCode()
{
int hash = 5;
hash = 23 * hash + this.entityAndTablePair.hashCode();
hash = 23 * hash + this.fromVersion;
hash = 23 * hash + this.toVersion;
return hash;
}
/***************************************************************************
*
*
**************************************************************************/
protected void updateColumns (final UpdateAction ... actions)
{
try
{
logger.info(String.format("update(%s)", Arrays.toString(actions)));
// Can't call getVersion(), reads the old value assert (manipulator.getVersion() == fromVersion);
manipulator.apply(actions);
manipulator.setVersion(toVersion);
}
catch (SQLException e)
{
throw new RuntimeException(e);
}
}
/***************************************************************************
*
*
**************************************************************************/
protected void executeupdate (final String sql)
throws SQLException
{
manipulator.executeUpdate(sql);
}
/***************************************************************************
*
*
**************************************************************************/
protected boolean existsTable (final String tableName)
throws SQLException
{
return maintainer.existsTable(tableName);
}
/***************************************************************************
*
*
**************************************************************************/
protected void importFromTable (final String tableName)
throws SQLException
{
logger.fine("importFromTable(%s)", tableName);
logger.finer(">>>> enforcing the update for %s...", tableName);
final TableManipulator otherManipulator = maintainer.updateEntity(new EntityAndTablePair(entityAndTablePair.getEntityClass(), tableName));
logger.finer(">>>> enforced the update for %s", tableName);
assert (otherManipulator != null);
// if (otherManipulator != null)
{
otherManipulator.destTableName = entityAndTablePair.getTableName();
// Disable this manipulator, it will be otherManipulator's responsibility to restore the table.
// But link its columns to the ones here so they will be updated.
// FIXME: it would be better to disable otherManipulator and do changes in manipulator
// manipulator.disableRestore();s
manipulator.columns = otherManipulator.columns;
manipulator.tempTableName = otherManipulator.tempTableName;
}
}
/***************************************************************************
*
*
**************************************************************************/
protected UpdateAction rename (final String oldName, final String newName)
{
return new RenameColumnAction(oldName, newName);
}
/***************************************************************************
*
*
**************************************************************************/
protected UpdateAction create (final String name, final String type, final Object initialValue)
{
return new AddColumnAction(name, type, initialValue);
}
/***************************************************************************
*
*
**************************************************************************/
protected UpdateAction drop (final String name)
{
return new DropColumnAction(name);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy