org.aspectj.weaver.AjAttribute.java Source code

Java tutorial

Introduction

Here is the source code for org.aspectj.weaver.AjAttribute.java

Source

/* *******************************************************************
 * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC).
 * All rights reserved. 
 * This program and the accompanying materials are made available 
 * under the terms of the Eclipse Public License v1.0 
 * which accompanies this distribution and is available at 
 * http://www.eclipse.org/legal/epl-v10.html 
 *  
 * Contributors: 
 *     PARC     initial implementation 
 * ******************************************************************/

package org.aspectj.weaver;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.IOException;

import org.aspectj.bridge.MessageUtil;
import org.aspectj.bridge.Version;
import org.aspectj.util.FileUtil;
import org.aspectj.weaver.patterns.Declare;
import org.aspectj.weaver.patterns.IScope;
import org.aspectj.weaver.patterns.PerClause;
import org.aspectj.weaver.patterns.Pointcut;

/**
 * These attributes are written to and read from .class files (see the JVM spec).
 * 
 * <p>
 * Each member or type can have a number of AjAttributes. Each such attribute is in 1-1 correspondence with an Unknown bcel
 * attribute. Creating one of these does NOTHING to the underlying thing, so if you really want to add an attribute to a particular
 * thing, well, you'd better actually do that.
 * 
 * @author Erik Hilsdale
 * @author Jim Hugunin
 */
public abstract class AjAttribute {

    public static final String AttributePrefix = "org.aspectj.weaver";

    protected abstract void write(CompressingDataOutputStream s) throws IOException;

    public abstract String getNameString();

    public char[] getNameChars() {
        return getNameString().toCharArray();
    }

    /**
     * Just writes the contents
     */
    public byte[] getBytes(ConstantPoolWriter compressor) {
        try {
            ByteArrayOutputStream b0 = new ByteArrayOutputStream();
            CompressingDataOutputStream s0 = new CompressingDataOutputStream(b0, compressor);
            write(s0);
            s0.close();
            return b0.toByteArray();
        } catch (IOException e) {
            // shouldn't happen with ByteArrayOutputStreams
            throw new RuntimeException("sanity check");
        }
    }

    /**
     * Writes the full attribute, i.e. name_index, length, and contents
     * 
     * @param constantPool
     */
    public byte[] getAllBytes(short nameIndex, ConstantPoolWriter dataCompressor) {
        try {
            byte[] bytes = getBytes(dataCompressor);

            ByteArrayOutputStream b0 = new ByteArrayOutputStream();
            DataOutputStream s0 = new DataOutputStream(b0);

            s0.writeShort(nameIndex);
            s0.writeInt(bytes.length);
            s0.write(bytes);
            s0.close();
            return b0.toByteArray();
        } catch (IOException e) {
            // shouldn't happen with ByteArrayOutputStreams
            throw new RuntimeException("sanity check");
        }
    }

    public static AjAttribute read(AjAttribute.WeaverVersionInfo v, String name, byte[] bytes,
            ISourceContext context, World w, ConstantPoolReader dataDecompressor) {
        try {
            if (bytes == null) {
                bytes = new byte[0];
            }

            VersionedDataInputStream s = new VersionedDataInputStream(new ByteArrayInputStream(bytes),
                    dataDecompressor);
            s.setVersion(v);
            if (name.equals(Aspect.AttributeName)) {
                return new Aspect(PerClause.readPerClause(s, context));
            } else if (name.equals(MethodDeclarationLineNumberAttribute.AttributeName)) {
                return MethodDeclarationLineNumberAttribute.read(s);
            } else if (name.equals(WeaverState.AttributeName)) {
                return new WeaverState(WeaverStateInfo.read(s, context));
            } else if (name.equals(WeaverVersionInfo.AttributeName)) {
                return WeaverVersionInfo.read(s);
            } else if (name.equals(AdviceAttribute.AttributeName)) {
                AdviceAttribute aa = AdviceAttribute.read(s, context);
                aa.getPointcut().check(context, w);
                return aa;
            } else if (name.equals(PointcutDeclarationAttribute.AttributeName)) {
                PointcutDeclarationAttribute pda = new PointcutDeclarationAttribute(
                        ResolvedPointcutDefinition.read(s, context));
                pda.pointcutDef.getPointcut().check(context, w);
                return pda;
            } else if (name.equals(TypeMunger.AttributeName)) {
                return new TypeMunger(ResolvedTypeMunger.read(s, context));
            } else if (name.equals(AjSynthetic.AttributeName)) {
                return new AjSynthetic();
            } else if (name.equals(DeclareAttribute.AttributeName)) {
                return new DeclareAttribute(Declare.read(s, context));
            } else if (name.equals(PrivilegedAttribute.AttributeName)) {
                return PrivilegedAttribute.read(s, context);
            } else if (name.equals(SourceContextAttribute.AttributeName)) {
                return SourceContextAttribute.read(s);
            } else if (name.equals(EffectiveSignatureAttribute.AttributeName)) {
                return EffectiveSignatureAttribute.read(s, context);
            } else {
                // We have to tell the user about this...
                if (w == null || w.getMessageHandler() == null) {
                    throw new BCException("unknown attribute" + name);
                }
                w.getMessageHandler().handleMessage(MessageUtil.warn("unknown attribute encountered " + name));
                return null;
            }
        } catch (BCException e) {
            throw new BCException("malformed " + name + " attribute (length:" + bytes.length + ")" + e);
        } catch (IOException e) {
            throw new BCException("malformed " + name + " attribute (length:" + bytes.length + ")" + e);
        }
    }

    // ----

    /**
     * Synthetic members should have NO advice put on them or on their contents. This attribute is currently unused as we consider
     * all members starting with NameMangler.PREFIX to automatically be synthetic. As we use this we might find that we want
     * multiple kinds of synthetic. In particular, if we want to treat the call to a synthetic getter (say, of an introduced field)
     * as a field reference itself, then a method might want a particular kind of AjSynthetic attribute that also includes a
     * signature of what it stands for.
     */
    public static class AjSynthetic extends AjAttribute {
        public static final String AttributeName = "org.aspectj.weaver.AjSynthetic";

        @Override
        public String getNameString() {
            return AttributeName;
        }

        // private ResolvedTypeMunger munger;
        public AjSynthetic() {
        }

        @Override
        public void write(CompressingDataOutputStream s) throws IOException {
        }
    }

    public static class TypeMunger extends AjAttribute {
        public static final String AttributeName = "org.aspectj.weaver.TypeMunger";

        @Override
        public String getNameString() {
            return AttributeName;
        }

        private final ResolvedTypeMunger munger;

        public TypeMunger(ResolvedTypeMunger munger) {
            this.munger = munger;
        }

        @Override
        public void write(CompressingDataOutputStream s) throws IOException {
            munger.write(s);
        }

        public ConcreteTypeMunger reify(World world, ResolvedType aspectType) {
            return world.getWeavingSupport().concreteTypeMunger(munger, aspectType);
        }
    }

    public static class WeaverState extends AjAttribute {
        public static final String AttributeName = "org.aspectj.weaver.WeaverState";

        @Override
        public String getNameString() {
            return AttributeName;
        }

        private final WeaverStateInfo kind;

        public WeaverState(WeaverStateInfo kind) {
            this.kind = kind;
        }

        @Override
        public void write(CompressingDataOutputStream s) throws IOException {
            kind.write(s);
        }

        public WeaverStateInfo reify() {
            return kind;
        }
    }

    public static class WeaverVersionInfo extends AjAttribute {
        public static final String AttributeName = "org.aspectj.weaver.WeaverVersion";

        // If you change the format of an AspectJ class file, you have two
        // options:
        // - changing the minor version means you have not added anything that
        // prevents
        // previous versions of the weaver from operating (e.g.
        // MethodDeclarationLineNumber attribute)
        // - changing the major version means you have added something that
        // prevents previous
        // versions of the weaver from operating correctly.
        //
        // The user will get a warning for any org.aspectj.weaver attributes the
        // weaver does
        // not recognize.

        // When we don't know ... (i.e. pre 1.2.1)
        public final static short WEAVER_VERSION_MAJOR_UNKNOWN = 0;
        public final static short WEAVER_VERSION_MINOR_UNKNOWN = 0;

        // These are the weaver major/minor numbers for AspectJ 1.2.1
        public final static short WEAVER_VERSION_MAJOR_AJ121 = 1;
        public final static short WEAVER_VERSION_MINOR_AJ121 = 0;

        // These are the weaver major/minor numbers for AspectJ 1.5.0
        public final static short WEAVER_VERSION_MAJOR_AJ150M4 = 3;
        public final static short WEAVER_VERSION_MAJOR_AJ150 = 2;
        public final static short WEAVER_VERSION_MINOR_AJ150 = 0;

        // These are the weaver major/minor numbers for AspectJ 1.6.0
        public final static short WEAVER_VERSION_MAJOR_AJ160M2 = 5;
        public final static short WEAVER_VERSION_MAJOR_AJ160 = 4;
        public final static short WEAVER_VERSION_MINOR_AJ160 = 0;

        // These are the weaver major/minor numbers for AspectJ 1.6.1
        // added annotation value binding
        public final static short WEAVER_VERSION_MAJOR_AJ161 = 6;
        public final static short WEAVER_VERSION_MINOR_AJ161 = 0;

        // 1.6.9 adds new style ITDs. This is used to see what version of AJ was used to
        // build the ITDs so we know id the generated get/set dispatchers are using old
        // or new style (new style will be get/setters for private ITD fields)
        public final static short WEAVER_VERSION_AJ169 = 7;

        // These are the weaver major/minor versions for *this* weaver
        private final static short CURRENT_VERSION_MAJOR = WEAVER_VERSION_AJ169;
        private final static short CURRENT_VERSION_MINOR = 0;

        public final static WeaverVersionInfo UNKNOWN = new WeaverVersionInfo(WEAVER_VERSION_MAJOR_UNKNOWN,
                WEAVER_VERSION_MINOR_UNKNOWN);
        public final static WeaverVersionInfo CURRENT = new WeaverVersionInfo(CURRENT_VERSION_MAJOR,
                CURRENT_VERSION_MINOR);

        // These are the versions read in from a particular class file.
        private final short major_version;
        private final short minor_version;

        private long buildstamp = Version.NOTIME;

        @Override
        public String getNameString() {
            return AttributeName;
        }

        // Default ctor uses the current version numbers
        public WeaverVersionInfo() {
            major_version = CURRENT_VERSION_MAJOR;
            minor_version = CURRENT_VERSION_MINOR;
        }

        public WeaverVersionInfo(short major, short minor) {
            major_version = major;
            minor_version = minor;
        }

        @Override
        public void write(CompressingDataOutputStream s) throws IOException {
            s.writeShort(CURRENT_VERSION_MAJOR);
            s.writeShort(CURRENT_VERSION_MINOR);
            s.writeLong(Version.getTime()); // build used to construct the
            // class...
        }

        public static WeaverVersionInfo read(VersionedDataInputStream s) throws IOException {
            short major = s.readShort();
            short minor = s.readShort();
            WeaverVersionInfo wvi = new WeaverVersionInfo(major, minor);
            if (s.getMajorVersion() >= WEAVER_VERSION_MAJOR_AJ150M4) {
                long stamp = 0;
                try {
                    stamp = s.readLong();
                    wvi.setBuildstamp(stamp);
                } catch (EOFException eof) {
                    // didnt find that build stamp - its not the end of the
                    // world
                }
            }
            return wvi;
        }

        public short getMajorVersion() {
            return major_version;
        }

        public short getMinorVersion() {
            return minor_version;
        }

        public static short getCurrentWeaverMajorVersion() {
            return CURRENT_VERSION_MAJOR;
        }

        public static short getCurrentWeaverMinorVersion() {
            return CURRENT_VERSION_MINOR;
        }

        public void setBuildstamp(long stamp) {
            buildstamp = stamp;
        }

        public long getBuildstamp() {
            return buildstamp;
        }

        @Override
        public String toString() {
            return major_version + "." + minor_version;
        }

        public static String toCurrentVersionString() {
            return CURRENT_VERSION_MAJOR + "." + CURRENT_VERSION_MINOR;
        }

    }

    public static class SourceContextAttribute extends AjAttribute {
        public static final String AttributeName = "org.aspectj.weaver.SourceContext";

        @Override
        public String getNameString() {
            return AttributeName;
        }

        private final String sourceFileName;
        private final int[] lineBreaks;

        public SourceContextAttribute(String sourceFileName, int[] lineBreaks) {
            this.sourceFileName = sourceFileName;
            this.lineBreaks = lineBreaks;
        }

        @Override
        public void write(CompressingDataOutputStream s) throws IOException {
            if (s.canCompress()) {
                s.writeCompressedPath(sourceFileName);
            } else {
                s.writeUTF(sourceFileName);
            }
            s.writeInt(lineBreaks.length);
            int previous = 0;
            for (int i = 0, max = lineBreaks.length; i < max; i++) {
                s.writeShort(lineBreaks[i] - previous);
                previous = lineBreaks[i];
            }
        }

        public static SourceContextAttribute read(VersionedDataInputStream s) throws IOException {
            String sourceFileName = s.isAtLeast169() ? s.readPath() : s.readUTF();
            int lineBreaks = s.readInt();
            int[] lines = new int[lineBreaks];
            int previous = 0;
            for (int i = 0; i < lineBreaks; i++) {
                if (s.isAtLeast169()) {
                    lines[i] = s.readShort() + previous;
                    previous = lines[i];
                } else {
                    lines[i] = s.readInt();
                }
            }
            return new SourceContextAttribute(sourceFileName, lines);
        }

        public int[] getLineBreaks() {
            return lineBreaks;
        }

        public String getSourceFileName() {
            return sourceFileName;
        }
    }

    public static class MethodDeclarationLineNumberAttribute extends AjAttribute {

        public static final String AttributeName = "org.aspectj.weaver.MethodDeclarationLineNumber";

        @Override
        public String getNameString() {
            return AttributeName;
        }

        private final int lineNumber;

        // AV: added in 1.5 M3 thus handling cases where we don't have that
        // information
        private final int offset;

        public MethodDeclarationLineNumberAttribute(int line, int offset) {
            lineNumber = line;
            this.offset = offset;
        }

        public int getLineNumber() {
            return lineNumber;
        }

        public int getOffset() {
            return offset;
        }

        @Override
        public void write(CompressingDataOutputStream s) throws IOException {
            s.writeInt(lineNumber);
            s.writeInt(offset);
        }

        public static MethodDeclarationLineNumberAttribute read(VersionedDataInputStream s) throws IOException {
            int line = s.readInt();
            int offset = 0;
            if (s.available() > 0) {
                offset = s.readInt();
            }
            return new MethodDeclarationLineNumberAttribute(line, offset);
        }

        @Override
        public String toString() {
            return AttributeName + ": " + lineNumber + ":" + offset;
        }
    }

    public static class PointcutDeclarationAttribute extends AjAttribute {
        public static final String AttributeName = "org.aspectj.weaver.PointcutDeclaration";

        @Override
        public String getNameString() {
            return AttributeName;
        }

        private final ResolvedPointcutDefinition pointcutDef;

        public PointcutDeclarationAttribute(ResolvedPointcutDefinition pointcutDef) {
            this.pointcutDef = pointcutDef;
        }

        @Override
        public void write(CompressingDataOutputStream s) throws IOException {
            pointcutDef.write(s);
        }

        public ResolvedPointcutDefinition reify() {
            return pointcutDef;
        }
    }

    public static class DeclareAttribute extends AjAttribute {
        public static final String AttributeName = "org.aspectj.weaver.Declare";

        @Override
        public String getNameString() {
            return AttributeName;
        }

        private final Declare declare;

        public DeclareAttribute(Declare declare) {
            this.declare = declare;
        }

        @Override
        public void write(CompressingDataOutputStream s) throws IOException {
            declare.write(s);
        }

        public Declare getDeclare() {
            return declare;
        }
    }

    public static class AdviceAttribute extends AjAttribute {
        public static final String AttributeName = "org.aspectj.weaver.Advice";

        @Override
        public String getNameString() {
            return AttributeName;
        }

        private final AdviceKind kind;
        private final Pointcut pointcut;
        private final int extraParameterFlags;
        private final int start;
        private final int end;
        private final ISourceContext sourceContext;

        // these are only used by around advice
        private boolean proceedInInners;
        private ResolvedMember[] proceedCallSignatures; // size == # of proceed
        // calls in body
        private boolean[] formalsUnchangedToProceed; // size == formals.size
        private UnresolvedType[] declaredExceptions;

        /**
         * @param lexicalPosition must be greater than the lexicalPosition of any advice declared before this one in an aspect,
         *        otherwise, it can be any value.
         */
        public AdviceAttribute(AdviceKind kind, Pointcut pointcut, int extraArgumentFlags, int start, int end,
                ISourceContext sourceContext) {
            this.kind = kind;
            this.pointcut = pointcut;
            extraParameterFlags = extraArgumentFlags;
            this.start = start;
            this.end = end;
            this.sourceContext = sourceContext;

            // XXX put this back when testing works better (or fails better)
            // if (kind == AdviceKind.Around) throw new
            // IllegalArgumentException("not for around");
        }

        public AdviceAttribute(AdviceKind kind, Pointcut pointcut, int extraArgumentFlags, int start, int end,
                ISourceContext sourceContext, boolean proceedInInners, ResolvedMember[] proceedCallSignatures,
                boolean[] formalsUnchangedToProceed, UnresolvedType[] declaredExceptions) {
            this.kind = kind;
            this.pointcut = pointcut;
            extraParameterFlags = extraArgumentFlags;
            this.start = start;
            this.end = end;
            this.sourceContext = sourceContext;

            if (kind != AdviceKind.Around) {
                throw new IllegalArgumentException("only for around");
            }

            this.proceedInInners = proceedInInners;
            this.proceedCallSignatures = proceedCallSignatures;
            this.formalsUnchangedToProceed = formalsUnchangedToProceed;
            this.declaredExceptions = declaredExceptions;
        }

        public static AdviceAttribute read(VersionedDataInputStream s, ISourceContext context) throws IOException {
            AdviceKind kind = AdviceKind.read(s);
            if (kind == AdviceKind.Around) {
                return new AdviceAttribute(kind, Pointcut.read(s, context), s.readByte(), s.readInt(), s.readInt(),
                        context, s.readBoolean(), ResolvedMemberImpl.readResolvedMemberArray(s, context),
                        FileUtil.readBooleanArray(s), UnresolvedType.readArray(s));
            } else {
                return new AdviceAttribute(kind, Pointcut.read(s, context), s.readByte(), s.readInt(), s.readInt(),
                        context);
            }
        }

        @Override
        public void write(CompressingDataOutputStream s) throws IOException {
            kind.write(s);
            pointcut.write(s);
            s.writeByte(extraParameterFlags);
            s.writeInt(start);
            s.writeInt(end);

            if (kind == AdviceKind.Around) {
                s.writeBoolean(proceedInInners);
                ResolvedMemberImpl.writeArray(proceedCallSignatures, s);
                FileUtil.writeBooleanArray(formalsUnchangedToProceed, s);
                UnresolvedType.writeArray(declaredExceptions, s);
            }
        }

        public Advice reify(Member signature, World world, ResolvedType concreteAspect) {
            return world.getWeavingSupport().createAdviceMunger(this, pointcut, signature, concreteAspect);
        }

        @Override
        public String toString() {
            return "AdviceAttribute(" + kind + ", " + pointcut + ", " + extraParameterFlags + ", " + start + ")";
        }

        public int getExtraParameterFlags() {
            return extraParameterFlags;
        }

        public AdviceKind getKind() {
            return kind;
        }

        public Pointcut getPointcut() {
            return pointcut;
        }

        public UnresolvedType[] getDeclaredExceptions() {
            return declaredExceptions;
        }

        public boolean[] getFormalsUnchangedToProceed() {
            return formalsUnchangedToProceed;
        }

        public ResolvedMember[] getProceedCallSignatures() {
            return proceedCallSignatures;
        }

        public boolean isProceedInInners() {
            return proceedInInners;
        }

        public int getEnd() {
            return end;
        }

        public ISourceContext getSourceContext() {
            return sourceContext;
        }

        public int getStart() {
            return start;
        }

    }

    public static class Aspect extends AjAttribute {
        public static final String AttributeName = "org.aspectj.weaver.Aspect";

        @Override
        public String getNameString() {
            return AttributeName;
        }

        private final PerClause perClause;
        private IScope resolutionScope;

        public Aspect(PerClause perClause) {
            this.perClause = perClause;
        }

        public PerClause reify(ResolvedType inAspect) {
            // XXXperClause.concretize(inAspect);
            return perClause;
        }

        public PerClause reifyFromAtAspectJ(ResolvedType inAspect) {
            perClause.resolve(resolutionScope);
            return perClause;
        }

        @Override
        public void write(CompressingDataOutputStream s) throws IOException {
            perClause.write(s);
        }

        public void setResolutionScope(IScope binding) {
            resolutionScope = binding;
        }
    }

    public static class PrivilegedAttribute extends AjAttribute {

        public static final String AttributeName = "org.aspectj.weaver.Privileged";

        private final ResolvedMember[] accessedMembers;

        public PrivilegedAttribute(ResolvedMember[] accessedMembers) {
            this.accessedMembers = accessedMembers;
        }

        @Override
        public void write(CompressingDataOutputStream s) throws IOException {
            ResolvedMemberImpl.writeArray(accessedMembers, s);
        }

        public ResolvedMember[] getAccessedMembers() {
            return accessedMembers;
        }

        public static PrivilegedAttribute read(VersionedDataInputStream stream, ISourceContext context)
                throws IOException {
            PrivilegedAttribute pa = new PrivilegedAttribute(
                    ResolvedMemberImpl.readResolvedMemberArray(stream, context));
            return pa;
        }

        @Override
        public String getNameString() {
            return AttributeName;
        }
    }

    public static class EffectiveSignatureAttribute extends AjAttribute {
        public static final String AttributeName = "org.aspectj.weaver.EffectiveSignature";

        @Override
        public String getNameString() {
            return AttributeName;
        }

        private final ResolvedMember effectiveSignature;
        private final Shadow.Kind shadowKind;
        private final boolean weaveBody;

        public EffectiveSignatureAttribute(ResolvedMember effectiveSignature, Shadow.Kind shadowKind,
                boolean weaveBody) {
            this.effectiveSignature = effectiveSignature;
            this.shadowKind = shadowKind;
            this.weaveBody = weaveBody;
        }

        @Override
        public void write(CompressingDataOutputStream s) throws IOException {
            effectiveSignature.write(s);
            shadowKind.write(s);
            s.writeBoolean(weaveBody);
        }

        public static EffectiveSignatureAttribute read(VersionedDataInputStream s, ISourceContext context)
                throws IOException {
            ResolvedMember member = ResolvedMemberImpl.readResolvedMember(s, context);
            return new EffectiveSignatureAttribute(member, Shadow.Kind.read(s), s.readBoolean());
        }

        public ResolvedMember getEffectiveSignature() {
            return effectiveSignature;
        }

        @Override
        public String toString() {
            return "EffectiveSignatureAttribute(" + effectiveSignature + ", " + shadowKind + ")";
        }

        public Shadow.Kind getShadowKind() {
            return shadowKind;
        }

        public boolean isWeaveBody() {
            return weaveBody;
        }

    }

}