com.costlowcorp.eriktools.wardetails.BasicBytecodeScan.java Source code

Java tutorial

Introduction

Here is the source code for com.costlowcorp.eriktools.wardetails.BasicBytecodeScan.java

Source

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.costlowcorp.eriktools.wardetails;

import com.costlowcorp.eriktools.back.ArchiveWalker;
import com.costlowcorp.eriktools.back.ArchiveWalkerRecipient;
import com.costlowcorp.eriktools.jardetails.ClassFileMetaVisitor;
import com.costlowcorp.eriktools.jardetails.IdentifiedURL;
import com.costlowcorp.eriktools.jardetails.URLIdentificationVisitor;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.attribute.FileTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.atomic.LongAdder;
import java.util.function.Consumer;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.zip.ZipInputStream;
import javafx.concurrent.Task;
import javafx.scene.control.TreeItem;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.Opcodes;

/**
 *
 * @author ecostlow
 */
public class BasicBytecodeScan extends Task<Void> {

    private final Path path;
    private final double maxClasses;
    private final Consumer<Set<String>> onCompletion;
    private final Set<String> ownedPackages = new TreeSet<>();
    private final Map<String, TreeItem> items = new HashMap<>();
    private TreeItem root;
    private TreeItem<IdentifiedURL> urlRoot;
    private final Consumer<TreeItem> updateTree;
    private final Consumer<TreeItem<IdentifiedURL>> urlUpdate;

    public BasicBytecodeScan(String title, Path path, long maxClasses, Consumer<Set<String>> onCompletion,
            Consumer<TreeItem> updateTree, Consumer<TreeItem<IdentifiedURL>> urlUpdate) {
        updateTitle(title);
        this.path = path;
        this.maxClasses = maxClasses;
        this.onCompletion = onCompletion;
        this.updateTree = updateTree;
        this.urlUpdate = urlUpdate;
    }

    @Override
    protected Void call() throws Exception {
        final LongAdder classCount = new LongAdder();
        final Double upMaxClasses = maxClasses;
        urlRoot = new TreeItem<>(new IdentifiedURL("/", "", "", ""));
        urlRoot.setExpanded(true);

        try (InputStream in = Files.newInputStream(path); ZipInputStream zin = new ZipInputStream(in)) {
            final ArchiveWalkerRecipient eachFile = (t, entry, u) -> {
                classCount.increment();
                final double currentClass = classCount.doubleValue();
                final String message = String.format("Class %1.0f of %1.0f", currentClass, upMaxClasses);
                updateMessage(message);
                updateProgress(currentClass, maxClasses);
                if (entry.getName().toLowerCase().endsWith(".class")) {

                    try {
                        final byte[] bytes = ArchiveWalker.currentEntry(u);
                        final URLIdentificationVisitor urlIdentificationVisitor = new URLIdentificationVisitor(
                                Opcodes.ASM5, null);
                        final ClassFileMetaVisitor v = new ClassFileMetaVisitor(Opcodes.ASM5,
                                urlIdentificationVisitor);
                        final ClassReader reader = new ClassReader(bytes);
                        reader.accept(v, ClassReader.SKIP_CODE);
                        final String pkg = v.getPackage();
                        final boolean foundJar = t.stream()
                                .filter(archive -> archive.toLowerCase().contains(".jar")).findAny().isPresent();
                        if (!foundJar && !"".equals(pkg)) {
                            ownedPackages.add(pkg);
                        }
                        final List<String> names = new ArrayList<>(t.size());
                        names.addAll(t);
                        names.set(names.size() - 1, pkg);
                        final String key = makeName(names);
                        if (items.containsKey(key)) {
                            final TreeItem<ArchiveOwnershipEntry> item = items.get(key);
                            final FileTime lastModified = entry.getLastModifiedTime() == null
                                    ? FileTime.fromMillis(0)
                                    : entry.getLastModifiedTime();
                            item.getValue().setWhenMade(new Date(lastModified.toMillis()));
                        } else {
                            final FileTime lastModified = entry.getLastModifiedTime() == null
                                    ? FileTime.fromMillis(0)
                                    : entry.getLastModifiedTime();
                            final TreeItem<ArchiveOwnershipEntry> item = nest(items, names, lastModified);
                            item.getValue().setWhenMade(new Date(lastModified.toMillis()));
                        }

                        if (!urlIdentificationVisitor.getIdentifiedURLs().isEmpty()) {
                            urlIdentificationVisitor.getIdentifiedURLs().stream().map(id -> new TreeItem<>(id))
                                    .forEach(urlRoot.getChildren()::add);
                        }
                    } catch (IOException ex) {
                        Logger.getLogger(BasicBytecodeScan.class.getName()).log(Level.SEVERE, null, ex);
                    }

                }
            };
            final ArchiveWalker walker = new ArchiveWalker(path.toString(), zin, eachFile);
            walker.walk();
        } catch (Exception ex) {
            Logger.getLogger(WarDetailsController.class.getName()).log(Level.SEVERE, "The task failed", ex);
        }
        done();
        return null;
    }

    @Override
    protected void succeeded() {
        super.succeeded();
        onCompletion.accept(ownedPackages);
        updateTree.accept(root);
        urlUpdate.accept(urlRoot);
    }

    private TreeItem nest(Map<String, TreeItem> items, List<String> names, FileTime when) {
        final String currentName = makeName(names);
        final Date time = when == null ? null : new Date(when.toMillis());
        if (items.isEmpty() && names.size() == 1) {
            final TreeItem item = new TreeItem(new ArchiveOwnershipEntry(names.get(names.size() - 1), time));
            items.put(currentName, item);
            root = item;
            item.setExpanded(true);
            return item;
        } else if (items.containsKey(currentName)) {
            return items.get(currentName);
        } else {
            final TreeItem item = new TreeItem(new ArchiveOwnershipEntry(names.get(names.size() - 1), time));
            item.setExpanded(true);
            final List<String> subList = names.subList(0, names.size() - 1);
            nest(items, subList, when).getChildren().add(item);
            items.put(currentName, item);
            return item;
        }
    }

    private static String makeName(List<String> names) {
        return String.join("->", names);
    }
}