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.ArrayList;
024 import java.util.List;
025
026 import org.apache.commons.discovery.Resource;
027 import org.apache.commons.discovery.ResourceDiscover;
028 import org.apache.commons.discovery.ResourceIterator;
029 import org.apache.commons.discovery.ResourceNameDiscover;
030 import org.apache.commons.discovery.ResourceNameIterator;
031 import org.apache.commons.discovery.resource.ClassLoaders;
032 import org.apache.commons.discovery.resource.DiscoverResources;
033 import org.apache.commons.logging.Log;
034 import org.apache.commons.logging.LogFactory;
035
036 /**
037 * Discover ALL files of a given name, and return resource names
038 * contained within the set of files:
039 * <ul>
040 * <li>one resource name per line,</li>
041 * <li>whitespace ignored,</li>
042 * <li>comments begin with '#'</li>
043 * </ul>
044 *
045 * Default discoverer is DiscoverClassLoaderResources,
046 * but it can be set to any other.
047 */
048 public class DiscoverNamesInFile extends ResourceNameDiscoverImpl implements ResourceNameDiscover {
049
050 private static Log log = LogFactory.getLog(DiscoverNamesInFile.class);
051
052 /**
053 * Sets the {@code Log} for this class.
054 *
055 * @param _log This class {@code Log}
056 * @deprecated This method is not thread-safe
057 */
058 @Deprecated
059 public static void setLog(Log _log) {
060 log = _log;
061 }
062
063 private ResourceDiscover _discoverResources;
064
065 private final String _prefix;
066
067 private final String _suffix;
068
069 /**
070 * Construct a new resource discoverer.
071 */
072 public DiscoverNamesInFile() {
073 _discoverResources = new DiscoverResources();
074 _prefix = null;
075 _suffix = null;
076 }
077
078 /**
079 * Construct a new resource discoverer.
080 *
081 * @param prefix The resource name prefix
082 * @param suffix The resource name suffix
083 */
084 public DiscoverNamesInFile(String prefix, String suffix) {
085 _discoverResources = new DiscoverResources();
086 _prefix = prefix;
087 _suffix = suffix;
088 }
089
090 /**
091 * Construct a new resource discoverer.
092 *
093 * @param loaders The class loaders holder
094 */
095 public DiscoverNamesInFile(ClassLoaders loaders) {
096 _discoverResources = new DiscoverResources(loaders);
097 _prefix = null;
098 _suffix = null;
099 }
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 }