org.jboss.windup.interrogator.impl.ClassInterrogator.java Source code

Java tutorial

Introduction

Here is the source code for org.jboss.windup.interrogator.impl.ClassInterrogator.java

Source

/*
 * Copyright (c) 2013 Red Hat, Inc. and/or its affiliates.
 *  
 *  All rights reserved. This program and the accompanying materials
 *  are made available under the terms of the Eclipse Public License v1.0
 *  which accompanies this distribution, and is available at
 *  http://www.eclipse.org/legal/epl-v10.html
 *  
 *  Contributors:
 *      Brad Davis - bradsdavis@gmail.com - Initial API and implementation
*/
package org.jboss.windup.interrogator.impl;

import java.io.File;
import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

import javassist.ClassPool;
import javassist.CtClass;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jboss.windup.decorator.java.decompiler.DecompilerAdapter;
import org.jboss.windup.metadata.type.FileMetadata;
import org.jboss.windup.metadata.type.JavaMetadata;
import org.jboss.windup.metadata.type.ZipEntryMetadata;
import org.jboss.windup.metadata.type.archive.ZipMetadata;
import org.jboss.windup.util.BlacklistPackageResolver;
import org.jboss.windup.util.CustomerPackageResolver;
import org.jboss.windup.util.FatalWindupException;

public class ClassInterrogator extends ExtensionInterrogator<JavaMetadata> {
    private static final Log LOG = LogFactory.getLog(ClassInterrogator.class);
    private DecompilerAdapter decompiler;

    private BlacklistPackageResolver blacklistPackageResolver;
    private CustomerPackageResolver customerPackageResolver;

    public void setBlacklistPackageResolver(BlacklistPackageResolver blacklistPackageResolver) {
        this.blacklistPackageResolver = blacklistPackageResolver;
    }

    public void setDecompiler(DecompilerAdapter decompiler) {
        this.decompiler = decompiler;
    }

    public void setCustomerPackageResolver(CustomerPackageResolver customerPackageResolver) {
        this.customerPackageResolver = customerPackageResolver;
    }

    @Override
    public JavaMetadata archiveEntryToMeta(ZipEntryMetadata archiveEntry) {
        String className = extractClassName(archiveEntry.getZipEntry().getName());
        if (LOG.isDebugEnabled()) {
            LOG.debug("Class: " + className + " " + customerPackageResolver.isCustomerPkg(className));
        }

        // first, is this a customer's package?
        if (!customerPackageResolver.isCustomerPkg(className)) {
            if (LOG.isTraceEnabled()) {
                LOG.trace("Class: " + className + " is not a customer package.");
            }
            return null;
        }

        // extract imports if it is a customer class.
        Set<String> clzImports = extractImports(archiveEntry);

        // second, is this generated?
        if (blacklistPackageResolver.containsGenerated(clzImports)) {
            LOG.trace("Class is generated.  Skip profiling.");
            return null;
        }

        // third does the class contain any blacklists?
        if (!blacklistPackageResolver.containsBlacklist(clzImports)) {
            LOG.trace("Class does not contain blacklists.");
            return null;
        }

        /*
         * ok; it contains blacklists... we need to process it. get the Java for the class by either
         * 1) finding it in the Zip archive... or
         * 2) decompiling.
         */
        return extractJavaFile(className, clzImports, archiveEntry);
    }

    private JavaMetadata extractJavaFile(String className, Set<String> clzImports, ZipEntryMetadata archiveEntry) {
        JavaMetadata javaMeta = new JavaMetadata();
        try {
            File clzFile;
            File javaFile;

            //TODO: make this work for directorymeta too.
            ZipMetadata zipMeta = (ZipMetadata) archiveEntry.getArchiveMeta();
            ZipFile zipFile = zipMeta.getZipFile();
            ZipEntry entry = archiveEntry.getZipEntry();
            // check to see whether the Java version is packaged with the archive...
            String javaZipEntry = StringUtils.removeEnd(entry.getName(), ".class") + ".java";

            if (zipFile.getEntry(javaZipEntry) != null) {
                if (LOG.isDebugEnabled()) {
                    LOG.debug("Found Java in archive: " + className);
                }
                ZipEntry javaEntry = zipFile.getEntry(javaZipEntry);
                archiveEntry.setZipEntry(javaEntry);
                javaFile = archiveEntry.getFilePointer();
            } else {
                clzFile = archiveEntry.getFilePointer();
                javaFile = new File(StringUtils.substringBeforeLast(clzFile.getAbsolutePath(), ".class") + ".java");
                File javaPathFile = new File(
                        StringUtils.substringBeforeLast(clzFile.getAbsolutePath(), File.separator));

                if (LOG.isDebugEnabled()) {
                    LOG.debug("Did not find class in archive. Decompiling class: " + className);
                }
                decompiler.decompile(className, clzFile, javaPathFile);

                if (LOG.isDebugEnabled()) {
                    LOG.debug("Unzipped class: " + className);
                }
            }

            javaMeta.setFilePointer(javaFile);
            javaMeta.setArchiveMeta(archiveEntry.getArchiveMeta());
            javaMeta.setClassDependencies(clzImports);
            javaMeta.setQualifiedClassName(className);
            javaMeta.setBlackListedDependencies(blacklistPackageResolver.extractBlacklist(clzImports));

            return javaMeta;
        } catch (Exception e) {
            if (e instanceof FatalWindupException) {
                throw (FatalWindupException) e;
            }

            LOG.error(e);
            return null;
        }
    }

    protected Set<String> extractImports(ZipEntryMetadata archiveEntry) {
        try {
            // otherwise, load the class and get its imports.

            //TODO: make this work for directorymeta too.
            ZipMetadata zipMeta = (ZipMetadata) archiveEntry.getArchiveMeta();
            ZipFile zipFile = zipMeta.getZipFile();
            ZipEntry entry = archiveEntry.getZipEntry();
            CtClass ctClz = new ClassPool().makeClass(zipFile.getInputStream(entry));
            if (LOG.isDebugEnabled()) {
                for (String clz : ctClz.getClassFile2().getInterfaces()) {
                    LOG.debug("Interfaces: " + clz);
                }
                LOG.debug("Super Class: " + ctClz.getClassFile2().getSuperclass());
            }
            Set<String> clzImports = new HashSet<String>(castList(String.class, ctClz.getRefClasses()));
            return clzImports;
        } catch (Exception e) {
            LOG.error(e);
            return null;
        }
    }

    public static <T> List<T> castList(Class<? extends T> aclass, Collection<?> c) {
        List<T> r = new ArrayList<T>(c.size());
        for (Object o : c) {
            r.add(aclass.cast(o));
        }
        return r;
    }

    protected String extractClassName(String entryName) {
        String className = StringUtils.replace(entryName, "\\", "/");
        className = StringUtils.removeStart(className, "/");
        className = StringUtils.replace(className, "/", ".");
        className = StringUtils.removeEnd(className, ".class");
        className = StringUtils.removeEnd(className, ".java");
        className = StringUtils.substringBefore(className, "$");

        // account for WAR classes.
        if (StringUtils.contains(className, "WEB-INF.classes.")) {
            className = StringUtils.substringAfter(className, "WEB-INF.classes.");
        }
        return className;
    }

    @Override
    public JavaMetadata fileEntryToMeta(FileMetadata entry) {
        JavaMetadata javaMeta = new JavaMetadata();
        javaMeta.setArchiveMeta(entry.getArchiveMeta());

        FileInputStream fis = null;
        try {
            fis = new FileInputStream(entry.getFilePointer());
            javaMeta.setFilePointer(entry.getFilePointer());
            //javaMeta.setArchiveMeta(archiveEntry.getArchiveMeta());
            CtClass ctClazz = new ClassPool().makeClass(fis);

            String className = ctClazz.getName();
            if (!customerPackageResolver.isCustomerPkg(className)) {
                if (LOG.isTraceEnabled()) {
                    LOG.trace("Class: " + className + " is not a customer package.");
                }
                return null;
            }

            Set<String> clzImports = new HashSet<String>(castList(String.class, ctClazz.getRefClasses()));

            // second, is this generated?
            if (blacklistPackageResolver.containsGenerated(clzImports)) {
                LOG.trace("Class is generated.  Skip profiling.");
                return null;
            }

            // third does the class contain any blacklists?
            if (!blacklistPackageResolver.containsBlacklist(clzImports)) {
                LOG.trace("Class does not contain blacklists.");
                return null;
            }

            javaMeta.setClassDependencies(clzImports);
            javaMeta.setQualifiedClassName(ctClazz.getName());
            javaMeta.setBlackListedDependencies(blacklistPackageResolver.extractBlacklist(clzImports));

            return javaMeta;
        } catch (Exception e) {
            LOG.error("Exception processing file: " + entry.getFilePointer().getAbsolutePath(), e);
        } finally {
            org.apache.commons.io.IOUtils.closeQuietly(fis);
        }

        return null;
    }
}