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

it.tidalwave.netbeans.persistence.maintenance.impl.TableManipulator 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.impl;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.logging.Logger;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.Statement;
import java.sql.SQLException;
import javax.persistence.EntityManager;
import it.tidalwave.netbeans.util.Locator;
import it.tidalwave.netbeans.persistence.EntityManagerProxy;
import it.tidalwave.netbeans.persistence.Persistence;
import it.tidalwave.netbeans.persistence.impl.PersistenceImpl;
import it.tidalwave.netbeans.persistence.maintenance.MaintainerTask.UpdateAction;

/***********************************************************************************************************************
 *
 * @author  Fabrizio Giudici
 * @version $Id$
 *
 **********************************************************************************************************************/
public class TableManipulator 
  {
    private static final String CLASS = TableManipulator.class.getName();
    private static final Logger logger = Logger.getLogger(CLASS);
    
    private final EntityAndTablePair entityAndTablePair;
    
    public String tableName; // FIXME: drop public
    
    public String destTableName; // FIXME: drop public
    
    public String tempTableName; // FIXME: drop public
    
    public List columns = new ArrayList(); // FIXME: drop public
    
    protected String createTableSQL;

    private boolean restoreNeeded = false;
    
    private final Maintainer maintainer;
    
    private final Connection connection;
    
    private final Statement statement;
    
    /***************************************************************************
     *
     *
     **************************************************************************/
    public TableManipulator (final EntityAndTablePair entityAndTablePair,
                             final Maintainer maintainer,
                             final Connection connection) 
      throws SQLException 
      {
        if (entityAndTablePair == null)
          {
            throw new IllegalArgumentException("entityClass is mandatory");
          }
        
        assert maintainer != null;
        assert connection != null;
        
        this.maintainer = maintainer;
        this.entityAndTablePair = entityAndTablePair;
        this.tableName = entityAndTablePair.getTableName();
        this.destTableName = tableName;
//        this.tableName = table.name();
        this.tempTableName = tableName + "_TMP";
        this.connection = connection;
        this.statement = connection.createStatement();
      }

    /***************************************************************************
     *
     *
     **************************************************************************/
    public void initialize()
      throws SQLException
      {
        final DatabaseMetaData databaseMetaData = connection.getMetaData();
        final ResultSet rs = databaseMetaData.getColumns(null, null, tableName, null);
        final StringBuilder builder = new StringBuilder();
        columns.clear();
        
        builder.append("CREATE TABLE ");
        builder.append(tempTableName);
        builder.append("(");
        String separator = "";
        
        while (rs.next())
          {
            final String columnName = rs.getString("COLUMN_NAME");
            String columnType = rs.getString("TYPE_NAME");
            
            if (columnType.equals("VARCHAR"))
              {
                columnType += "(" + rs.getInt("COLUMN_SIZE") + ")";
              }
            
            columns.add(columnName);
            
            builder.append(separator);
            builder.append(columnName);
            builder.append(" ");
            builder.append(columnType);
            separator = ", ";
          }
        
        rs.close();

        builder.append(")");
        createTableSQL = builder.toString();
      }

    /***************************************************************************
     *
     * Creates a temporary table, copies all records in it and drops the original
     * table. 
     *
     **************************************************************************/
    public void createTemporaryTable() 
      throws SQLException
      {
        if (maintainer.existsTable(tableName))
          {
            executeUpdate(createTableSQL);
            final String sqlColumns = commaSeparated(columns);
            executeUpdate(String.format("INSERT INTO %s(%s) SELECT %s FROM %s", tempTableName, sqlColumns, sqlColumns, tableName));
            executeUpdate("DROP TABLE " + tableName);
            restoreNeeded = true; 
          }
      }
    
    /***************************************************************************
     *
     * Disables the {@link #restoreTable()} execution.
     *
     **************************************************************************/
    public void disableRestore()
      {
        logger.info(String.format("restoreTable() disabled for table %s", tableName));
        restoreNeeded = false; 
      }
    
    /***************************************************************************
     *
     * This method forces JPA to create from scratch the destination table, then
     * copies records from the temporary table and drops the temporary table.
     *
     **************************************************************************/
    public void restoreTable()
      {
        logger.fine("restoreTable()");
        // Here we MUST use the EntityManager
        // Be careful, not to initialize JPA stuff before this method!
        final EntityManager em = new EntityManagerProxy();
        em.find(entityAndTablePair.getEntityClass(), ""); // force creation of table
        
        if (restoreNeeded)
          {
            final String sqlColumns = commaSeparated(columns);
            final String sql = String.format("INSERT INTO %s(%s) SELECT %s FROM %s", destTableName, sqlColumns, sqlColumns, tempTableName);
            logger.fine("SQL: " + sql);
            final int n = em.createNativeQuery(sql).executeUpdate();
            logger.fine(String.format("SQL: %d records updated", n));
            dropTable(tempTableName);
          } 
        
        // TODO: create indexes
      }

    /***************************************************************************
     *
     * Closes this object, releasing inner resources.
     *
     * @throws  SQLException 
     * 
     **************************************************************************/
    public void close() 
      throws SQLException
      {
        statement.close();
      }
    
    /***************************************************************************
     *
     * Applies a set of {@link UpdateAction}s.
     * 
     * @param   actions  the actions
     * @throws  SQLException 
     *
     **************************************************************************/
    public void apply (final UpdateAction ... actions) 
      throws SQLException 
      {
//        if (existsTable(tableName))
          {
            for (final UpdateAction action : actions)
              {
                action.apply(this);  
              }
          }
      }
    
    /***************************************************************************
     *
     * Returns the current version of the managed table.
     * 
     * @return  the version
     * @throws  SQLException 
     *
     **************************************************************************/
    public int getVersion() 
      throws SQLException 
      {
        return maintainer.getVersion(tableName);
      }
    
    /***************************************************************************
     *
     * Sets the current version of the managed table.
     * 
     * @param   version  the version
     * @throws  SQLException 
     *
     **************************************************************************/
    public void setVersion (final int version)
      throws SQLException
      {
        maintainer.setVersion(tableName, version);
      }
    
    /***************************************************************************
     *
     * Executes a SQL update statement.
     * 
     * @param   sql  the statement
     * @throws  SQLException 
     *
     **************************************************************************/
    public void executeUpdate (final String sql) 
      throws SQLException
      {
        logger.fine("SQL: " + sql);
        final int n = statement.executeUpdate(sql);
        logger.fine(String.format("SQL: %s records updated", n));
      }
    
    /***************************************************************************
     *
     * {@inheritDoc}
     *
     **************************************************************************/
    public void dropTable (final String tableName) 
      {
        logger.info(String.format("dropTable(%s)", tableName));
        
        final PersistenceImpl persistence = (PersistenceImpl)Locator.find(Persistence.class);
        
        if (!persistence.tableExists(tableName)) // can't use Maintainer, since it works in Phase 1 only
          {
            logger.info(String.format(">>>> table %s doesn't exist", tableName));
          }
        
        else
          {
            final EntityManager em = new EntityManagerProxy();
            final String jpaql = String.format("DROP TABLE %s", tableName);
            em.createNativeQuery(jpaql).executeUpdate();
          }
      }
    
    /***************************************************************************
     *
     * Returns a comma-separated string containing all the items in the given
     * collection.
     * 
     * @param  strings  the items
     * @return          the string
     *
     **************************************************************************/
    private static String commaSeparated (final Collection strings)
      {
        final StringBuilder builder = new StringBuilder();
        String separator = "";

        for (final String string : strings) 
          {
            builder.append(separator);
            builder.append(string);
            separator = ", ";
          }
        
        return builder.toString();
      }

    public boolean tempTableExists() 
      throws SQLException 
      {
        return maintainer.existsTable(tempTableName);
      }
  }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy