com.github.antag99.retinazer.weaver.WeaverMetadata.java Source code

Java tutorial

Introduction

Here is the source code for com.github.antag99.retinazer.weaver.WeaverMetadata.java

Source

/*******************************************************************************
 * Retinazer, an entity-component-system framework for Java
 *
 * Copyright (C) 2015-2016 Anton Gustafsson
 *
 * This file is part of Retinazer.
 *
 * Retinazer is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Retinazer is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with Retinazer.  If not, see <http://www.gnu.org/licenses/>.
 ******************************************************************************/
package com.github.antag99.retinazer.weaver;

import java.util.ArrayList;
import java.util.List;

import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.Opcodes;

final class WeaverMetadata implements Opcodes {
    /** The weaver instance */
    public Weaver weaver;
    /** Internal name of the class */
    public String internalName;
    /** Name of the super class; may be null if unknown. */
    public String superName;
    /** Interfaces of the class; may be null if unknown. */
    public String[] interfaces;
    /** Source of this class; may be null if unknown. */
    public ChainSource source;

    /** Component metadata for this class; may be null if not a component */
    public ComponentMetadata componentMetadata;
    /** System metadata for this class; may be null if not a system */
    public SystemMetadata systemMetadata;

    private boolean processed = false;

    public WeaverMetadata(Weaver weaver, final String internalName) {
        this.weaver = weaver;
        this.internalName = internalName;
    }

    public boolean isLoaded() {
        return source != null;
    }

    public boolean isProcessed() {
        return processed;
    }

    public void load(byte[] classFile) {
        final ClassReader classReader = new ClassReader(classFile);
        source = new ChainSource() {
            @Override
            public void accept(ClassVisitor visitor) {
                classReader.accept(visitor, 0);
            }
        };
    }

    public void processMetadata() {
        final ClassVisitor classVisitor = new ClassVisitor(ASM5) {
            @Override
            public void visit(int version, int access, String name, String signature, String superName,
                    String[] interfaces) {
                WeaverMetadata.this.internalName = name;
                WeaverMetadata.this.superName = name;
                WeaverMetadata.this.interfaces = interfaces != null ? interfaces : new String[0];

                boolean isComponent = false;

                for (String interfaceName : WeaverMetadata.this.interfaces) {
                    isComponent |= interfaceName.equals(WeaverConstants.COMPONENT_NAME);
                    isComponent |= weaver.getMetadata(interfaceName).componentMetadata != null;

                    if (isComponent)
                        break;
                }

                boolean isSystem = false;

                if (!"java/lang/Object".equals(superName)) {
                    isSystem |= superName.equals(WeaverConstants.ENTITY_SYSTEM_NAME);
                    isSystem |= weaver.getMetadata(superName).systemMetadata != null;
                }

                if (isComponent) {
                    cv = (componentMetadata = new ComponentMetadata(cv));
                }

                if (isSystem) {
                    cv = (systemMetadata = new SystemMetadata(cv));
                }

                super.visit(version, access, name, signature, superName, interfaces);
            }
        };
        source.accept(classVisitor);
    }

    public void process() {
        if (processed)
            return;
        processed = true;

        List<ChainVisitor> visitors = new ArrayList<>();
        if (componentMetadata != null && !componentMetadata.isInterface) {
            visitors.add(new ComponentProcessor(componentMetadata));
            visitors.add(new AccessProcessor(weaver));

            // Generate component mapper
            WeaverMetadata metadata = weaver.createMetadata(componentMetadata.getMapperName());
            metadata.source = new MapperGenerator(componentMetadata);
            metadata.processMetadata();
            metadata.process();
        }

        if (systemMetadata != null) {
            visitors.add(new SystemProcessor(systemMetadata));
            visitors.add(new AccessProcessor(weaver));
        }

        ChainVisitor chainWriter = new ChainVisitor(ASM5);
        chainWriter.setClassVisitor(weaver.createClass(internalName));
        visitors.add(chainWriter);

        for (int i = 1; i < visitors.size(); i++)
            visitors.get(i - 1).setClassVisitor(visitors.get(i));

        source.accept(visitors.get(0));
    }
}