Package org.apache.commons.weaver.privilizer

Source Code of org.apache.commons.weaver.privilizer.ActionGenerator

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.commons.weaver.privilizer;

import java.lang.reflect.Modifier;
import java.security.PrivilegedAction;
import java.security.PrivilegedExceptionAction;
import java.util.Map;

import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.Validate;
import org.apache.commons.lang3.builder.Builder;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Label;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.commons.GeneratorAdapter;
import org.objectweb.asm.commons.Method;
import org.objectweb.asm.signature.SignatureReader;
import org.objectweb.asm.signature.SignatureVisitor;
import org.objectweb.asm.signature.SignatureWriter;

/**
* Generates the Privileged[Exception?]Action class to privilize a given Method.
*/
class ActionGenerator extends Privilizer.WriteClass implements Builder<Type> {
    final PrivilizingVisitor owner;
    final Method methd;
    final boolean exc;
    final Type[] exceptions;
    final String simpleName;
    final Type action;
    final Method impl;
    final int index;
    final boolean implIsStatic;
    final Method helper;
    final Type result;
    final Field[] fields;
    private final Type actionInterface;

    /**
     * Create a new {@link ActionGenerator}.
     * @param access modifier
     * @param methd {@link Method} to implement
     * @param exceptions thrown
     * @param owner of the action class
     */
    ActionGenerator(final int access, final Method methd, final String[] exceptions, final PrivilizingVisitor owner) {
        owner.privilizer().super(new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES));
        this.methd = methd;
        this.exc = ArrayUtils.isNotEmpty(exceptions);
        this.exceptions = exc ? new Type[] { Type.getType(Exception.class) } : null;
        this.owner = owner;
        this.simpleName = generateName(methd);
        this.action = Type.getObjectType(owner.className + '$' + simpleName);

        int privilegedAccessIndex = -1;
        String implName = null;
        for (final Map.Entry<Method, String> entry : owner.privilegedMethods.entrySet()) {
            privilegedAccessIndex++;
            if (entry.getKey().equals(methd)) {
                implName = entry.getValue();
                break;
            }
        }
        Validate.validState(implName != null);

        this.index = privilegedAccessIndex;

        this.impl = new Method(implName, methd.getDescriptor());
        this.implIsStatic = Modifier.isStatic(access);
        final Type[] args =
            implIsStatic ? methd.getArgumentTypes() : ArrayUtils.add(methd.getArgumentTypes(), 0, owner.target);
        this.helper = new Method(privilizer().generateName("access$" + index), methd.getReturnType(), args);
        this.result = privilizer().wrap(methd.getReturnType());
        this.fields = fields(args);
        this.actionInterface = Type.getType(exc ? PrivilegedExceptionAction.class : PrivilegedAction.class);
    }

    private static String generateName(final Method methd) {
        final StringBuilder buf = new StringBuilder(methd.getName());
        if (methd.getArgumentTypes().length > 0) {
            buf.append("$$");
            for (final Type arg : methd.getArgumentTypes()) {
                buf.append(arg.getDescriptor().replace("[", "arrayOf").replace('/', '_').replace(';', '$'));
            }
        }
        return buf.append("_ACTION").toString();
    }

    private static Field[] fields(final Type[] args) {
        final Field[] result = new Field[args.length];

        for (int i = 0; i < args.length; i++) {
            final String name = new StringBuilder("f").append(i + 1).toString();
            result[i] = new Field(Opcodes.ACC_PRIVATE + Opcodes.ACC_FINAL, name, args[i]);
        }
        return result;
    }

    @Override
    public Type build() {
        generateHelper();
        begin();
        init();
        impl();
        visitEnd();
        owner.privilizer().env.debug("Generated %s implementation %s to call %s#%s", actionInterface.getClassName(),
            action.getClassName(), owner.target.getClassName(), helper);
        return action;
    }

    /**
     * We must add special methods for inner classes to invoke their owners' methods, according to the scheme "access$n"
     * where n is the index into this (ordered) map. Additionally we will prefix the whole thing like we usually do
     * (__privileged_):
     */
    private void generateHelper() {
        owner.privilizer().env.debug("Generating static helper method %s.%s to call %s", owner.target.getClassName(),
            helper, impl);
        final GeneratorAdapter mgen =
            new GeneratorAdapter(Opcodes.ACC_STATIC | Opcodes.ACC_SYNTHETIC, helper, null, exceptions, owner);

        mgen.visitCode();
        mgen.loadArgs();
        if (implIsStatic) {
            mgen.invokeStatic(owner.target, impl);
        } else {
            mgen.invokeVirtual(owner.target, impl);
        }
        mgen.returnValue();
        mgen.endMethod();
    }

    private void begin() {
        owner.visitInnerClass(action.getInternalName(), owner.className, simpleName, Opcodes.ACC_PRIVATE
            | Opcodes.ACC_STATIC);

        final SignatureWriter type = new SignatureWriter();
        final SignatureVisitor actionImplemented = type.visitInterface();
        actionImplemented.visitClassType(actionInterface.getInternalName());
        final SignatureVisitor visitTypeArgument = actionImplemented.visitTypeArgument('=');
        final SignatureReader result = new SignatureReader(privilizer().wrap(methd.getReturnType()).getDescriptor());
        result.accept(visitTypeArgument);
        actionImplemented.visitEnd();

        final String signature = type.toString();

        visit(Opcodes.V1_5, Opcodes.ACC_SUPER | Opcodes.ACC_SYNTHETIC | Opcodes.ACC_FINAL, action.getInternalName(),
            signature, Type.getType(Object.class).getInternalName(),
            new String[] { actionInterface.getInternalName() });
    }

    /**
     * Add fields and generate constructor.
     */
    private void init() {
        for (final Field field : fields) {
            visitField(field.access, field.name, field.type.getDescriptor(), null, null).visitEnd();
        }
        final Method init = new Method("<init>", Type.VOID_TYPE, helper.getArgumentTypes());

        final GeneratorAdapter mgen =
            new GeneratorAdapter(0, init, null, Privilizer.EMPTY_TYPE_ARRAY, this);

        mgen.visitCode();
        final Label begin = mgen.mark();

        // invoke super constructor
        mgen.loadThis();
        mgen.invokeConstructor(Type.getType(Object.class), Method.getMethod("void <init> ()"));
        // assign remaining fields

        int arg = 0;
        for (final Field field : fields) {
            mgen.loadThis();
            mgen.loadArg(arg++);
            mgen.putField(action, field.name, field.type);
        }

        mgen.returnValue();
        final Label end = mgen.mark();

        // declare local vars
        mgen.visitLocalVariable("this", action.getDescriptor(), null, begin, end, 0);
        arg = 1;
        for (final Field field : fields) {
            mgen.visitLocalVariable("arg" + arg, field.type.getDescriptor(), null, begin, end, arg++);
        }
        mgen.endMethod();
    }

    /**
     * Generate impl method.
     */
    private void impl() {
        final Method run = Method.getMethod("Object run()");

        final GeneratorAdapter mgen = new GeneratorAdapter(Opcodes.ACC_PUBLIC, run, null, exceptions, this);

        for (final Field field : fields) {
            mgen.loadThis();
            mgen.getField(action, field.name, field.type);
        }

        mgen.invokeStatic(owner.target, helper);

        if (methd.getReturnType().getSort() < Type.ARRAY) {
            mgen.valueOf(methd.getReturnType());
        }

        mgen.returnValue();

        mgen.endMethod();
    }

}
TOP

Related Classes of org.apache.commons.weaver.privilizer.ActionGenerator

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.