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.util;
019
020import java.util.Iterator;
021import java.util.LinkedList;
022import java.util.List;
023import java.util.ServiceConfigurationError;
024import java.util.ServiceLoader;
025
026import net.sf.hajdbc.logging.Level;
027import net.sf.hajdbc.logging.Logger;
028import net.sf.hajdbc.logging.LoggerFactory;
029
030public class ServiceLoaders
031{
032        private static final Logger logger = LoggerFactory.getLogger(ServiceLoaders.class);
033        
034        public static <T> T findService(Class<T> serviceClass)
035        {
036                Iterator<T> services = ServiceLoader.load(serviceClass, serviceClass.getClassLoader()).iterator();
037                
038                while (services.hasNext())
039                {
040                        try
041                        {
042                                return services.next();
043                        }
044                        catch (ServiceConfigurationError e)
045                        {
046                                logger.log(Level.DEBUG, e.getLocalizedMessage());
047                        }
048                }
049                return null;
050        }
051
052        public static <T> T findRequiredService(Class<T> serviceClass)
053        {
054                T service = findService(serviceClass);
055                if (service == null)
056                {
057                        throw new IllegalStateException(String.format("No %s found", serviceClass.getName()));
058                }
059                return service;
060        }
061
062        public static <T> T findService(Matcher<T> matcher, Class<T> serviceClass)
063        {
064                List<T> matches = new LinkedList<T>();
065                Iterator<T> services = ServiceLoader.load(serviceClass, serviceClass.getClassLoader()).iterator();
066                
067                while (services.hasNext())
068                {
069                        try
070                        {
071                                T service = services.next();
072                                if (matcher.matches(service))
073                                {
074                                        matches.add(service);
075                                }
076                        }
077                        catch (ServiceConfigurationError e)
078                        {
079                                logger.log(Level.DEBUG, e.getLocalizedMessage());
080                        }
081                }
082                
083                if (matches.size() > 1)
084                {
085                        logger.log(Level.WARN, "Multiple {0} found matching {1}: {2}", serviceClass.getName(), matcher, matches);
086                }
087                
088                return !matches.isEmpty() ? matches.get(0) : null;
089        }
090
091        public static <T> T findRequiredService(Matcher<T> matcher, Class<T> serviceClass)
092        {
093                T service = findService(matcher, serviceClass);
094                if (service == null)
095                {
096                        throw new IllegalArgumentException(String.format("No %s found matching %s", serviceClass.getName(), matcher));
097                }
098                return service;
099        }
100
101        private ServiceLoaders()
102        {
103                // Hide
104        }
105}