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

Java tutorial

Introduction

Here is the source code for com.netease.hearttouch.hthotfix.patch.PatchGeneratorTransformExecutor.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 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;
import org.objectweb.asm.ClassReader;

import com.netease.hearttouch.hthotfix.inject.HackInjector;

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

    private final Logger logger;
    private final HashFileParser hashFileParser;
    private final PatchJarHelper patchJarHelper;
    private final HTHotfixExtension extension;
    private HackInjector hackInjector;
    private final RefScanInstrument refScanInstrument;

    public PatchGeneratorTransformExecutor(Project project, HTHotfixExtension extension,
            RefScanInstrument refScanInstrument) {
        this.project = project;
        this.logger = project.getLogger();
        hashFileParser = new HashFileParser(project);
        patchJarHelper = new PatchJarHelper(project);
        this.extension = extension;
        hackInjector = new HackInjector(project, extension.getIncludePackage(), extension.getExcludeClass());
        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()) {
                    if (hashFileParser == null) {
                        project.getLogger().error("hashFileParser is null,do you set  generatePath true?");
                    }

                    if ((hashFileParser != null) && (hashFileParser.isChanged(className, bytecode))) {
                        project.getLogger().error("has change classname,\t" + className);

                        ResourceDiffChecker.checkClass(project, className);
                        patchJarHelper.writeClassToDirectory(className, hackInjector.inject(className, bytecode));
                        refScanInstrument.addPatchClassName(className, hackInjector.getLastSuperName());

                    }
                }
                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()) {
                        ClassReader cr = new ClassReader(bytecode);
                        String className = cr.getClassName();
                        if ((hashFileParser != null) && (hashFileParser.isChanged(className, bytecode))) {
                            patchJarHelper.writeClassToDirectory(className,
                                    hackInjector.inject(className, bytecode));
                            refScanInstrument.addPatchClassName(className, hackInjector.getLastSuperName());
                        }
                    }
                    outputJar.writeEntry(entry, bytecode);
                } else {
                    outputJar.writeEntry(entry, bytecode);
                }
            } finally {
                IOUtils.closeQuietly(is);
            }
        }
        outputJar.close();
    }
}