001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     *
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    package org.apache.commons.discovery.resource.names;
018    
019    import java.io.BufferedReader;
020    import java.io.IOException;
021    import java.io.InputStream;
022    import java.io.InputStreamReader;
023    import java.util.Vector;
024    
025    import org.apache.commons.discovery.Resource;
026    import org.apache.commons.discovery.ResourceDiscover;
027    import org.apache.commons.discovery.ResourceIterator;
028    import org.apache.commons.discovery.ResourceNameDiscover;
029    import org.apache.commons.discovery.ResourceNameIterator;
030    import org.apache.commons.discovery.log.DiscoveryLogFactory;
031    import org.apache.commons.discovery.resource.ClassLoaders;
032    import org.apache.commons.discovery.resource.DiscoverResources;
033    import org.apache.commons.logging.Log;
034    
035    
036    
037    /**
038     * Discover ALL files of a given name, and return resource names
039     * contained within the set of files:
040     * <ul>
041     *   <li>one resource name per line,</li>
042     *   <li>whitespace ignored,</li>
043     *   <li>comments begin with '#'</li>
044     * </ul>
045     * 
046     * Default discoverer is DiscoverClassLoaderResources,
047     * but it can be set to any other.
048     *
049     * @author Richard A. Sitze
050     * @author Costin Manolache
051     * @author James Strachan
052     */
053    public class DiscoverNamesInFile
054        extends ResourceNameDiscoverImpl
055        implements ResourceNameDiscover
056    {
057        private static Log log = DiscoveryLogFactory.newLog(DiscoverNamesInFile.class);
058        public static void setLog(Log _log) {
059            log = _log;
060        }
061        
062        private ResourceDiscover _discoverResources;
063        
064        private final String _prefix;
065        private final String _suffix;
066            
067        /**
068         *  Construct a new resource discoverer
069         */
070        public DiscoverNamesInFile() {
071            _discoverResources = new DiscoverResources();
072            _prefix = null;
073            _suffix = null;
074        }
075            
076        /**
077         *  Construct a new resource discoverer
078         */
079        public DiscoverNamesInFile(String prefix, String suffix) {
080            _discoverResources = new DiscoverResources();
081            _prefix = prefix;
082            _suffix = suffix;
083        }
084        
085        /**
086         *  Construct a new resource discoverer
087         */
088        public DiscoverNamesInFile(ClassLoaders loaders) {
089            _discoverResources = new DiscoverResources(loaders);
090            _prefix = null;
091            _suffix = null;
092        }
093        
094        /**
095         *  Construct a new resource discoverer
096         */
097        public DiscoverNamesInFile(ClassLoaders loaders, String prefix, String suffix) {
098            _discoverResources = new DiscoverResources(loaders);
099            _prefix = prefix;
100            _suffix = suffix;
101        }
102        
103        /**
104         *  Construct a new resource discoverer
105         */
106        public DiscoverNamesInFile(ResourceDiscover discoverer) {
107            _discoverResources = discoverer;
108            _prefix = null;
109            _suffix = null;
110        }
111        
112        /**
113         *  Construct a new resource discoverer
114         */
115        public DiscoverNamesInFile(ResourceDiscover discoverer, String prefix, String suffix) {
116            _discoverResources = discoverer;
117            _prefix = prefix;
118            _suffix = suffix;
119        }
120    
121        /**
122         * Specify set of class loaders to be used in searching.
123         */
124        public void setDiscoverer(ResourceDiscover discover) {
125            _discoverResources = discover;
126        }
127    
128        /**
129         * To be used by downstream elements..
130         */
131        public ResourceDiscover getDiscover() {
132            return _discoverResources;
133        }
134    
135        /**
136         * @return Enumeration of ServiceInfo
137         */
138        public ResourceNameIterator findResourceNames(final String serviceName) {
139            String fileName;
140            if (_prefix != null && _prefix.length() > 0) {
141                fileName = _prefix + serviceName;
142            } else {
143                fileName = serviceName;
144            }
145    
146            if (_suffix != null && _suffix.length() > 0) {
147                fileName = fileName + _suffix;
148            }
149    
150            if (log.isDebugEnabled()) {
151                if (_prefix != null  &&  _suffix != null) {
152                    log.debug("find: serviceName='" + serviceName + "' as '" + fileName + "'");
153                } else {
154                    log.debug("find: serviceName = '" + fileName + "'");
155                }
156            }
157    
158    
159            final ResourceIterator files =
160                getDiscover().findResources(fileName);
161    
162            return new ResourceNameIterator() {
163                private int idx = 0;
164                private Vector classNames = null;
165                private String resource = null;
166                
167                public boolean hasNext() {
168                    if (resource == null) {
169                        resource = getNextClassName();
170                    }
171                    return resource != null;
172                }
173                
174                public String nextResourceName() {
175                    String element = resource;
176                    resource = null;
177                    return element;
178                }
179                
180                private String getNextClassName() {
181                    if (classNames == null || idx >= classNames.size()) {
182                        classNames = getNextClassNames();
183                        idx = 0;
184                        if (classNames == null) {
185                            return null;
186                        }
187                    }
188    
189                    String className = (String)classNames.get(idx++);
190    
191                    if (log.isDebugEnabled())
192                        log.debug("getNextClassResource: next class='" + className + "'");
193    
194                    return className;
195                }
196    
197                private Vector getNextClassNames() {
198                    while (files.hasNext()) {
199                        Vector results = readServices(files.nextResource());
200                        if (results != null  &&  results.size() > 0) {
201                            return results;
202                        }
203                    }
204                    return null;
205                }
206            };
207        }
208    
209        /**
210         * Read everything, no defering here..
211         * Ensure that files are closed before we leave.
212         */
213        private Vector readServices(final Resource info) {
214            Vector results = new Vector();
215            
216            InputStream is = info.getResourceAsStream();
217            
218            if( is != null ) {
219                try {
220                    try {
221                        // This code is needed by EBCDIC and other
222                        // strange systems.  It's a fix for bugs
223                        // reported in xerces
224                        BufferedReader rd;
225                        try {
226                            rd = new BufferedReader(new InputStreamReader(is, "UTF-8"));
227                        } catch (java.io.UnsupportedEncodingException e) {
228                            rd = new BufferedReader(new InputStreamReader(is));
229                        }
230                        
231                        try {
232                            String serviceImplName;
233                            while( (serviceImplName = rd.readLine()) != null) {
234                                int idx = serviceImplName.indexOf('#');
235                                if (idx >= 0) {
236                                    serviceImplName = serviceImplName.substring(0, idx);
237                                }
238                                serviceImplName = serviceImplName.trim();
239        
240                                if (serviceImplName.length() != 0) {
241                                    results.add(serviceImplName);
242                                }
243                            }
244                        } finally {
245                            rd.close();
246                        }
247                    } finally {
248                        is.close();
249                    }
250                } catch (IOException e) {
251                    // ignore
252                }
253            }
254            
255            return results;
256        }
257    }