View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.discovery.resource.names;
18  
19  import java.io.BufferedReader;
20  import java.io.IOException;
21  import java.io.InputStream;
22  import java.io.InputStreamReader;
23  import java.util.ArrayList;
24  import java.util.List;
25  
26  import org.apache.commons.discovery.Resource;
27  import org.apache.commons.discovery.ResourceDiscover;
28  import org.apache.commons.discovery.ResourceIterator;
29  import org.apache.commons.discovery.ResourceNameDiscover;
30  import org.apache.commons.discovery.ResourceNameIterator;
31  import org.apache.commons.discovery.resource.ClassLoaders;
32  import org.apache.commons.discovery.resource.DiscoverResources;
33  import org.apache.commons.logging.Log;
34  import org.apache.commons.logging.LogFactory;
35  
36  /**
37   * Discover ALL files of a given name, and return resource names
38   * contained within the set of files:
39   * <ul>
40   *   <li>one resource name per line,</li>
41   *   <li>whitespace ignored,</li>
42   *   <li>comments begin with '#'</li>
43   * </ul>
44   *
45   * Default discoverer is DiscoverClassLoaderResources,
46   * but it can be set to any other.
47   */
48  public class DiscoverNamesInFile extends ResourceNameDiscoverImpl implements ResourceNameDiscover {
49  
50      private static Log log = LogFactory.getLog(DiscoverNamesInFile.class);
51  
52      /**
53       * Sets the {@code Log} for this class.
54       *
55       * @param _log This class {@code Log}
56       * @deprecated This method is not thread-safe
57       */
58      @Deprecated
59      public static void setLog(Log _log) {
60          log = _log;
61      }
62  
63      private ResourceDiscover _discoverResources;
64  
65      private final String _prefix;
66  
67      private final String _suffix;
68  
69      /**
70       * Construct a new resource discoverer.
71       */
72      public DiscoverNamesInFile() {
73          _discoverResources = new DiscoverResources();
74          _prefix = null;
75          _suffix = null;
76      }
77  
78      /**
79       * Construct a new resource discoverer.
80       *
81       * @param prefix The resource name prefix
82       * @param suffix The resource name suffix
83       */
84      public DiscoverNamesInFile(String prefix, String suffix) {
85          _discoverResources = new DiscoverResources();
86          _prefix = prefix;
87          _suffix = suffix;
88      }
89  
90      /**
91       * Construct a new resource discoverer.
92       *
93       * @param loaders The class loaders holder
94       */
95      public DiscoverNamesInFile(ClassLoaders loaders) {
96          _discoverResources = new DiscoverResources(loaders);
97          _prefix = null;
98          _suffix = null;
99      }
100 
101     /**
102      * Construct a new resource discoverer.
103      *
104      * @param loaders The class loaders holder
105      * @param prefix The resource name prefix
106      * @param suffix The resource name suffix
107      */
108     public DiscoverNamesInFile(ClassLoaders loaders, String prefix, String suffix) {
109         _discoverResources = new DiscoverResources(loaders);
110         _prefix = prefix;
111         _suffix = suffix;
112     }
113 
114     /**
115      * Construct a new resource discoverer.
116      *
117      * @param discoverer The discoverer to resolve resources
118      */
119     public DiscoverNamesInFile(ResourceDiscover discoverer) {
120         _discoverResources = discoverer;
121         _prefix = null;
122         _suffix = null;
123     }
124 
125     /**
126      * Construct a new resource discoverer.
127      *
128      * @param discoverer The discoverer to resolve resources
129      * @param prefix The resource name prefix
130      * @param suffix The resource name suffix
131      */
132     public DiscoverNamesInFile(ResourceDiscover discoverer, String prefix, String suffix) {
133         _discoverResources = discoverer;
134         _prefix = prefix;
135         _suffix = suffix;
136     }
137 
138     /**
139      * Set the discoverer to resolve resources.
140      *
141      * @param discover The discoverer to resolve resources
142      */
143     public void setDiscoverer(ResourceDiscover discover) {
144         _discoverResources = discover;
145     }
146 
147     /**
148      * Return the discoverer to resolve resources.
149      *
150      * To be used by downstream elements...
151      *
152      * @return The discoverer to resolve resources
153      */
154     public ResourceDiscover getDiscover() {
155         return _discoverResources;
156     }
157 
158     /**
159      * {@inheritDoc}
160      */
161     @Override
162     public ResourceNameIterator findResourceNames(final String serviceName) {
163         String fileName;
164         if (_prefix != null && _prefix.length() > 0) {
165             fileName = _prefix + serviceName;
166         } else {
167             fileName = serviceName;
168         }
169 
170         if (_suffix != null && _suffix.length() > 0) {
171             fileName = fileName + _suffix;
172         }
173 
174         if (log.isDebugEnabled()) {
175             if (_prefix != null  &&  _suffix != null) {
176                 log.debug("find: serviceName='" + serviceName + "' as '" + fileName + "'");
177             } else {
178                 log.debug("find: serviceName = '" + fileName + "'");
179             }
180         }
181 
182 
183         final ResourceIterator files =
184             getDiscover().findResources(fileName);
185 
186         return new ResourceNameIterator() {
187 
188             private int idx = 0;
189 
190             private List<String> classNames = null;
191 
192             private String resource = null;
193 
194             public boolean hasNext() {
195                 if (resource == null) {
196                     resource = getNextClassName();
197                 }
198                 return resource != null;
199             }
200 
201             public String nextResourceName() {
202                 String element = resource;
203                 resource = null;
204                 return element;
205             }
206 
207             private String getNextClassName() {
208                 if (classNames == null || idx >= classNames.size()) {
209                     classNames = getNextClassNames();
210                     idx = 0;
211                     if (classNames == null) {
212                         return null;
213                     }
214                 }
215 
216                 String className = classNames.get(idx++);
217 
218                 if (log.isDebugEnabled()) {
219                     log.debug("getNextClassResource: next class='" + className + "'");
220                 }
221 
222                 return className;
223             }
224 
225             private List<String> getNextClassNames() {
226                 while (files.hasNext()) {
227                     List<String> results = readServices(files.nextResource());
228                     if (results != null  &&  results.size() > 0) {
229                         return results;
230                     }
231                 }
232                 return null;
233             }
234         };
235     }
236 
237     /**
238      * Parses the resource info file and store all the defined SPI implementation classes
239      *
240      * @param info The resource file
241      * @return The list with all SPI implementation names
242      */
243     private List<String> readServices(final Resource info) {
244         List<String> results = new ArrayList<String>();
245 
246         InputStream is = info.getResourceAsStream();
247 
248         if (is != null) {
249             try {
250                 try {
251                     // This code is needed by EBCDIC and other
252                     // strange systems.  It's a fix for bugs
253                     // reported in xerces
254                     BufferedReader rd;
255                     try {
256                         rd = new BufferedReader(new InputStreamReader(is, "UTF-8"));
257                     } catch (java.io.UnsupportedEncodingException e) {
258                         rd = new BufferedReader(new InputStreamReader(is));
259                     }
260 
261                     try {
262                         String serviceImplName;
263                         while( (serviceImplName = rd.readLine()) != null) {
264                             int idx = serviceImplName.indexOf('#');
265                             if (idx >= 0) {
266                                 serviceImplName = serviceImplName.substring(0, idx);
267                             }
268                             serviceImplName = serviceImplName.trim();
269 
270                             if (serviceImplName.length() != 0) {
271                                 results.add(serviceImplName);
272                             }
273                         }
274                     } finally {
275                         rd.close();
276                     }
277                 } finally {
278                     is.close();
279                 }
280             } catch (IOException e) {
281                 // ignore
282             }
283         }
284 
285         return results;
286     }
287 
288 }