001 /* 002 * Sonar, open source software quality management tool. 003 * Copyright (C) 2008-2012 SonarSource 004 * mailto:contact AT sonarsource DOT com 005 * 006 * Sonar is free software; you can redistribute it and/or 007 * modify it under the terms of the GNU Lesser General Public 008 * License as published by the Free Software Foundation; either 009 * version 3 of the License, or (at your option) any later version. 010 * 011 * Sonar is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 014 * Lesser General Public License for more details. 015 * 016 * You should have received a copy of the GNU Lesser General Public 017 * License along with Sonar; if not, write to the Free Software 018 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 019 */ 020 package org.sonar.server.plugins; 021 022 import com.google.common.base.*; 023 import com.google.common.collect.Lists; 024 import org.apache.commons.io.FileUtils; 025 import org.apache.commons.lang.CharEncoding; 026 import org.apache.commons.lang.StringUtils; 027 028 import javax.annotation.Nullable; 029 import java.io.File; 030 import java.io.IOException; 031 import java.net.URL; 032 import java.net.URLDecoder; 033 import java.util.Collection; 034 import java.util.Enumeration; 035 import java.util.jar.JarEntry; 036 import java.util.jar.JarFile; 037 038 /** 039 * @since 3.0 040 */ 041 public final class ClassLoaderUtils { 042 043 private ClassLoaderUtils() { 044 } 045 046 public static File copyResources(ClassLoader classLoader, String rootPath, File toDir) { 047 return copyResources(classLoader, rootPath, toDir, Functions.<String>identity()); 048 } 049 050 public static File copyResources(ClassLoader classLoader, String rootPath, File toDir, Function<String, String> relocationFunction) { 051 Collection<String> relativePaths = listFiles(classLoader, rootPath); 052 for (String relativePath : relativePaths) { 053 URL resource = classLoader.getResource(relativePath); 054 String filename = relocationFunction.apply(relativePath); 055 File toFile = new File(toDir, filename); 056 try { 057 FileUtils.copyURLToFile(resource, toFile); 058 } catch (IOException e) { 059 throw new IllegalStateException("Fail to extract " + relativePath + " to " + toFile.getAbsolutePath()); 060 } 061 } 062 063 return toDir; 064 } 065 066 /** 067 * Finds files within a given directory and its subdirectories 068 * 069 * @param classLoader 070 * @param rootPath the root directory, for example org/sonar/sqale 071 * @return a list of relative paths, for example {"org/sonar/sqale/foo/bar.txt}. Never null. 072 */ 073 public static Collection<String> listFiles(ClassLoader classLoader, String rootPath) { 074 return listResources(classLoader, rootPath, new Predicate<String>() { 075 public boolean apply(@Nullable String path) { 076 return !StringUtils.endsWith(path, "/"); 077 } 078 }); 079 } 080 081 082 public static Collection<String> listResources(ClassLoader classLoader, String rootPath) { 083 return listResources(classLoader, rootPath, Predicates.<String>alwaysTrue()); 084 } 085 086 /** 087 * Finds directories and files within a given directory and its subdirectories. 088 * 089 * @param classLoader 090 * @param rootPath the root directory, for example org/sonar/sqale, or a file in this root directory, for example org/sonar/sqale/index.txt 091 * @param 092 * @return a list of relative paths, for example {"org/sonar/sqale", "org/sonar/sqale/foo", "org/sonar/sqale/foo/bar.txt}. Never null. 093 */ 094 public static Collection<String> listResources(ClassLoader classLoader, String rootPath, Predicate<String> predicate) { 095 try { 096 Collection<String> paths = Lists.newArrayList(); 097 rootPath = StringUtils.removeStart(rootPath, "/"); 098 099 URL root = classLoader.getResource(rootPath); 100 if (root != null) { 101 checkJarFile(root); 102 103 // Path of the root directory 104 // Examples : 105 // org/sonar/sqale/index.txt -> rootDirectory is org/sonar/sqale 106 // org/sonar/sqale/ -> rootDirectory is org/sonar/sqale 107 // org/sonar/sqale -> rootDirectory is org/sonar/sqale 108 String rootDirectory = rootPath; 109 if (StringUtils.substringAfterLast(rootPath, "/").indexOf('.') >= 0) { 110 rootDirectory = StringUtils.substringBeforeLast(rootPath, "/"); 111 } 112 String jarPath = root.getPath().substring(5, root.getPath().indexOf("!")); //strip out only the JAR file 113 JarFile jar = new JarFile(URLDecoder.decode(jarPath, CharEncoding.UTF_8)); 114 Enumeration<JarEntry> entries = jar.entries(); 115 while (entries.hasMoreElements()) { 116 String name = entries.nextElement().getName(); 117 if (name.startsWith(rootDirectory) && predicate.apply(name)) { 118 paths.add(name); 119 } 120 } 121 } 122 return paths; 123 } catch (Exception e) { 124 throw Throwables.propagate(e); 125 } 126 } 127 128 private static void checkJarFile(URL root) { 129 if (!"jar".equals(root.getProtocol())) { 130 throw new IllegalStateException("Unsupported protocol: " + root.getProtocol()); 131 } 132 } 133 }