org.cacheonix.impl.transformer.CacheonixClassAdapter.java Source code

Java tutorial

Introduction

Here is the source code for org.cacheonix.impl.transformer.CacheonixClassAdapter.java

Source

/**
 *
 */
/*
 * Cacheonix Systems licenses this file to You under the LGPL 2.1
 * (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.cacheonix.org/products/cacheonix/license-lgpl-2.1.htm
 *
 * 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.cacheonix.impl.transformer;

import java.util.HashMap;
import java.util.Map;

import org.objectweb.asm.ClassAdapter;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;

/**
 * A class visitor that provides the implementation for Cacheonix annotations.
 * <p/>
 * <p/>
 * For generating new methods based on the annotation information this class uses <code>CacheonixMethodsGenerator</code>
 */
public class CacheonixClassAdapter extends ClassAdapter {

    public static final String CACHEONIX_CONFIG_FILE_FIELD = "strCacheonixConfigFile";

    public static final String CACHE_NAME_FIELD = "strCacheonixCacheName";

    private static final String defaultCacheonixConfigFile = "cacheonix-config.xml";

    private String cacheonixConfigFileFieldValue;

    private String cacheonixCacheFieldValue;

    private boolean bCacheonixConfigPresent = false;

    private boolean bCacheonixCacheName = false;

    private final Map<String, MethodMetaData> methodLevelAnnotationInfo;

    private String className;

    /**
     * Class constructor
     *
     * @param cv                    Class visitor that this class delegates the call in the chain for further processing
     * @param className             inernal name of the class
     * @param classLevelAnnotation  Map containing the Annotation Name and the parameter for the class
     * @param methodLevelAnnotation Map containg the Annotation information for each method in the class
     */
    public CacheonixClassAdapter(final ClassVisitor cv, final String className,
            final Map<String, AnnotationParameter> classLevelAnnotation,
            final Map<String, MethodMetaData> methodLevelAnnotation) {

        super(cv);

        methodLevelAnnotationInfo = new HashMap<String, MethodMetaData>(methodLevelAnnotation);

        // if there are any method level annotations but some or all of the
        // class level annotations are missing then populate the
        // class level annotation values with default values

        if (!methodLevelAnnotationInfo.isEmpty()) {
            AnnotationParameter param = classLevelAnnotation
                    .get(CacheonixAnnotation.CACHECONFIGURATION_CONFIGURATION_PATH);
            if (param == null) {
                cacheonixConfigFileFieldValue = defaultCacheonixConfigFile;
            } else {
                cacheonixConfigFileFieldValue = param.oVal.toString();
            }

            param = classLevelAnnotation.get(CacheonixAnnotation.CACHECONFIGURATION_CACHE_NAME);
            if (param == null) {
                cacheonixCacheFieldValue = className.replace('/', '.');
            } else {
                cacheonixCacheFieldValue = param.oVal.toString();
            }

        }
    }

    /*
      * (non-Javadoc)
      *
      * @see org.objectweb.asm.ClassVisitor#visitField(int, java.lang.String,
      * java.lang.String, java.lang.String, java.lang.Object)
      */
    public FieldVisitor visitField(final int access, final String name, final String desc, final String signature,
            final Object value) {

        if (name.equals(CACHEONIX_CONFIG_FILE_FIELD)) {
            bCacheonixConfigPresent = true;
        }
        if (name.equals(CACHE_NAME_FIELD)) {
            bCacheonixCacheName = true;
        }

        return cv.visitField(access, name, desc, signature, value);
    }

    /*
      * (non-Javadoc)
      *
      * @see org.objectweb.asm.ClassVisitor#visitEnd()
      */
    public void visitEnd() {

        final String signature = null;

        // Add CacheonixConfig Field Now
        if (!bCacheonixConfigPresent) {
            final FieldVisitor fv = cv.visitField(Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC | Opcodes.ACC_FINAL,
                    CACHEONIX_CONFIG_FILE_FIELD, Type.getType(String.class).getDescriptor(), signature,
                    cacheonixConfigFileFieldValue);
            if (fv != null) {
                fv.visitEnd();
            }
        }

        // Add CacheonixCacheName Field Now
        if (!bCacheonixCacheName) {
            final FieldVisitor fv = cv.visitField(Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC | Opcodes.ACC_FINAL,
                    CACHE_NAME_FIELD, Type.getType(String.class).getDescriptor(), signature,
                    cacheonixCacheFieldValue);
            if (fv != null) {
                fv.visitEnd();
            }
        }

        cv.visitEnd();
    }

    /*
      * (non-Javadoc)
      *
      * @see org.objectweb.asm.ClassVisitor#visitMethod(int, java.lang.String,
      * java.lang.String, java.lang.String, java.lang.String[])
      */
    public MethodVisitor visitMethod(final int access, final String name, final String desc, final String signature,
            final String[] exceptions) {

        final String key = name + desc;

        // System.out.println(" ~~~~~~~~~~~~~~~~ Visit name and desc: " + name +
        // "  " + desc);
        // Type[] args = Type.getArgumentTypes(desc);
        // System.out.println(" ~~~~~~~~~~~~~~~~ Arguments are: " +
        // Arrays.toString(args));
        //
        // Object to = args;
        //
        String newName = name;
        final MethodMetaData metadata = methodLevelAnnotationInfo.get(key);
        if (metadata != null) {
            newName = "orig$Cacheonix$" + name;
            // System.out.println(" ~~~~~~~~~~~~~~~~ Processing name and desc: "
            // + name + "  " + desc);
            // System.out.println(" ~~~~~~~~~~~~~~~~ Replacing with name and desc: "
            // + newName + "  " + desc);

            if (metadata.isAnnotationPresent(CacheonixAnnotation.CACHE_DATA_SOURCE_DESCRIPTOR)) {
                CacheonixMethodGenerator.generateCacheAddBody(cv, className, access, desc, signature, exceptions,
                        name, newName, metadata, cacheonixCacheFieldValue);
            } else if (metadata.isAnnotationPresent(CacheonixAnnotation.CACHE_INVALIDATE_DESCRIPTOR)) {
                CacheonixMethodGenerator.generateCacheRemoveBody(cv, className, access, desc, signature, exceptions,
                        name, newName, metadata, cacheonixCacheFieldValue);
            }
        }
        return super.visitMethod(access, newName, desc, signature, exceptions);
    }

    /*
      * (non-Javadoc)
      *
      * @see org.objectweb.asm.ClassVisitor#visit(int, int, java.lang.String,
      * java.lang.String, java.lang.String, java.lang.String[])
      */
    public void visit(final int version, final int access, final String name, final String signature,
            final String superName, final String[] interfaces) {

        className = name;
        cv.visit(version, access, className, signature, superName, interfaces);
    }
}