/******************************************************************************* * Copyright (c) 2006-2010 eBay Inc. All Rights Reserved. * Licensed 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 *******************************************************************************/ package org.ebayopensource.turmeric.tools.codegen.util; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.util.Enumeration; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; import org.ebayopensource.turmeric.tools.codegen.exception.CodeGenFailedException; import edu.emory.mathcs.backport.java.util.Collections; /** * Utility methods for working with the {@link Thread#getContextClassLoader()} in a consistent fashion. */ public class ContextClassLoaderUtil { private final static Logger LOG = Logger.getLogger(ContextClassLoaderUtil.class.getName()); /** * Return the InputStream of the resource provided, following the {@link #findResource(String)} rules. * * @param path * the resource to find. * @return the {@link InputStream} to the resource, or null if not found. * @throws IOException * if unable to open the {@link InputStream}. * @see {@link URL#openStream()} */ public static InputStream getResourceAsStream(String path) throws IOException { ClassLoader cl = Thread.currentThread().getContextClassLoader(); return cl.getResourceAsStream(path); } /** * Look for a single resource in the classloader. * <p> * Logic on what is returned. * <ol> * <li>If one resource match is found, return it.</li> * <li>If more than one is found, return the project local version.</li> * <li>Return first hit</li> * </ol> * * @param path * the path to look for * @return the URL of the found resource, following the rules above. */ public static URL findResource(String path) { LOG.info("Attempting to find resource: " + path); ClassLoader cl = Thread.currentThread().getContextClassLoader(); try { Enumeration<URL> hits = cl.getResources(path); if (!hits.hasMoreElements()) { LOG.info("Resource does not exist: " + path); return null; // no hits } @SuppressWarnings("unchecked") List<URL> urls = Collections.list(hits); if (urls.size() > 1) { // Local always takes precedence. URL local = null; LOG.warning(path + " (MORE THAN 1 FOUND)"); for (URL url : urls) { LOG.warning(path + " = " + url); if (url.getProtocol().equals("file")) { local = url; } } // Return local hit (if found) if (local != null) { LOG.info(path + " RETURNING LOCAL at " + local.toExternalForm()); return local; } } URL url = urls.get(0); LOG.info(path + " FOUND at " + url.toExternalForm()); return url; } catch (IOException e) { LOG.log(Level.INFO, "findResource: " + path, e); } return null; } /** * Load a class from the context class loader. * * @param fullyQualifiedClassName * the class to load from the context classloader. * @return the loaded class. * @throws ClassNotFoundException * if unable to find the class. * @see #loadOptionalClass(String) */ public static Class<?> loadClass(String fullyQualifiedClassName) throws ClassNotFoundException { LOG.fine("Attempting to load class: " + fullyQualifiedClassName); ClassLoader cl = Thread.currentThread().getContextClassLoader(); return cl.loadClass(fullyQualifiedClassName); } /** * Similar to {@link #loadClass(String)} but doesn't throw a {@link ClassNotFoundException} if unable to find the * class, just returns null (to make logic easier to code against). * <p> * Emits a log message on {@link ClassNotFoundException} at {@link Level#FINE} level. * * @param fullyQualifiedClassName * the classname to load. * @return the class, or null if not found. */ public static Class<?> loadOptionalClass(String fullyQualifiedClassName) { LOG.fine("Attempting to load optional class: " + fullyQualifiedClassName); ClassLoader cl = Thread.currentThread().getContextClassLoader(); try { return cl.loadClass(fullyQualifiedClassName); } catch (ClassNotFoundException e) { LOG.log(Level.FINE, "Unable to find class: " + fullyQualifiedClassName, e); return null; } } /** * Similar to {@link #loadOptionalClass(String)} but throws a {@link ClassNotFoundException} if unable to find the * class * * @param fullyQualifiedClassName * the classname to load. * @return the class * @throws CodeGenFailedException * if unable to find the required class */ public static Class<?> loadRequiredClass(String fullyQualifiedClassName) throws CodeGenFailedException { LOG.fine("Attempting to load required class: " + fullyQualifiedClassName); ClassLoader cl = Thread.currentThread().getContextClassLoader(); try { return cl.loadClass(fullyQualifiedClassName); } catch (ClassNotFoundException e) { throw new CodeGenFailedException("Failed to load class : " + fullyQualifiedClassName, e); } } }