/** * Copyright 2011-2017 Asakusa Framework Team. * * 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 com.asakusafw.windgate.jdbc; import java.io.IOException; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.text.MessageFormat; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.asakusafw.windgate.core.WindGateLogger; import com.asakusafw.windgate.core.resource.SourceDriver; import com.asakusafw.windgate.core.vocabulary.DataModelJdbcSupport.DataModelResultSet; /** * An implementation of {@link SourceDriver} using JDBC. * @param <T> the type of data model object * @since 0.2.2 */ public class JdbcSourceDriver<T> implements SourceDriver<T> { static final WindGateLogger WGLOG = new JdbcLogger(JdbcSourceDriver.class); static final Logger LOG = LoggerFactory.getLogger(JdbcSourceDriver.class); private final JdbcProfile profile; private final JdbcScript<T> script; private final Connection connection; private final T object; private Statement statement; private ResultSet resultSet; private DataModelResultSet<? super T> support; private boolean sawNext; /** * Creates a new instance. * @param profile the profile of the target database * @param script the script of this action * @param connection the connection * @param object the data model object used as a buffer * @throws IllegalArgumentException if any parameter is {@code null} */ public JdbcSourceDriver( JdbcProfile profile, JdbcScript<T> script, Connection connection, T object) { if (profile == null) { throw new IllegalArgumentException("profile must not be null"); //$NON-NLS-1$ } if (script == null) { throw new IllegalArgumentException("script must not be null"); //$NON-NLS-1$ } if (connection == null) { throw new IllegalArgumentException("connection must not be null"); //$NON-NLS-1$ } if (object == null) { throw new IllegalArgumentException("object must not be null"); //$NON-NLS-1$ } this.profile = profile; this.script = script; this.connection = connection; this.object = object; } @Override public void prepare() throws IOException { LOG.debug("Preparing JDBC resource source (resource={}, table={})", profile.getResourceName(), script.getTableName()); try { this.resultSet = prepareResultSet(); } catch (SQLException e) { for (SQLException ex = e; ex != null; ex = ex.getNextException()) { WGLOG.error(ex, "E03001", profile.getResourceName(), script.getName(), script.getTableName(), script.getColumnNames()); } throw new IOException(MessageFormat.format( "Failed to prepare JDBC source (resource={0}, table={1}, columns={2})", profile.getResourceName(), script.getTableName(), script.getColumnNames()), e); } LOG.debug("Creating ResultSet support {} for {}", script.getSupport().getClass().getName(), script.getColumnNames()); support = script.getSupport().createResultSetSupport(resultSet, script.getColumnNames()); } private ResultSet prepareResultSet() throws SQLException { String sql = createSql(); statement = connection.createStatement(); boolean succeed = false; try { WGLOG.info("I03001", profile.getResourceName(), script.getName(), script.getTableName(), script.getColumnNames()); if (profile.getBatchGetUnit() != 0) { statement.setFetchSize(profile.getBatchGetUnit()); } LOG.debug("Executing SQL: {}", sql); ResultSet result = statement.executeQuery(sql); LOG.debug("Executed SQL: {}", sql); WGLOG.info("I03002", profile.getResourceName(), script.getName(), script.getTableName(), script.getColumnNames()); succeed = true; return result; } finally { if (succeed == false) { try { statement.close(); } catch (SQLException e) { for (SQLException ex = e; ex != null; ex = ex.getNextException()) { WGLOG.warn(ex, "W03001", profile.getResourceName(), script.getName(), script.getTableName(), script.getColumnNames()); } } } } } private String createSql() { assert script.getColumnNames().isEmpty() == false; if (script.getCondition() != null) { assert script.getCondition().isEmpty() == false; return MessageFormat.format( "SELECT {1} FROM {0} WHERE {2}", script.getTableName(), JdbcResourceUtil.join(script.getColumnNames()), script.getCondition()); } else { return MessageFormat.format( "SELECT {1} FROM {0}", script.getTableName(), JdbcResourceUtil.join(script.getColumnNames())); } } @Override public boolean next() throws IOException { try { sawNext = support.next(object); return sawNext; } catch (SQLException e) { sawNext = false; for (SQLException ex = e; ex != null; ex = ex.getNextException()) { WGLOG.error(ex, "E03001", profile.getResourceName(), script.getName(), script.getTableName(), script.getColumnNames()); } throw new IOException(MessageFormat.format( "Failed to fetch next object from JDBC source (resource={0}, table={1})", profile.getResourceName(), script.getTableName()), e); } } @Override public T get() throws IOException { if (sawNext == false) { throw new IOException("Next data model was not prepared"); } return object; } @Override public void close() throws IOException { LOG.debug("Closing JDBC resource source (resource={}, table={})", profile.getResourceName(), script.getTableName()); sawNext = false; if (resultSet != null) { try { resultSet.close(); resultSet = null; support = null; } catch (SQLException e) { for (SQLException ex = e; ex != null; ex = ex.getNextException()) { WGLOG.warn(ex, "W03001", profile.getResourceName(), script.getName(), script.getTableName(), script.getColumnNames()); } } try { if (statement != null) { statement.close(); } } catch (SQLException e) { for (SQLException ex = e; ex != null; ex = ex.getNextException()) { WGLOG.warn(ex, "W03001", profile.getResourceName(), script.getName(), script.getTableName(), script.getColumnNames()); } } } try { connection.close(); } catch (SQLException e) { for (SQLException ex = e; ex != null; ex = ex.getNextException()) { WGLOG.warn(ex, "W02001", profile.getResourceName(), script.getName()); } } } }