/** * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.manifoldcf.core.system; import org.apache.manifoldcf.core.interfaces.*; import java.net.URL; import java.net.URLClassLoader; import java.net.MalformedURLException; import java.util.*; import java.io.*; /** An instance of this class is capable of minting URLClassLoader objects on * demand, for the purpose of loading plugins. */ public class ManifoldCFResourceLoader { public static final String _rcsid = "@(#)$Id: ManifoldCFResourceLoader.java 988245 2010-08-23 18:39:35Z kwright $"; /** The parent class loader */ protected ClassLoader parent; /** The class loader we're caching */ protected ClassLoader classLoader = null; /** The current 'classpath' - a list of File objects */ protected ArrayList currentClasspath = new ArrayList(); /** Construct a resource manager. *@param parent is the parent class loader. */ public ManifoldCFResourceLoader(ClassLoader parent) throws ManifoldCFException { this.parent = parent; } /** Set the classpath to a given list of libdirs. *@param libdirList is an arraylist of File objects, each representing a directory. */ public synchronized void setClassPath(ArrayList libdirList) throws ManifoldCFException { if (currentClasspath.size() > 0) { currentClasspath.clear(); classLoader = null; } int i = 0; while (i < libdirList.size()) { File dir = (File)libdirList.get(i++); addToClassPath(dir,null); } } /** Clear the class-search path. */ public synchronized void clearClassPath() { if (currentClasspath.size() == 0) return; currentClasspath.clear(); classLoader = null; } /** Add to the class-search path. *@param file is the jar or class root. */ public synchronized void addToClassPath(final File file) throws ManifoldCFException { if (file.canRead()) { addDirsToClassPath(new File[]{file.getParentFile()}, new FileFilter[]{new FileFilter() { public boolean accept(final File pathname) { return pathname.equals(file); } } } ); } else throw new ManifoldCFException("Path '"+file.toString()+"' does not exist or is not readable"); } /** Add to the class-search path. *@param dir is the directory to add. *@param filter is the file filter to use on that directory. */ public synchronized void addToClassPath(File dir, FileFilter filter) throws ManifoldCFException { addDirsToClassPath(new File[]{dir}, new FileFilter[]{filter}); } /** Get the class loader representing this resource loader. */ public synchronized ClassLoader getClassLoader() throws ManifoldCFException { if (classLoader == null) { // Mint a class loader on demand if (currentClasspath.size() == 0) classLoader = parent; else { URL[] elements = new URL[currentClasspath.size()]; for (int j = 0; j < currentClasspath.size(); j++) { try { URL element = ((File)currentClasspath.get(j)).toURI().normalize().toURL(); elements[j] = element; } catch (MalformedURLException e) { // Should never happen, but... throw new ManifoldCFException(e.getMessage(),e); } } classLoader = URLClassLoader.newInstance(elements, parent); } } return classLoader; } /** Get the specified class using the proper classloader. *@param cname is the fully-qualified class name. */ public Class findClass(String cname) throws ClassNotFoundException,ManifoldCFException { // If we ever get this far, we have a classloader at least... return Class.forName(cname,true,getClassLoader()); } /** Add fully-resolved directories (with filters) to the current class path. *@param baseList is the list of library directories. *@param filterList is the corresponding list of filters. */ protected void addDirsToClassPath(File[] baseList, FileFilter[] filterList) throws ManifoldCFException { int i = 0; while (i < baseList.length) { File base = baseList[i]; FileFilter filter; if (filterList != null) filter = filterList[i]; else filter = null; if (base.canRead() && base.isDirectory()) { File[] files = base.listFiles(filter); if (files != null && files.length > 0) { int j = 0; while (j < files.length) { File file = files[j++]; currentClasspath.add(file); // Invalidate the current classloader classLoader = null; } } } else throw new ManifoldCFException("Supposed directory '"+base.toString()+"' is either not a directory, or is unreadable."); i++; } } }