com.netease.hearttouch.hthotfix.patch.PatchRefGeneratorTransformExecutor.java Source code

Java tutorial

Introduction

Here is the source code for com.netease.hearttouch.hthotfix.patch.PatchRefGeneratorTransformExecutor.java

Source

/*
 * This source code is licensed under the MIT-style license found in the
 * LICENSE file in the root directory of this source tree.
 */

package com.netease.hearttouch.hthotfix.patch;

import com.netease.hearttouch.hthotfix.*;
import com.netease.hearttouch.hthotfix.refclass.RefScanInstrument;
import org.apache.commons.io.IOUtils;
import org.gradle.api.Project;
import org.gradle.api.logging.Logger;
import org.objectweb.asm.ClassReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Enumeration;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

/**
 * patch class
 * Created by zw on 16/5/27.
 */
public class PatchRefGeneratorTransformExecutor {
    private final Project project;

    private final Logger logger;
    private final PatchJarHelper patchJarHelper;
    private final HTHotfixExtension extension;
    private final RefScanInstrument refScanInstrument;

    public PatchRefGeneratorTransformExecutor(Project project, HTHotfixExtension extension,
            RefScanInstrument refScanInstrument) {
        this.project = project;
        this.logger = project.getLogger();
        patchJarHelper = new PatchJarHelper(project);
        this.extension = extension;
        this.refScanInstrument = refScanInstrument;
    }

    public void transformDirectory(File inputFile, File outputFile) throws IOException {

        Path inputDir = inputFile.toPath();
        Path outputDir = outputFile.toPath();

        if (!Files.isDirectory(inputDir)) {
            return;
        }
        final OutputDirectory outputDirectory = new OutputDirectory(outputDir);
        Files.walkFileTree(inputDir, new ClasspathVisitor() {
            @Override
            protected void visitClass(Path path, byte[] bytecode) throws IOException {
                ClassReader cr = new ClassReader(bytecode);
                String className = cr.getClassName();
                if (extension.getGeneratePatch() && extension.getScanRef()) {
                    if (!refScanInstrument.isPatchClass(className.replace("/", "."))) {
                        boolean bPatchRef = refScanInstrument.hasReference(bytecode, project);
                        if (bPatchRef) {
                            patchJarHelper.writeClassToDirectory(className, bytecode);
                        }
                    }
                }
                outputDirectory.writeClass(className, bytecode);
            }

            @Override
            protected void visitResource(Path relativePath, byte[] content) throws IOException {
                outputDirectory.writeFile(relativePath, content);

            }
        });
    }

    public void transformJar(File inputFile, File outputFile) throws IOException {
        final JarFile jar = new JarFile(inputFile);
        final OutputJar outputJar = new OutputJar(outputFile);
        for (final Enumeration<JarEntry> entries = jar.entries(); entries.hasMoreElements();) {
            final JarEntry entry = entries.nextElement();
            if (entry.isDirectory()) {
                continue;
            }
            final InputStream is = jar.getInputStream(entry);
            try {

                byte[] bytecode = IOUtils.toByteArray(is);
                if (entry.getName().endsWith(".class")) {
                    if (extension.getGeneratePatch() && extension.getScanRef()) {
                        ClassReader cr = new ClassReader(bytecode);
                        String className = cr.getClassName();
                        if (extension.getGeneratePatch() && extension.getScanRef()) {
                            if (!refScanInstrument.isPatchClass(className.replace("/", "."))) {
                                boolean bPatchRef = refScanInstrument.hasReference(bytecode, project);
                                if (bPatchRef) {
                                    patchJarHelper.writeClassToDirectory(className, bytecode);
                                }
                            }
                        }
                    }
                    outputJar.writeEntry(entry, bytecode);
                } else {
                    outputJar.writeEntry(entry, bytecode);
                }
            } finally {
                IOUtils.closeQuietly(is);
            }
        }
        outputJar.close();
    }

    public void transformFinish() {

    }
}