/* * Copyright 2015 SFB 632. * * 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. */ package annis.dao; import annis.administration.FileAccessException; import annis.administration.StatementController; import annis.utils.DynamicDataSource; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStreamReader; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; import java.util.HashMap; import java.util.Map; import java.util.regex.Matcher; import javax.sql.DataSource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.core.io.FileSystemResource; import org.springframework.core.io.Resource; import org.springframework.dao.DataAccessException; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.PreparedStatementCallback; import org.springframework.jdbc.core.PreparedStatementCreator; import org.springframework.jdbc.core.namedparam.MapSqlParameterSource; /** * Common functions used by all data access objects. * @author Thomas Krause <krauseto@hu-berlin.de> */ public abstract class AbstractDao { private final static Logger log = LoggerFactory.getLogger( AbstractDao.class); private JdbcTemplate jdbcTemplate; private DynamicDataSource dataSource; private StatementController statementController; private String scriptPath; /** * executes an SQL string, substituting the * parameters found in args * * @param sql * @param args * @return */ protected PreparedStatement executeSql(String sql, MapSqlParameterSource args) { // XXX: uses raw type, what are the parameters to Map in MapSqlParameterSource? Map<String, Object> parameters = args != null ? args.getValues() : new HashMap(); for (Map.Entry<String, Object> placeHolderEntry : parameters.entrySet()) { String key = placeHolderEntry.getKey(); String value = placeHolderEntry.getValue().toString(); log.debug("substitution for parameter '" + key + "' in SQL script: " + value); sql = sql.replaceAll(key, Matcher.quoteReplacement(value)); } log.debug("Executing SQL\n{}", sql); CancelableStatements cancelableStats = new CancelableStatements( sql, statementController); // register the statement, so we could try to interrupt it in the gui. if (statementController != null) { statementController.registerStatement(cancelableStats.statement); } else { log.debug("statement controller is not initialized"); } getJdbcTemplate().execute(cancelableStats, cancelableStats); return cancelableStats.statement; } /** * executes an SQL script from $ANNIS_HOME/scripts, substituting the * parameters found in args * * @param script * @param args * @return */ protected PreparedStatement executeSqlFromScript(String script, MapSqlParameterSource args) { File fScript = new File(scriptPath, script); if (fScript.canRead() && fScript.isFile()) { Resource resource = new FileSystemResource(fScript); log.debug("executing SQL script: " + resource.getFilename()); String sql = readSqlFromResource(resource); return executeSql(sql, args); } else { log.debug("SQL script " + fScript.getName() + " does not exist"); return null; } } /** * Reads the content from a resource into a string. * @param resource * @return */ private String readSqlFromResource(Resource resource) { try (BufferedReader reader = new BufferedReader(new InputStreamReader( new FileInputStream( resource. getFile()), "UTF-8"));) { StringBuilder sqlBuf = new StringBuilder(); for (String line = reader.readLine(); line != null; line = reader.readLine()) { sqlBuf.append(line).append("\n"); } return sqlBuf.toString(); } catch (IOException e) { log.error("Couldn't read SQL script from resource file.", e); throw new FileAccessException( "Couldn't read SQL script from resource file.", e); } } protected MapSqlParameterSource makeArgs() { return new MapSqlParameterSource(); } public void registerGUICancelThread(StatementController statementCon) { this.statementController = statementCon; } public JdbcTemplate getJdbcTemplate() { return jdbcTemplate; } public void setJdbcTemplate(JdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; DataSource dsArg = jdbcTemplate.getDataSource(); if(dsArg instanceof DynamicDataSource) { this.dataSource = (DynamicDataSource) dsArg; } else { this.dataSource = new DynamicDataSource(); this.dataSource.setInnerDataSource(dsArg); } } public DynamicDataSource getDataSource() { return dataSource; } public void setDataSource(DynamicDataSource dataSource) { this.dataSource = dataSource; jdbcTemplate = new JdbcTemplate(dataSource); } public String getScriptPath() { return scriptPath; } public void setScriptPath(String scriptPath) { this.scriptPath = scriptPath; } /** * Registers a {@link PreparedStatement} to the {@link StatementController}. */ private static class CancelableStatements implements PreparedStatementCreator, PreparedStatementCallback<Void> { private final String sqlQuery; private PreparedStatement statement; private final StatementController statementController; public CancelableStatements(String sql, StatementController statementController) { this.sqlQuery = sql; this.statementController = statementController; } @Override public PreparedStatement createPreparedStatement(Connection con) throws SQLException { if (statementController != null && statementController.isCancelled()) { throw new SQLException("process was cancelled"); } statement = con.prepareCall(sqlQuery); if (statementController != null) { statementController.registerStatement(statement); } return statement; } @Override public Void doInPreparedStatement(PreparedStatement ps) throws SQLException, DataAccessException { ps.execute(); return null; } } }