org.apache.hadoop.hbase.util.ClassLoaderTestHelper.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.hadoop.hbase.util.ClassLoaderTestHelper.java

Source

/**
 * 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.hadoop.hbase.util;

import static org.junit.Assert.assertTrue;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarOutputStream;
import java.util.jar.Manifest;

import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;

/**
 * Some utilities to help class loader testing
 */
public class ClassLoaderTestHelper {
    private static final Log LOG = LogFactory.getLog(ClassLoaderTestHelper.class);

    private static final int BUFFER_SIZE = 4096;

    /**
     * Jar a list of files into a jar archive.
     *
     * @param archiveFile the target jar archive
     * @param tobejared a list of files to be jared
     */
    private static boolean createJarArchive(File archiveFile, File[] tobeJared) {
        try {
            byte buffer[] = new byte[BUFFER_SIZE];
            // Open archive file
            FileOutputStream stream = new FileOutputStream(archiveFile);
            JarOutputStream out = new JarOutputStream(stream, new Manifest());

            for (int i = 0; i < tobeJared.length; i++) {
                if (tobeJared[i] == null || !tobeJared[i].exists() || tobeJared[i].isDirectory()) {
                    continue;
                }

                // Add archive entry
                JarEntry jarAdd = new JarEntry(tobeJared[i].getName());
                jarAdd.setTime(tobeJared[i].lastModified());
                out.putNextEntry(jarAdd);

                // Write file to archive
                FileInputStream in = new FileInputStream(tobeJared[i]);
                while (true) {
                    int nRead = in.read(buffer, 0, buffer.length);
                    if (nRead <= 0)
                        break;
                    out.write(buffer, 0, nRead);
                }
                in.close();
            }
            out.close();
            stream.close();
            LOG.info("Adding classes to jar file completed");
            return true;
        } catch (Exception ex) {
            LOG.error("Error: " + ex.getMessage());
            return false;
        }
    }

    /**
     * Create a test jar for testing purpose for a given class
     * name with specified code string: save the class to a file,
     * compile it, and jar it up. If the code string passed in is
     * null, a bare empty class will be created and used.
     *
     * @param testDir the folder under which to store the test class and jar
     * @param className the test class name
     * @param code the optional test class code, which can be null.
     * If null, a bare empty class will be used
     * @return the test jar file generated
     */
    public static File buildJar(String testDir, String className, String code) throws Exception {
        return buildJar(testDir, className, code, testDir);
    }

    /**
     * Create a test jar for testing purpose for a given class
     * name with specified code string.
     *
     * @param testDir the folder under which to store the test class
     * @param className the test class name
     * @param code the optional test class code, which can be null.
     * If null, an empty class will be used
     * @param folder the folder under which to store the generated jar
     * @return the test jar file generated
     */
    public static File buildJar(String testDir, String className, String code, String folder) throws Exception {
        String javaCode = code != null ? code : "public class " + className + " {}";
        Path srcDir = new Path(testDir, "src");
        File srcDirPath = new File(srcDir.toString());
        srcDirPath.mkdirs();
        File sourceCodeFile = new File(srcDir.toString(), className + ".java");
        BufferedWriter bw = new BufferedWriter(new FileWriter(sourceCodeFile));
        bw.write(javaCode);
        bw.close();

        // compile it by JavaCompiler
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        ArrayList<String> srcFileNames = new ArrayList<String>();
        srcFileNames.add(sourceCodeFile.toString());
        StandardJavaFileManager fm = compiler.getStandardFileManager(null, null, null);
        Iterable<? extends JavaFileObject> cu = fm.getJavaFileObjects(sourceCodeFile);
        List<String> options = new ArrayList<String>();
        options.add("-classpath");
        // only add hbase classes to classpath. This is a little bit tricky: assume
        // the classpath is {hbaseSrc}/target/classes.
        String currentDir = new File(".").getAbsolutePath();
        String classpath = currentDir + File.separator + "target" + File.separator + "classes"
                + System.getProperty("path.separator") + System.getProperty("java.class.path")
                + System.getProperty("path.separator") + System.getProperty("surefire.test.class.path");

        options.add(classpath);
        LOG.debug("Setting classpath to: " + classpath);

        JavaCompiler.CompilationTask task = compiler.getTask(null, fm, null, options, null, cu);
        assertTrue("Compile file " + sourceCodeFile + " failed.", task.call());

        // build a jar file by the classes files
        String jarFileName = className + ".jar";
        File jarFile = new File(folder, jarFileName);
        jarFile.getParentFile().mkdirs();
        if (!createJarArchive(jarFile, new File[] { new File(srcDir.toString(), className + ".class") })) {
            assertTrue("Build jar file failed.", false);
        }
        return jarFile;
    }

    /**
     * Add a list of jar files to another jar file under a specific folder.
     * It is used to generated coprocessor jar files which can be loaded by
     * the coprocessor class loader.  It is for testing usage only so we
     * don't be so careful about stream closing in case any exception.
     *
     * @param targetJar the target jar file
     * @param libPrefix the folder where to put inner jar files
     * @param srcJars the source inner jar files to be added
     * @throws Exception if anything doesn't work as expected
     */
    public static void addJarFilesToJar(File targetJar, String libPrefix, File... srcJars) throws Exception {
        FileOutputStream stream = new FileOutputStream(targetJar);
        JarOutputStream out = new JarOutputStream(stream, new Manifest());
        byte buffer[] = new byte[BUFFER_SIZE];

        for (File jarFile : srcJars) {
            // Add archive entry
            JarEntry jarAdd = new JarEntry(libPrefix + jarFile.getName());
            jarAdd.setTime(jarFile.lastModified());
            out.putNextEntry(jarAdd);

            // Write file to archive
            FileInputStream in = new FileInputStream(jarFile);
            while (true) {
                int nRead = in.read(buffer, 0, buffer.length);
                if (nRead <= 0)
                    break;
                out.write(buffer, 0, nRead);
            }
            in.close();
        }
        out.close();
        stream.close();
        LOG.info("Adding jar file to outer jar file completed");
    }

    static String localDirPath(Configuration conf) {
        return conf.get(ClassLoaderBase.LOCAL_DIR_KEY) + File.separator + "jars" + File.separator;
    }

}