/* * Copyright (C) 2003-2010 eXo Platform SAS. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Affero General Public License * as published by the Free Software Foundation; either version 3 * of the License, or (at your option) any later version. * * 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, see<http://www.gnu.org/licenses/>. */ package org.exoplatform.services.jcr.impl.clean.rdbms; import org.exoplatform.commons.utils.SecurityHelper; import org.exoplatform.services.database.utils.JDBCUtils; import org.exoplatform.services.jcr.core.security.JCRRuntimePermissions; import org.exoplatform.services.log.ExoLogger; import org.exoplatform.services.log.Log; import java.security.PrivilegedExceptionAction; import java.sql.Connection; import java.sql.SQLException; import java.sql.Statement; import java.util.ArrayList; import java.util.Collection; import java.util.List; /** * The goal of this class is removing data from database. * * @author <a href="karpenko.sergiy@gmail.com">Karpenko Sergiy</a> * @version $Id: DBCleanerTool.java 3769 2011-01-04 15:36:06Z areshetnyak $ */ public class DBCleanerTool { /** * Logger. */ protected final static Log LOG = ExoLogger.getLogger("exo.jcr.component.core.DBCleaner"); protected final Connection connection; protected final boolean autoCommit; protected final List<String> rollbackingScripts = new ArrayList<String>(); protected final List<String> committingScripts = new ArrayList<String>(); protected final List<String> cleaningScripts = new ArrayList<String>(); /** * DBCleanerTool constructor. * * @param connection * connection to database which will be used in cleaning, take in account DBCleanerTool does not * close connection * @param autoCommit * auto commit mode which will be set during script execution */ DBCleanerTool(Connection connection, boolean autoCommit, Collection<String> cleaningScripts, Collection<String> committingScripts, Collection<String> rollbackingScripts) { this.connection = connection; this.autoCommit = autoCommit; this.cleaningScripts.addAll(cleaningScripts); this.committingScripts.addAll(committingScripts); this.rollbackingScripts.addAll(rollbackingScripts); } /** * Clean JCR tables, can't contain some indexes or constraints, * should be added on {@link #commit}. It done for possibility to restore * data without any violations. * * <br> * This method does not invoke commit or rollback on {@link Connection} but * needed autocommit mode can be set. * * @throws DBCleanException */ public void clean() throws DBCleanException { try { execute(cleaningScripts); } catch (SQLException e) { throw new DBCleanException(JDBCUtils.getFullMessage(e), e); } } /** * Executes SQL scripts for finishing clean operations if needed. * It can be adding indexes, constraints, removing temporary objects etc * (related to specific database) or does nothing. * * <br> * This method does not invoke commit or rollback on {@link Connection} but * needed autocommit mode can be set. * * @throws DBCleanException */ public void commit() throws DBCleanException { try { execute(committingScripts); } catch (SQLException e) { throw new DBCleanException(JDBCUtils.getFullMessage(e), e); } } /** * Tries to restore previous data by renaming tables etc * (related to specific database) or does nothing. * * <br> * This method does not invoke commit or rollback on {@link Connection} but * needed autocommit mode can be set. * * @throws DBCleanException */ public void rollback() throws DBCleanException { try { execute(rollbackingScripts); } catch (SQLException e) { throw new DBCleanException(JDBCUtils.getFullMessage(e), e); } } /** * Return connection which it is used in cleaner. */ public Connection getConnection() { return connection; } /** * Execute script on database. Set auto commit mode if needed. * * @param scripts * the scripts for execution * @throws SQLException */ protected void execute(List<String> scripts) throws SQLException { SecurityHelper.validateSecurityPermission(JCRRuntimePermissions.MANAGE_REPOSITORY_PERMISSION); // set needed auto commit mode boolean autoCommit = connection.getAutoCommit(); if (autoCommit != this.autoCommit) { connection.setAutoCommit(this.autoCommit); } Statement st = connection.createStatement(); try { for (String scr : scripts) { String sql = JDBCUtils.cleanWhitespaces(scr.trim()); if (!sql.isEmpty()) { if (LOG.isDebugEnabled()) { LOG.debug("Execute script: \n[" + sql + "]"); } executeQuery(st, sql); } } } finally { try { st.close(); } catch (SQLException e) { LOG.error("Can't close the Statement." + e.getMessage()); } // restore previous auto commit mode if (autoCommit != this.autoCommit) { connection.setAutoCommit(autoCommit); } } } protected void executeQuery(final Statement statement, final String sql) throws SQLException { try { long start = 0; if (LOG.isDebugEnabled()) { start = System.currentTimeMillis(); LOG.debug("Execute script: \n[" + sql + "]"); } SecurityHelper.doPrivilegedSQLExceptionAction(new PrivilegedExceptionAction<Object>() { public Object run() throws Exception { statement.executeUpdate(sql); return null; } }); if (LOG.isDebugEnabled()) { LOG.debug("Script "+sql+" executed in " + ((System.currentTimeMillis() - start) / 1000d) + " sec"); } } catch (SQLException e) { LOG.error("Query execution \"" + sql + "\" failed: " + JDBCUtils.getFullMessage(e), e); throw e; } } }