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 }