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    }