View Javadoc

1   /**
2    * Licensed under the Apache License, Version 2.0 (the "License");
3    * you may not use this file except in compliance with the License.
4    * You may obtain a copy of the License at
5    *
6    *   http://www.apache.org/licenses/LICENSE-2.0
7    *
8    * Unless required by applicable law or agreed to in writing, software
9    * distributed under the License is distributed on an "AS IS" BASIS,
10   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11   * See the License for the specific language governing permissions and
12   * limitations under the License. See accompanying LICENSE file.
13   */
14  package org.apache.hadoop.hbase.mapreduce.hadoopbackport;
15  
16  import com.google.common.base.Preconditions;
17  
18  import java.io.BufferedOutputStream;
19  import java.io.File;
20  import java.io.FileInputStream;
21  import java.io.FileOutputStream;
22  import java.io.IOException;
23  import java.io.InputStream;
24  import java.net.URL;
25  import java.net.URLDecoder;
26  import java.text.MessageFormat;
27  import java.util.Enumeration;
28  import java.util.jar.JarFile;
29  import java.util.jar.JarOutputStream;
30  import java.util.jar.Manifest;
31  import java.util.zip.ZipEntry;
32  import java.util.zip.ZipOutputStream;
33  
34  /**
35   * Finds the Jar for a class. If the class is in a directory in the
36   * classpath, it creates a Jar on the fly with the contents of the directory
37   * and returns the path to that Jar. If a Jar is created, it is created in
38   * the system temporary directory.
39   * 
40   * This file was forked from hadoop/common/branches/branch-2@1377176.
41   */
42  public class JarFinder {
43  
44    private static void copyToZipStream(InputStream is, ZipEntry entry,
45                                ZipOutputStream zos) throws IOException {
46      zos.putNextEntry(entry);
47      byte[] arr = new byte[4096];
48      int read = is.read(arr);
49      while (read > -1) {
50        zos.write(arr, 0, read);
51        read = is.read(arr);
52      }
53      is.close();
54      zos.closeEntry();
55    }
56  
57    public static void jarDir(File dir, String relativePath, ZipOutputStream zos)
58      throws IOException {
59      Preconditions.checkNotNull(relativePath, "relativePath");
60      Preconditions.checkNotNull(zos, "zos");
61  
62      // by JAR spec, if there is a manifest, it must be the first entry in the
63      // ZIP.
64      File manifestFile = new File(dir, JarFile.MANIFEST_NAME);
65      ZipEntry manifestEntry = new ZipEntry(JarFile.MANIFEST_NAME);
66      if (!manifestFile.exists()) {
67        zos.putNextEntry(manifestEntry);
68        new Manifest().write(new BufferedOutputStream(zos));
69        zos.closeEntry();
70      } else {
71        InputStream is = new FileInputStream(manifestFile);
72        copyToZipStream(is, manifestEntry, zos);
73      }
74      zos.closeEntry();
75      zipDir(dir, relativePath, zos, true);
76      zos.close();
77    }
78  
79    private static void zipDir(File dir, String relativePath, ZipOutputStream zos,
80                               boolean start) throws IOException {
81      String[] dirList = dir.list();
82      for (String aDirList : dirList) {
83        File f = new File(dir, aDirList);
84        if (!f.isHidden()) {
85          if (f.isDirectory()) {
86            if (!start) {
87              ZipEntry dirEntry = new ZipEntry(relativePath + f.getName() + "/");
88              zos.putNextEntry(dirEntry);
89              zos.closeEntry();
90            }
91            String filePath = f.getPath();
92            File file = new File(filePath);
93            zipDir(file, relativePath + f.getName() + "/", zos, false);
94          }
95          else {
96            String path = relativePath + f.getName();
97            if (!path.equals(JarFile.MANIFEST_NAME)) {
98              ZipEntry anEntry = new ZipEntry(path);
99              InputStream is = new FileInputStream(f);
100             copyToZipStream(is, anEntry, zos);
101           }
102         }
103       }
104     }
105   }
106 
107   private static void createJar(File dir, File jarFile) throws IOException {
108     Preconditions.checkNotNull(dir, "dir");
109     Preconditions.checkNotNull(jarFile, "jarFile");
110     File jarDir = jarFile.getParentFile();
111     if (!jarDir.exists()) {
112       if (!jarDir.mkdirs()) {
113         throw new IOException(MessageFormat.format("could not create dir [{0}]",
114                                                    jarDir));
115       }
116     }
117     JarOutputStream zos = new JarOutputStream(new FileOutputStream(jarFile));
118     jarDir(dir, "", zos);
119   }
120 
121   /**
122    * Returns the full path to the Jar containing the class. It always return a
123    * JAR.
124    *
125    * @param klass class.
126    *
127    * @return path to the Jar containing the class.
128    */
129   public static String getJar(Class klass) {
130     Preconditions.checkNotNull(klass, "klass");
131     ClassLoader loader = klass.getClassLoader();
132     if (loader != null) {
133       String class_file = klass.getName().replaceAll("\\.", "/") + ".class";
134       try {
135         for (Enumeration itr = loader.getResources(class_file);
136              itr.hasMoreElements(); ) {
137           URL url = (URL) itr.nextElement();
138           String path = url.getPath();
139           if (path.startsWith("file:")) {
140             path = path.substring("file:".length());
141           }
142           path = URLDecoder.decode(path, "UTF-8");
143           if ("jar".equals(url.getProtocol())) {
144             path = URLDecoder.decode(path, "UTF-8");
145             return path.replaceAll("!.*$", "");
146           }
147           else if ("file".equals(url.getProtocol())) {
148             String klassName = klass.getName();
149             klassName = klassName.replace(".", "/") + ".class";
150             path = path.substring(0, path.length() - klassName.length());
151             File baseDir = new File(path);
152             File testDir = new File(System.getProperty("test.build.dir", "target/test-dir"));
153             testDir = testDir.getAbsoluteFile();
154             if (!testDir.exists()) {
155               testDir.mkdirs();
156             }
157             File tempJar = File.createTempFile("hadoop-", "", testDir);
158             tempJar = new File(tempJar.getAbsolutePath() + ".jar");
159             createJar(baseDir, tempJar);
160             return tempJar.getAbsolutePath();
161           }
162         }
163       }
164       catch (IOException e) {
165         throw new RuntimeException(e);
166       }
167     }
168     return null;
169   }
170 }