org.cdmckay.coffeep.Program.java Source code

Java tutorial

Introduction

Here is the source code for org.cdmckay.coffeep.Program.java

Source

/*
 * Copyright 2013 Cameron McKay
 *
 * 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
 *
 * 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.cdmckay.coffeep;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.sun.tools.classfile.Attribute;
import com.sun.tools.classfile.ClassFile;
import com.sun.tools.classfile.ConstantPoolException;
import com.sun.tools.classfile.DescriptorException;
import com.sun.tools.javac.file.JavacFileManager;
import com.sun.tools.javac.util.Context;
import org.apache.commons.cli.*;
import org.apache.log4j.Logger;
import org.cdmckay.coffeep.readers.TypeReader;

import javax.tools.JavaFileManager;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.StandardLocation;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigInteger;
import java.security.DigestInputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class Program {

    private final static Logger logger = Logger.getLogger(Program.class);

    public static void main(String[] args) throws IOException, ConstantPoolException, DescriptorException {
        final Options options = createOptions();
        final CommandLineParser parser = new PosixParser();
        final CommandLine line;
        try {
            line = parser.parse(options, args);
            if (line.getArgList().isEmpty()) {
                logger.fatal("Missing class argument");
                System.out.println("Missing class argument");
            }

            if (line.getArgList().isEmpty() || line.hasOption('h')) {
                final HelpFormatter helpFormatter = new HelpFormatter();
                helpFormatter.printHelp("coffeep <options> <class>", options);
                return;
            }
        } catch (ParseException e) {
            logger.fatal("Command line parsing failed", e);
            return;
        }

        final String className = line.getArgs()[0];
        final JavaFileObject fileObject = getFileObject(className);
        if (fileObject == null) {
            logger.fatal("Class not found: " + className);
            System.out.println("Class not found: " + className);
            return;
        }

        final Coffeep coffeep = convertToCoffeep(fileObject);
        final Gson gson = line.hasOption('p') ? new GsonBuilder().setPrettyPrinting().create() : new Gson();
        final String json = gson.toJson(coffeep);
        System.out.println(json);
    }

    public static Coffeep convertToCoffeep(JavaFileObject fileObject)
            throws IOException, ConstantPoolException, DescriptorException {
        final Coffeep coffeep = new Coffeep();
        coffeep.systemInfo = new CoffeepSystemInfo();

        final ClassFile classFile = getClassFile(fileObject, coffeep.systemInfo);
        coffeep.type = new TypeReader(classFile).read();

        return coffeep;
    }

    private static Options createOptions() {
        final Options options = new Options();

        final Option helpOption = new Option("h", "help", false, "print this message");
        options.addOption(helpOption);

        final Option prettyPrintOption = new Option("p", "pretty", false, "pretty print the JSON");
        options.addOption(prettyPrintOption);

        return options;
    }

    private static JavaFileObject getFileObject(String className) throws IOException {
        final Context context = new Context();
        final JavaFileManager fileManager = new JavacFileManager(context, true, null);

        JavaFileObject fileObject;

        fileObject = fileManager.getJavaFileForInput(StandardLocation.PLATFORM_CLASS_PATH, className,
                JavaFileObject.Kind.CLASS);
        if (fileObject != null)
            return fileObject;

        fileObject = fileManager.getJavaFileForInput(StandardLocation.CLASS_PATH, className,
                JavaFileObject.Kind.CLASS);
        if (fileObject != null)
            return fileObject;

        final StandardJavaFileManager standardFileManager = (StandardJavaFileManager) fileManager;
        return standardFileManager.getJavaFileObjects(className).iterator().next();
    }

    private static ClassFile getClassFile(JavaFileObject fileObject, CoffeepSystemInfo systemInfo)
            throws IOException, ConstantPoolException {
        if (fileObject == null) {
            throw new IllegalArgumentException("fileObject cannot be null");
        }
        if (systemInfo == null) {
            throw new IllegalArgumentException("systemInfo cannot be null");
        }

        InputStream inputStream = fileObject.openInputStream();
        try {
            MessageDigest messageDigest = null;
            try {
                messageDigest = MessageDigest.getInstance("MD5");
            } catch (NoSuchAlgorithmException e) {
                logger.warn("Exception while getting MD5 MessageDigest", e);
            }

            DigestInputStream digestInputStream = new DigestInputStream(inputStream, messageDigest);
            CountingInputStream countingInputStream = new CountingInputStream(digestInputStream);

            Attribute.Factory attributeFactory = new Attribute.Factory();
            ClassFile classFile = ClassFile.read(countingInputStream, attributeFactory);

            systemInfo.classFileUri = fileObject.toUri();
            systemInfo.classFileSize = countingInputStream.getSize();
            systemInfo.lastModifiedTimestamp = fileObject.getLastModified();
            if (messageDigest != null) {
                systemInfo.digestAlgorithm = messageDigest.getAlgorithm();
                systemInfo.digest = new BigInteger(1, messageDigest.digest()).toString(16);
            }

            return classFile;
        } finally {
            inputStream.close();
        }
    }

    private static class CountingInputStream extends FilterInputStream {

        private int size;

        CountingInputStream(InputStream inputStream) {
            super(inputStream);
        }

        @Override
        public int read(byte[] buf, int offset, int length) throws IOException {
            int n = super.read(buf, offset, length);
            if (n > 0) {
                size += n;
            }
            return n;
        }

        @Override
        public int read() throws IOException {
            int b = super.read();
            size += 1;
            return b;
        }

        public int getSize() {
            return size;
        }

    }

}