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.classes;
018
019 import java.net.URL;
020 import java.security.CodeSource;
021 import java.util.HashSet;
022 import java.util.Set;
023
024 import org.apache.commons.discovery.ResourceClass;
025 import org.apache.commons.discovery.ResourceClassDiscover;
026 import org.apache.commons.discovery.ResourceClassIterator;
027 import org.apache.commons.discovery.resource.ClassLoaders;
028 import org.apache.commons.logging.Log;
029 import org.apache.commons.logging.LogFactory;
030
031 /**
032 * The findResources() method will check every loader.
033 *
034 * @param <T> The SPI type
035 */
036 public class DiscoverClasses<T> extends ResourceClassDiscoverImpl<T> implements ResourceClassDiscover<T> {
037
038 private static Log log = LogFactory.getLog(DiscoverClasses.class);
039
040 /**
041 * Sets the {@code Log} for this class.
042 *
043 * @param _log This class {@code Log}
044 * @deprecated This method is not thread-safe
045 */
046 @Deprecated
047 public static void setLog(Log _log) {
048 log = _log;
049 }
050
051 /**
052 * Construct a new resource discoverer
053 */
054 public DiscoverClasses() {
055 super();
056 }
057
058 /**
059 * Construct a new resource discoverer.
060 *
061 * @param classLoaders The class loaders holder
062 */
063 public DiscoverClasses(ClassLoaders classLoaders) {
064 super(classLoaders);
065 }
066
067 /**
068 * {@inheritDoc}
069 */
070 @Override
071 public ResourceClassIterator<T> findResourceClasses(final String className) {
072 final String resourceName = className.replace('.','/') + ".class";
073
074 if (log.isDebugEnabled()) {
075 log.debug("find: className='" + className + "'");
076 }
077
078 return new ResourceClassIterator<T>() {
079
080 private final Set<URL> history = new HashSet<URL>();
081
082 private int idx = 0;
083
084 private ResourceClass<T> resource = null;
085
086 public boolean hasNext() {
087 if (resource == null) {
088 resource = getNextClass();
089 }
090 return resource != null;
091 }
092
093 @Override
094 public ResourceClass<T> nextResourceClass() {
095 ResourceClass<T> element = resource;
096 resource = null;
097 return element;
098 }
099
100 private ResourceClass<T> getNextClass() {
101 while (idx < getClassLoaders().size()) {
102 ClassLoader loader = getClassLoaders().get(idx++);
103
104 URL url = null;
105
106 try {
107 url = loader.getResource(resourceName);
108 } catch (UnsupportedOperationException e) {
109 // ignore
110 }
111
112 if (url == null) {
113 try {
114 CodeSource codeSource = loader.loadClass(className)
115 .getProtectionDomain()
116 .getCodeSource();
117 if (codeSource != null) {
118 url = new URL(codeSource.getLocation(), resourceName);
119 }
120 // else keep url null
121 } catch (Exception le) {
122 // keep url null
123 }
124 }
125
126 if (url != null) {
127 if (history.add(url)) {
128 if (log.isDebugEnabled()) {
129 log.debug("getNextClass: next URL='" + url + "'");
130 }
131
132 return new ResourceClass<T>(className, url, loader);
133 }
134 if (log.isDebugEnabled()) {
135 log.debug("getNextClass: duplicate URL='" + url + "'");
136 }
137 } else {
138 if (log.isDebugEnabled()) {
139 log.debug("getNextClass: loader " + loader + ": '" + resourceName + "' not found");
140 }
141 }
142 }
143 return null;
144 }
145 };
146 }
147
148 }