001    /*
002     * Copyright 2005,2009 Ivan SZKIBA
003     *
004     * Licensed under the Apache License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     *      http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    package org.ini4j.spi;
017    
018    import java.io.BufferedReader;
019    import java.io.InputStream;
020    import java.io.InputStreamReader;
021    
022    /**
023     * JDK JAR Services API alap??? service keres??? oszt???ly.
024     *
025     * @author Szkiba Iv???n
026     * @version $Name:  $
027     */
028    public final class ServiceFinder
029    {
030        private static final String SERVICES_PATH = "META-INF/services/";
031    
032        private ServiceFinder()
033        {
034        }
035    
036        /**
037         * Service objektum keres???s ???s p???ld???nyos???t???s
038         *
039         * a JDK JAR specifik???ci???ban defini???lt <B>Services API</B>-nak
040         * megfelel???en service oszt???ly keres???s, majd pedig p???ld???ny k???pz???s a context
041         * ClassLoader seg???ts???g???vel.</p><p>
042         * Az implement???l??? oszt???ly n???v keres???se a <CODE>serviceId</CODE> nev???
043         * system property vizsg???lat???val kezd???dik. Amennyiben nincs ilyen
044         * property, ???gy a keres???s a
045         * <CODE>/META-INF/services/<I>serviceId</I></CODE> nev??? file tartalm???val
046         * folytat???dik. Amennyiben nincs ilyen nev??? file, ???gy a param???terk???nt ???tadott
047         * <CODE>defaultService</CODE> lesz az oszt???ly neve.</p><p>
048         * A fenti keres???st k???vet???en t???rt???nik a p???ld???ny k???pz???s. A visszat???r???si
049         * ???rt???k mindig egy val???di objektum, l???v???n minden hiba exception-t gener???l.
050         * @param <T> type
051         * @param clazz keresett oszt???ly/service neve
052         * @throws IllegalArgumentException keres???si vagy p???ld???nyos???t???si hiba eset???n
053         * @return a keresett oszt???ly implement???l??? objektum
054         */
055        public static <T> T findService(Class<T> clazz)
056        {
057            try
058            {
059    
060                // ez a cast nem lenne sz??ks??ges, de ??gy a ClassCastException csak a h??v??n??l j??n...
061                return clazz.cast(findServiceClass(clazz).newInstance());
062            }
063            catch (Exception x)
064            {
065                throw (IllegalArgumentException) new IllegalArgumentException("Provider " + clazz.getName() + " could not be instantiated: " + x)
066                  .initCause(x);
067            }
068        }
069    
070        @SuppressWarnings(Warnings.UNCHECKED)
071        static <T> Class<? extends T> findServiceClass(Class<T> clazz) throws IllegalArgumentException
072        {
073            ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
074            String serviceClassName = findServiceClassName(clazz.getName());
075            Class<T> ret = clazz;
076    
077            if (serviceClassName != null)
078            {
079                try
080                {
081                    ret = (Class<T>) ((classLoader == null) ? Class.forName(serviceClassName) : classLoader.loadClass(serviceClassName));
082                }
083                catch (ClassNotFoundException x)
084                {
085                    throw (IllegalArgumentException) new IllegalArgumentException("Provider " + serviceClassName + " not found").initCause(x);
086                }
087            }
088    
089            return ret;
090        }
091    
092        static String findServiceClassName(String serviceId) throws IllegalArgumentException
093        {
094            String serviceClassName = null;
095    
096            // Use the system property first
097            try
098            {
099                String systemProp = System.getProperty(serviceId);
100    
101                if (systemProp != null)
102                {
103                    serviceClassName = systemProp;
104                }
105            }
106            catch (SecurityException x)
107            {
108                assert true;
109            }
110    
111            if (serviceClassName == null)
112            {
113                serviceClassName = loadLine(SERVICES_PATH + serviceId);
114            }
115    
116            return serviceClassName;
117        }
118    
119        private static String loadLine(String servicePath)
120        {
121            String ret = null;
122    
123            // try to find services in CLASSPATH
124            try
125            {
126                InputStream is = null;
127                ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
128    
129                if (classLoader == null)
130                {
131                    is = ClassLoader.getSystemResourceAsStream(servicePath);
132                }
133                else
134                {
135                    is = classLoader.getResourceAsStream(servicePath);
136                }
137    
138                if (is != null)
139                {
140                    BufferedReader rd = new BufferedReader(new InputStreamReader(is, "UTF-8"));
141                    String line = rd.readLine();
142    
143                    rd.close();
144                    if (line != null)
145                    {
146                        line = line.trim();
147                        if (line.length() != 0)
148                        {
149                            ret = line.split("\\s|#")[0];
150                        }
151                    }
152                }
153            }
154            catch (Exception x)
155            {
156                assert true;
157            }
158    
159            return ret;
160        }
161    }