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(File file, ZipEntry entry,
45                                ZipOutputStream zos) throws IOException {
46      InputStream is = new FileInputStream(file);
47      try {
48        zos.putNextEntry(entry);
49        byte[] arr = new byte[4096];
50        int read = is.read(arr);
51        while (read > -1) {
52          zos.write(arr, 0, read);
53          read = is.read(arr);
54        }
55      } finally {
56        try {
57          is.close();
58        } finally {
59          zos.closeEntry();
60        }
61      }
62    }
63  
64    public static void jarDir(File dir, String relativePath, ZipOutputStream zos)
65      throws IOException {
66      Preconditions.checkNotNull(relativePath, "relativePath");
67      Preconditions.checkNotNull(zos, "zos");
68  
69      // by JAR spec, if there is a manifest, it must be the first entry in the
70      // ZIP.
71      File manifestFile = new File(dir, JarFile.MANIFEST_NAME);
72      ZipEntry manifestEntry = new ZipEntry(JarFile.MANIFEST_NAME);
73      if (!manifestFile.exists()) {
74        zos.putNextEntry(manifestEntry);
75        new Manifest().write(new BufferedOutputStream(zos));
76        zos.closeEntry();
77      } else {
78        copyToZipStream(manifestFile, manifestEntry, zos);
79      }
80      zos.closeEntry();
81      zipDir(dir, relativePath, zos, true);
82      zos.close();
83    }
84  
85    private static void zipDir(File dir, String relativePath, ZipOutputStream zos,
86                               boolean start) throws IOException {
87      String[] dirList = dir.list();
88      for (String aDirList : dirList) {
89        File f = new File(dir, aDirList);
90        if (!f.isHidden()) {
91          if (f.isDirectory()) {
92            if (!start) {
93              ZipEntry dirEntry = new ZipEntry(relativePath + f.getName() + "/");
94              zos.putNextEntry(dirEntry);
95              zos.closeEntry();
96            }
97            String filePath = f.getPath();
98            File file = new File(filePath);
99            zipDir(file, relativePath + f.getName() + "/", zos, false);
100         }
101         else {
102           String path = relativePath + f.getName();
103           if (!path.equals(JarFile.MANIFEST_NAME)) {
104             ZipEntry anEntry = new ZipEntry(path);
105             copyToZipStream(f, anEntry, zos);
106           }
107         }
108       }
109     }
110   }
111 
112   private static void createJar(File dir, File jarFile) throws IOException {
113     Preconditions.checkNotNull(dir, "dir");
114     Preconditions.checkNotNull(jarFile, "jarFile");
115     File jarDir = jarFile.getParentFile();
116     if (!jarDir.exists()) {
117       if (!jarDir.mkdirs()) {
118         throw new IOException(MessageFormat.format("could not create dir [{0}]",
119                                                    jarDir));
120       }
121     }
122     JarOutputStream zos = new JarOutputStream(new FileOutputStream(jarFile));
123     jarDir(dir, "", zos);
124   }
125 
126   /**
127    * Returns the full path to the Jar containing the class. It always return a
128    * JAR.
129    *
130    * @param klass class.
131    *
132    * @return path to the Jar containing the class.
133    */
134   public static String getJar(Class klass) {
135     Preconditions.checkNotNull(klass, "klass");
136     ClassLoader loader = klass.getClassLoader();
137     if (loader != null) {
138       String class_file = klass.getName().replaceAll("\\.", "/") + ".class";
139       try {
140         for (Enumeration itr = loader.getResources(class_file);
141              itr.hasMoreElements(); ) {
142           URL url = (URL) itr.nextElement();
143           String path = url.getPath();
144           if (path.startsWith("file:")) {
145             path = path.substring("file:".length());
146           }
147           path = URLDecoder.decode(path, "UTF-8");
148           if ("jar".equals(url.getProtocol())) {
149             path = URLDecoder.decode(path, "UTF-8");
150             return path.replaceAll("!.*$", "");
151           }
152           else if ("file".equals(url.getProtocol())) {
153             String klassName = klass.getName();
154             klassName = klassName.replace(".", "/") + ".class";
155             path = path.substring(0, path.length() - klassName.length());
156             File baseDir = new File(path);
157             File testDir = new File(System.getProperty("test.build.dir", "target/test-dir"));
158             testDir = testDir.getAbsoluteFile();
159             if (!testDir.exists()) {
160               testDir.mkdirs();
161             }
162             File tempJar = File.createTempFile("hadoop-", "", testDir);
163             tempJar = new File(tempJar.getAbsolutePath() + ".jar");
164             createJar(baseDir, tempJar);
165             return tempJar.getAbsolutePath();
166           }
167         }
168       }
169       catch (IOException e) {
170         throw new RuntimeException(e);
171       }
172     }
173     return null;
174   }
175 }