/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.ignite.cache.store.jdbc; import java.sql.Connection; import java.sql.SQLException; import javax.cache.Cache; import javax.cache.integration.CacheWriterException; import javax.sql.DataSource; import org.apache.ignite.IgniteException; import org.apache.ignite.cache.store.CacheStore; import org.apache.ignite.cache.store.CacheStoreSession; import org.apache.ignite.cache.store.CacheStoreSessionListener; import org.apache.ignite.internal.util.typedef.internal.U; import org.apache.ignite.lifecycle.LifecycleAware; /** * Cache store session listener based on JDBC connection. * <p> * For each session this listener gets a new JDBC connection * from provided {@link DataSource} and commits (or rolls * back) it when session ends. * <p> * The connection is saved as a store session * {@link CacheStoreSession#attachment() attachment}. * The listener guarantees that the connection will be * available for any store operation. If there is an * ongoing cache transaction, all operations within this * transaction will be committed or rolled back only when * the session ends. * <p> * As an example, here is how the {@link CacheStore#write(Cache.Entry)} * method can be implemented if {@link CacheJdbcStoreSessionListener} * is configured: * <pre name="code" class="java"> * private static class Store extends CacheStoreAdapter<Integer, Integer> { * @CacheStoreSessionResource * private CacheStoreSession ses; * * @Override public void write(Cache.Entry<? extends Integer, ? extends Integer> entry) throws CacheWriterException { * // Get connection from the current session. * Connection conn = ses.attachment(); * * // Execute update SQL query. * try { * conn.createStatement().executeUpdate("..."); * } * catch (SQLException e) { * throw new CacheWriterException("Failed to update the store.", e); * } * } * } * </pre> * JDBC connection will be automatically created by the listener * at the start of the session and closed when it ends. */ public class CacheJdbcStoreSessionListener implements CacheStoreSessionListener, LifecycleAware { /** Data source. */ private DataSource dataSrc; /** * Sets data source. * <p> * This is a required parameter. If data source is not set, * exception will be thrown on startup. * * @param dataSrc Data source. */ public void setDataSource(DataSource dataSrc) { this.dataSrc = dataSrc; } /** * Gets data source. * * @return Data source. */ public DataSource getDataSource() { return dataSrc; } /** {@inheritDoc} */ @Override public void start() throws IgniteException { if (dataSrc == null) throw new IgniteException("Data source is required by " + getClass().getSimpleName() + '.'); } /** {@inheritDoc} */ @Override public void stop() throws IgniteException { // No-op. } /** {@inheritDoc} */ @Override public void onSessionStart(CacheStoreSession ses) { if (ses.attachment() == null) { try { Connection conn = dataSrc.getConnection(); conn.setAutoCommit(false); ses.attach(conn); } catch (SQLException e) { throw new CacheWriterException("Failed to start store session [tx=" + ses.transaction() + ']', e); } } } /** {@inheritDoc} */ @Override public void onSessionEnd(CacheStoreSession ses, boolean commit) { Connection conn = ses.attach(null); if (conn != null) { try { if (commit) conn.commit(); else conn.rollback(); } catch (SQLException e) { throw new CacheWriterException("Failed to end store session [tx=" + ses.transaction() + ']', e); } finally { U.closeQuiet(conn); } } } }