All Downloads are FREE. Search and download functionalities are using the official Maven repository.

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