001 /* 002 * Licensed under the Apache License, Version 2.0 (the "License"); 003 * you may not use this file except in compliance with the License. 004 * You may obtain a copy of the License at 005 * 006 * http://www.apache.org/licenses/LICENSE-2.0 007 * 008 * Unless required by applicable law or agreed to in writing, software 009 * distributed under the License is distributed on an "AS IS" BASIS, 010 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 011 * See the License for the specific language governing permissions and 012 * limitations under the License. 013 */ 014 package org.apache.commons.classscan.builtin; 015 016 import java.io.IOException; 017 import java.io.InputStream; 018 import java.net.URL; 019 import java.util.Map; 020 import java.util.ServiceConfigurationError; 021 022 import org.apache.commons.classscan.ClassPathElement; 023 import org.apache.commons.classscan.MetaClassLoader; 024 import org.apache.commons.classscan.MetaClassPathElement; 025 import org.apache.commons.classscan.spi.ClassDigesterFactory; 026 import org.apache.commons.classscan.spi.ClassPathElementFactory; 027 import org.apache.commons.classscan.spi.ClassPathFactory; 028 import org.apache.commons.classscan.spi.model.SpiClassDigester; 029 import org.apache.commons.classscan.spi.model.SpiClassPath; 030 import org.apache.commons.classscan.spi.model.SpiClassPathElement; 031 import org.apache.commons.classscan.spi.model.SpiMetaClass; 032 import org.apache.commons.classscan.spi.model.SpiMetaClassPathElement; 033 import org.apache.commons.classscan.spi.model.SpiMetaRegistry; 034 import org.apache.commons.classscan.util.FactoryCache; 035 import org.apache.commons.classscan.util.ReapingHashMap; 036 import org.apache.commons.classscan.util.ServiceVisitor; 037 import org.slf4j.Logger; 038 import org.slf4j.LoggerFactory; 039 040 /** 041 * The factory for MetaClassLoaders. Wherever possible, an existing 042 * MetaClassLoader is returned for a ClassLoader. The implementation should not 043 * prevent the garbage collection of a ClassLoader. 044 */ 045 public class DefaultMetaRegistry implements SpiMetaRegistry { 046 047 private static final Logger logger = LoggerFactory.getLogger(DefaultMetaRegistry.class); 048 049 private final Map<ClassLoader, MetaClassLoader> metaClassLoaders; 050 private final FactoryCache<ClassPathFactory> classPathFactories; 051 private final FactoryCache<ClassPathElementFactory> classPathElementFactories; 052 private SpiClassDigester classDigester; 053 054 public DefaultMetaRegistry() { 055 metaClassLoaders = new ReapingHashMap<ClassLoader, MetaClassLoader>(); 056 ClassLoader classLoader = getClass().getClassLoader(); 057 classPathFactories = new FactoryCache<ClassPathFactory>(ClassPathFactory.class, classLoader); 058 classPathElementFactories = new FactoryCache<ClassPathElementFactory>(ClassPathElementFactory.class, classLoader); 059 060 findClassDigester(classLoader); 061 } 062 063 private void findClassDigester(ClassLoader classLoader) { 064 new ServiceVisitor<ClassDigesterFactory>() { 065 @Override 066 protected boolean visit(ClassDigesterFactory factory) { 067 try { 068 classDigester= factory.createDigester(DefaultMetaRegistry.this); 069 return false; 070 } 071 catch(Throwable error) { 072 logger.warn("Ignoring configuration error", error); 073 return true; 074 } 075 } 076 }.visitProviders(ClassDigesterFactory.class, classLoader); 077 078 if(classDigester==null) { 079 throw new ServiceConfigurationError("Could not load a ClassDigester"); 080 } 081 } 082 083 @Override 084 public MetaClassLoader getMetaClassLoader(ClassLoader classLoader) { 085 synchronized(metaClassLoaders) { 086 MetaClassLoader mcl = metaClassLoaders.get(classLoader); 087 if (mcl == null) { 088 mcl = createMetaClassLoader(classLoader); 089 metaClassLoaders.put(classLoader, mcl); 090 } 091 return mcl; 092 } 093 } 094 095 public MetaClassLoader createMetaClassLoader(ClassLoader classLoader) { 096 SpiClassPath cp= getClassPath(classLoader); 097 return cp.createMetaClassLoader(this, classLoader); 098 } 099 100 @Override 101 public SpiClassPath getClassPath(ClassLoader classLoader) { 102 103 for(ClassPathFactory factory : classPathFactories) { 104 SpiClassPath cp= factory.getClassPath(this, classLoader); 105 if(cp!=null) { 106 return cp; 107 } 108 } 109 110 throw new IllegalArgumentException("No ClassPathFactory found for ClassLoader "+classLoader); 111 } 112 113 @Override 114 public SpiClassPathElement createClassPathElement(URL url) throws IOException { 115 116 for(ClassPathElementFactory factory : classPathElementFactories) { 117 SpiClassPathElement cp= factory.getClassPathElement(this, url); 118 if(cp!=null) { 119 return cp; 120 } 121 } 122 123 return null; 124 } 125 126 @Override 127 public SpiMetaClassPathElement createMetaClassPathElement(ClassPathElement pathElement) { 128 return new DefaultMetaClassPathElement(this, pathElement); 129 } 130 131 @Override 132 public SpiMetaClass createMetaClass(MetaClassPathElement location, String className, InputStream byteStream) throws IOException { 133 try { 134 SpiMetaClass smc = classDigester.createMetaClass(location, className, byteStream); 135 if (!className.equals(smc.getName())) { 136 throw new IllegalArgumentException("Expecting classname " + className + " but found " + smc.getName()); 137 } 138 return smc; 139 } 140 finally { 141 byteStream.close(); 142 } 143 } 144 }