001/*
002 * HA-JDBC: High-Availability JDBC
003 * Copyright (C) 2012  Paul Ferraro
004 *
005 * This program is free software: you can redistribute it and/or modify
006 * it under the terms of the GNU Lesser General Public License as published by
007 * the Free Software Foundation, either version 3 of the License, or
008 * (at your option) any later version.
009 *
010 * This program is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
013 * GNU Lesser General Public License for more details.
014 *
015 * You should have received a copy of the GNU Lesser General Public License
016 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
017 */
018package net.sf.hajdbc.durability.coarse;
019
020import java.util.Map;
021import java.util.SortedMap;
022
023import net.sf.hajdbc.Database;
024import net.sf.hajdbc.DatabaseCluster;
025import net.sf.hajdbc.durability.DurabilityListener;
026import net.sf.hajdbc.durability.InvocationEvent;
027import net.sf.hajdbc.durability.InvocationEventImpl;
028import net.sf.hajdbc.durability.InvokerEvent;
029import net.sf.hajdbc.durability.none.NoDurability;
030import net.sf.hajdbc.invocation.InvocationStrategy;
031import net.sf.hajdbc.invocation.Invoker;
032import net.sf.hajdbc.sql.ProxyFactory;
033import net.sf.hajdbc.state.StateManager;
034
035/**
036 * {@link net.sf.hajdbc.durability.Durability} implementation that tracks invocations only, but not per-database invokers.
037 * This durability level can detect, but not recover from, mid-commit crashes.
038 * @author Paul Ferraro
039 */
040/**
041 * @author Paul Ferraro
042 * @param <Z>
043 * @param <D>
044 */
045public class CoarseDurability<Z, D extends Database<Z>> extends NoDurability<Z, D>
046{
047        protected final DatabaseCluster<Z, D> cluster;
048
049        public CoarseDurability(DatabaseCluster<Z, D> cluster)
050        {
051                this.cluster = cluster;
052        }
053
054        /**
055         * {@inheritDoc}
056         * @see net.sf.hajdbc.durability.none.NoDurability#getInvocationStrategy(net.sf.hajdbc.invocation.InvocationStrategy, net.sf.hajdbc.durability.Durability.Phase, java.lang.Object)
057         */
058        @Override
059        public InvocationStrategy getInvocationStrategy(final InvocationStrategy strategy, final Phase phase, final Object transactionId)
060        {
061                final DurabilityListener listener = this.cluster.getStateManager();
062
063                return new InvocationStrategy()
064                {
065                        @Override
066                        public <ZZ, DD extends Database<ZZ>, T, R, EE extends Exception> SortedMap<DD, R> invoke(ProxyFactory<ZZ, DD, T, EE> proxy, Invoker<ZZ, DD, T, R, EE> invoker) throws EE
067                        {
068                                InvocationEvent event = new InvocationEventImpl(transactionId, phase, proxy.getExceptionFactory().getType());
069
070                                listener.beforeInvocation(event);
071
072                                try
073                                {
074                                        return strategy.invoke(proxy, invoker);
075                                }
076                                catch (Exception e)
077                                {
078                                        throw proxy.getExceptionFactory().createException(e);
079                                }
080                                finally
081                                {
082                                        listener.afterInvocation(event);
083                                }
084                        }
085                };
086        }
087
088        /**
089         * {@inheritDoc}
090         * @see net.sf.hajdbc.durability.none.NoDurability#recover(java.util.Map)
091         */
092        @Override
093        public void recover(Map<InvocationEvent, Map<String, InvokerEvent>> invokers)
094        {
095                StateManager stateManager = this.cluster.getStateManager();
096
097                for (D database: this.cluster.getBalancer().backups())
098                {
099                        this.cluster.deactivate(database, stateManager);
100                }
101
102                for (InvocationEvent event: invokers.keySet())
103                {
104                        stateManager.afterInvocation(event);
105                }
106        }
107}