
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