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.invocation; 019 020import java.util.Map; 021import java.util.SortedMap; 022import java.util.TreeMap; 023 024import net.sf.hajdbc.Database; 025import net.sf.hajdbc.DatabaseCluster; 026import net.sf.hajdbc.ExceptionFactory; 027import net.sf.hajdbc.Messages; 028import net.sf.hajdbc.balancer.Balancer; 029import net.sf.hajdbc.dialect.Dialect; 030import net.sf.hajdbc.logging.Level; 031import net.sf.hajdbc.logging.Logger; 032import net.sf.hajdbc.logging.LoggerFactory; 033import net.sf.hajdbc.sql.ProxyFactory; 034import net.sf.hajdbc.state.StateManager; 035 036/** 037 * @author Paul Ferraro 038 */ 039public class InvokeOnAnyInvocationStrategy implements InvocationStrategy 040{ 041 private static Logger logger = LoggerFactory.getLogger(ExistingResultsCollector.class); 042 043 private final InvocationStrategy strategy; 044 045 public InvokeOnAnyInvocationStrategy(InvocationStrategy strategy) 046 { 047 this.strategy = strategy; 048 } 049 050 /** 051 * {@inheritDoc} 052 */ 053 @Override 054 public <Z, D extends Database<Z>, T, R, E extends Exception> SortedMap<D, R> invoke(ProxyFactory<Z, D, T, E> factory, Invoker<Z, D, T, R, E> invoker) throws E 055 { 056 DatabaseCluster<Z, D> cluster = factory.getDatabaseCluster(); 057 Balancer<Z, D> balancer = cluster.getBalancer(); 058 Dialect dialect = cluster.getDialect(); 059 StateManager stateManager = cluster.getStateManager(); 060 061 for (Map.Entry<D, T> entry: factory.entries()) 062 { 063 D database = entry.getKey(); 064 065 // If this database is no longer active, just skip it. 066 if (balancer.contains(database)) 067 { 068 try 069 { 070 R result = invoker.invoke(database, entry.getValue()); 071 072 SortedMap<D, R> resultMap = new TreeMap<D, R>(); 073 resultMap.put(database, result); 074 return resultMap; 075 } 076 catch (Exception e) 077 { 078 // If this database was concurrently deactivated, just ignore the failure 079 if (cluster.getBalancer().contains(database)) 080 { 081 ExceptionFactory<E> exceptionFactory = factory.getExceptionFactory(); 082 E exception = exceptionFactory.createException(e); 083 084 if (exceptionFactory.indicatesFailure(exception, dialect) && (cluster.getBalancer().size() > 1)) 085 { 086 if (cluster.deactivate(database, stateManager)) 087 { 088 logger.log(Level.ERROR, exception, Messages.DATABASE_DEACTIVATED.getMessage(), database, cluster); 089 } 090 } 091 else 092 { 093 throw exception; 094 } 095 } 096 } 097 } 098 } 099 100 // If no existing databases could handle the request, delegate to another invocation strategy 101 return this.strategy.invoke(factory, invoker); 102 } 103}