Package org.apache.beehive.controls.runtime.generator

Source Code of org.apache.beehive.controls.runtime.generator.AptControlInterface

package org.apache.beehive.controls.runtime.generator;
/*
* Copyright 2004 The Apache Software Foundation.
*
* Licensed 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.
*
* $Header:$
*/

import java.io.*;
import java.lang.reflect.*;
import java.lang.annotation.*;
import java.net.*;
import java.util.*;

import com.sun.mirror.apt.Filer;
import com.sun.mirror.declaration.AnnotationMirror;
import com.sun.mirror.declaration.AnnotationTypeDeclaration;
import com.sun.mirror.declaration.Declaration;
import com.sun.mirror.declaration.InterfaceDeclaration;
import com.sun.mirror.declaration.MethodDeclaration;
import com.sun.mirror.declaration.TypeDeclaration;
import com.sun.mirror.type.DeclaredType;
import com.sun.mirror.type.InterfaceType;
import com.sun.mirror.type.MirroredTypesException;

import org.apache.beehive.controls.api.bean.ControlChecker;
import org.apache.beehive.controls.api.bean.ControlExtension;
import org.apache.beehive.controls.api.bean.ControlInterface;
import org.apache.beehive.controls.api.bean.ExternalPropertySets;
import org.apache.beehive.controls.api.events.EventSet;
import org.apache.beehive.controls.api.packaging.FeatureInfo;
import org.apache.beehive.controls.api.packaging.ManifestAttribute;
import org.apache.beehive.controls.api.packaging.ManifestAttributes;
import org.apache.beehive.controls.api.properties.PropertySet;
import org.apache.beehive.controls.api.versioning.Version;
import org.apache.beehive.controls.api.versioning.VersionRequired;
import org.apache.beehive.controls.runtime.generator.apt.TwoPhaseAnnotationProcessor;

/**
* The AptControlInterface provides validation and metadata management for a ControlInterface
* or ControlExtension class during APT processing.  It is also used to model the interface
* to contextual services, since they parallel the conventions of control interfaces.
*/
public class AptControlInterface extends AptType implements Generator
{
    /**
     * Constructs a new AptControlInterface instance where interface information is derived
     * from an APT interface declaration
     * @param decl the annotated Declaration
     * @param ap the top-level annotation processor
     */
    public AptControlInterface(Declaration decl, TwoPhaseAnnotationProcessor ap)
    {
        _ap = ap;

        //
        // Verify that the @ControlInterface/@ControlExtension annotations are only used on an
        // interface.
        // Note: AptControlInterface is also used to construct the operation and event model
        // for contextual services (see AptContextField).  Becaue contextual sevices can actually
        // be classes as well as interfaces, the test below has to be specific to the annotated
        // use cases
        //
        if (! (decl instanceof InterfaceDeclaration) &&
              (decl.getAnnotation(ControlExtension.class) != null ||
               decl.getAnnotation(ControlInterface.class) != null))
        {
            _ap.printError(decl, "control.interface.annotation.badlocation" );
            return;
        }

        _intfDecl = (InterfaceDeclaration)decl;
        setDeclaration(_intfDecl);

        _isExtension = initIsExtension();

        _superClass = initSuperClass();

        _operations = initOperations();

        _propertySets = initPropertySets();

        _eventSets = initEventSets();

        _featureInfo = initFeatureInfo();

        _version = initVersion();
        _versionRequired = initVersionRequired();

        //
        // Construct a bean instance for this interface
        //
        _bean = new ControlBean(this);

        //
        // Enforce VersionRequired semantics
        //
        enforceVersionRequired();

        //
        // Do work specific to control extensions
        //

        if (isExtension())
        {
            //
            // If this is an control extension, run the control-author-specified
            // checker class to perform additional validation.
            //
            check();
        }
    }

    /**
     * Returns the parent control interface or extension type from which the control
     * interface is derived (or null, if it is at the root of the interface hierarchy)
     */
    public InterfaceType getSuperType()
    {
        if ( _intfDecl.getSuperinterfaces() == null )
            return null;

        for (InterfaceType intfType : _intfDecl.getSuperinterfaces())
        {
            InterfaceDeclaration superDecl = intfType.getDeclaration();
            if ( superDecl != null )
            {
                if (superDecl.getAnnotation(ControlExtension.class) != null ||
                    superDecl.getAnnotation(ControlInterface.class) != null)
                {
                    _superDecl = superDecl;
                    return intfType;
                }
            }
        }

        return null;
    }

    /**
     * Initializes the super interface that this ControlInterface extends (or sets it to null
     * if a base interface)
     */
    private AptControlInterface initSuperClass()
    {
        //
        // Look for a super interface that is either a control interface or extension.
        // If found, return it.
        //
        InterfaceType superType = getSuperType();
        if (superType == null)
        {
            // At this point, we're processing the root of the interface heirarchy,
            // which is not permitted to be a ControlExtension (that would imply a
            // ControlExtension that wasn't actually extending a ControlInterface).
            if ( isExtension() )
            {
                _ap.printError( _intfDecl, "control.extension.badinterface");
            }

            return null;
        }

        InterfaceDeclaration superDecl = superType.getDeclaration();
        if ( superDecl != null )
        {
            if (superDecl.getAnnotation(ControlExtension.class) != null ||
                superDecl.getAnnotation(ControlInterface.class) != null)
            {
                _superDecl = superDecl;
                AptControlInterface superIntf = new AptControlInterface(_superDecl, _ap);

                if (!isExtension() && superIntf.isExtension())
                {
                    _ap.printError( _intfDecl, "control.interface.badinterface");
                }
                return superIntf;
            }
        }

        return null;
    }

    /**
     * Returns the super interface for this interface
     */
    public AptControlInterface getSuperClass() { return _superClass; }

    /**
     * Initializes the list of operations declared by this AptControlInterface
     */
    private AptMethodSet<AptOperation> initOperations()
    {
        AptMethodSet<AptOperation> operList = new AptMethodSet<AptOperation>();

        if ( _intfDecl == null )
            return operList;

        //
        // Add the methods from the current interface and all super interfaces *other*
        // than the one from which control inheritance or extension is defined.  These
        // exceptions are handled on the super ControlInterface (the return value
        // of AptControlInterface.initSuperClass())
        //
        // Do this by:
        //  - initially populate the check vector with the control interface
        //  - iterate through the check vector, examining each interface to:
        //      * ignore the super interface
        //      * add all declared interface methods to the operations list
        //      * add any super interfaces to the Vector (avoiding recursion)
        //  - the iteration continues until all superinterfaces have been processed
        //
        Vector<InterfaceDeclaration> checkIntfs = new Vector<InterfaceDeclaration>();
        checkIntfs.add(_intfDecl);

        for (int i = 0; i < checkIntfs.size(); i++)
        {
            InterfaceDeclaration intfDecl = checkIntfs.elementAt(i);
            if (intfDecl.equals(_superDecl))
                continue;

            if ( intfDecl.getMethods() == null )
                continue;

            // Add all declared methods, but ignore the mystery <clinit> methods
            for (MethodDeclaration methodDecl : intfDecl.getMethods())
                if (!methodDecl.toString().equals("<clinit>()"))
                    operList.add(new AptOperation(this, methodDecl, _ap));

            if ( intfDecl.getSuperinterfaces() == null )
                continue;

            for (InterfaceType superType : intfDecl.getSuperinterfaces())
            {
                InterfaceDeclaration superDecl = superType.getDeclaration();
                if (superDecl != null && !checkIntfs.contains(superDecl))
                    checkIntfs.add(superDecl);
            }
        }

        return operList;
    }

    /**
     * Returns the list of ControlOperations declared directly by this AptControlInterface
     */
    public Collection<AptOperation> getOperations() { return _operations.getMethods(); }

    /**
     * Returns the total number of operations for this control interface
     */
    public int getOperationCount()
    {
        int count = _operations.size();
        if (_superClass != null)
            count += _superClass.getOperationCount();

        return count;
    }

    /**
     * Initializes the list of PropertySets declared or referenced by this AptControlInterface
     */
    private ArrayList<AptPropertySet> initPropertySets()
    {
        ArrayList<AptPropertySet> propSets = new ArrayList<AptPropertySet>();

        if ( _intfDecl == null )
            return propSets;

        // TODO: enforce presence of prefixes when multiple property sets w/ the same
        // property name exist

        //
        // Add the intrinsic/base property set
        //

        TypeDeclaration basePropsDecl =
            _ap.getAnnotationProcessorEnvironment().getTypeDeclaration( "org.apache.beehive.controls.api.properties.BaseProperties" );
        if ( basePropsDecl != null )
        {
            propSets.add( new AptPropertySet( null, basePropsDecl, _ap ) );
        }

        //
        // Add external property sets
        //
        ExternalPropertySets extPropsAnnotation = _intfDecl.getAnnotation(ExternalPropertySets.class);
        if ( extPropsAnnotation != null )
        {
            if (isExtension())
            {
                _ap.printError( _intfDecl, "extpropertyset.illegal.usage" );
            }

            try
            {
                Class[] extProps = extPropsAnnotation.value();
            }
            catch ( MirroredTypesException mte )
            {
                Collection<String> extProps = mte.getQualifiedNames();
                for ( String extPropName : extProps )
                {
                    TypeDeclaration extPropDecl = _ap.getAnnotationProcessorEnvironment().getTypeDeclaration( extPropName );
                    if ( extPropDecl != null )
                    {
                        AptPropertySet extPropSet = new AptPropertySet( null, extPropDecl, _ap );
                        propSets.add( extPropSet );
                    }
                    else
                    {
                        _ap.printError( _intfDecl, "extpropertyset.type.not.found", extPropName );
                    }
                }
            }
        }

        //
        // Add nested property sets
        //

        if ( _intfDecl.getNestedTypes() == null )
            return propSets;

        for (TypeDeclaration innerDecl : _intfDecl.getNestedTypes())
        {
            boolean fError = false;

            // HACKHACK: There appear to be mirror API bugs where calling getAnnotation()
            // on certain entity types will result in an endless loop.  For now, work around
            // this by a priori filtering... but this mechanism will drop errors that appear
            // on an inapropriate type (see check below)
            if (! (innerDecl instanceof AnnotationTypeDeclaration))
                continue;

            if (innerDecl.getAnnotation(PropertySet.class) != null)
            {
                if (! (innerDecl instanceof AnnotationTypeDeclaration))
                {
                    _ap.printError( innerDecl, "propertyset.not.annotation.type" );
                    fError = true;
                }

                Retention ret = innerDecl.getAnnotation(Retention.class);
                if (ret == null || ret.value() != RetentionPolicy.RUNTIME)
                {
                    _ap.printError( innerDecl, "propertyset.missing.retention" );
                    fError = true;
                }

                if (isExtension())
                {
                    _ap.printError( innerDecl, "propertyset.illegal.usage.2" );
                    fError = true;
                }

                if ( !fError )
                    propSets.add(
                        new AptPropertySet(this, (AnnotationTypeDeclaration)innerDecl, _ap));
            }
        }

        //
        // Detect the presence of locally declared bound or constrained properties
        // Enforce property name (including prefix) uniqueness across all propertysets on this interface.
        //

        Set<String> propertyNames = new HashSet<String>();

        for (AptPropertySet propSet : propSets)
        {
            for (AptProperty prop : propSet.getProperties())
            {
                if (prop.isBound())
                    _hasBoundProperties = true;

                if (prop.isConstrained())
                    _hasConstrainedProperties = true;

                String propName = prop.getAccessorName();

                if ( propertyNames.contains( propName ) )
                {
                    _ap.printError( _intfDecl, "propertyset.duplicate.property.names", propName, propSet.getShortName() );
                }
                else
                {
                    propertyNames.add( propName );
                }
            }
        }

        return propSets;
    }

    /**
     * Returns the list of PropertySets declared directly by this AptControlInterface
     */
    public Collection<AptPropertySet> getPropertySets() { return _propertySets; }

    /**
     * Returns the total number of properties for this control interface
     */
    public int getPropertyCount()
    {
        int count;
        if (_superClass == null)
            count = 0;
        else
            count = _superClass.getPropertyCount();

        for (AptPropertySet propertySet : _propertySets)
            count += propertySet.getProperties().size();

        return count;
    }

    /**
     * Returns true if the interface has any bound properties associated with it.
     */
    public boolean hasBoundProperties()
    {
        if (_superClass != null && _superClass.hasBoundProperties())
            return true;

        return _hasBoundProperties;
    }

    /**
     * Returns true if this interface is the first interface in the inheritance hierarchy
     * to declare support for bound properties.  This is used to declared PropertyChangeListener
     * registration methods for the bean once (and only once).
     */
    public boolean addsBoundPropertySupport()
    {
        //
        // If a super interface has already added support, then not added here
        //
        if (_superClass != null && _superClass.addsBoundPropertySupport())
            return false;

        return hasBoundProperties();
    }

    /**
     * Returns true if any properties declared directly by this control interface are constrained
     * properties.  This <b>will not</b> reflect the attributes of properties declared on
     * an interface from which this interface derives.
     */
    public boolean hasConstrainedProperties()
    {
        if (_superClass != null && _superClass.hasConstrainedProperties())
            return true;

        return _hasConstrainedProperties;
    }

    /**
     * Returns true if this interface is the first interface in the inheritance hierarchy
     * to declare support for constrained properties.  This is used to declared
     * VetoableChangeListener registration methods for the bean once (and only once).
     */
    public boolean addsConstrainedPropertySupport()
    {
        //
        // If a super interface has already added support, then not added here
        //
        if (_superClass != null && _superClass.addsConstrainedPropertySupport())
            return false;

        return hasConstrainedProperties();
    }

    /**
     * Initializes the list of EventSets declared by this AptControlInterface
     */
    private ArrayList<AptEventSet> initEventSets()
    {
        ArrayList<AptEventSet> eventSets = new ArrayList<AptEventSet>();

        if ( _intfDecl == null || _intfDecl.getNestedTypes() == null )
            return eventSets;

        for (TypeDeclaration innerDecl : _intfDecl.getNestedTypes())
        {
            // HACKHACK: There appear to be mirror API bugs where calling getAnnotation()
            // on certain entity types will result in an endless loop.  For now, work around
            // this by a priori filtering... but this mechanism will drop errors that appear
            // on an inapropriate type (see check below)
            if (! (innerDecl instanceof InterfaceDeclaration))
                continue;

            if (innerDecl.getAnnotation(EventSet.class) != null)
            {

                if (! (innerDecl instanceof InterfaceDeclaration))
                {
                    _ap.printError( innerDecl, "eventset.illegal.usage" );
                }
                else
                {
                    eventSets.add(
                        new AptEventSet(this, (InterfaceDeclaration)innerDecl, _ap));
                }
            }
        }
        return eventSets;
    }

    /**
     * Returns the list of AptEventSet declared directly by this AptControlInterface
     */
    public Collection<AptEventSet> getEventSets() { return _eventSets; }

    /**
     * Returns the total number of operations for this control interface
     */
    public int getEventSetCount()
    {
        int count = _eventSets.size();
        if (_superClass != null)
            count += _superClass.getEventSetCount();

        return count;
    }

    /**
     * Returns the AptEventSet with the specified name
     */
    public AptEventSet getEventSet(String name)
    {
        for (AptEventSet eventSet: getEventSets())
            if (eventSet.getClassName().equals(name))
                return eventSet;

        if (_superClass != null)
            return _superClass.getEventSet(name);

        return null;
    }

    /**
     * Returns the FeatureInfo attributes for this control interface
     */
    public FeatureInfo getFeatureInfo() { return _featureInfo; }

    /**
     * Returns the list of fully qualified class names for types that are derived
     * from this Generator
     */
    public String [] getGeneratedTypes()
    {
        return new String [] { _bean.getClassName() };
    }

    /**
     * Returns the Version annotation, if any.
     */
    public Version getVersion()
    {
        return _version;
    }

    /**
     * Returns the VersionRequired annotation, if any.
     */
    public VersionRequired getVersionRequired()
    {
        return _versionRequired;
    }

    /**
     * Returns the information necessary to generate a ControlBean from this AptControlInterface
     */
    public List<GeneratorOutput> getCheckOutput(Filer filer) throws IOException
    {
        HashMap<String,Object> map = new HashMap<String,Object>();

        map.put("intf", this);                  // the control interface
        map.put("bean", _bean);

        ArrayList<GeneratorOutput> genList = new ArrayList<GeneratorOutput>();

        //
        // the ControlBean class
        //
        Writer beanWriter = new IndentingWriter(filer.createSourceFile(_bean.getClassName()));
        GeneratorOutput beanSource =
            new GeneratorOutput(beanWriter,
                               "org/apache/beehive/controls/runtime/generator/ControlBean.vm", map);
        genList.add(beanSource);

        //
        // the ControlBean BeanInfo class
        //
        Writer beanInfoWriter = new IndentingWriter(filer.createSourceFile(_bean.getBeanInfoName()));
        GeneratorOutput beanInfoSource =
            new GeneratorOutput(beanInfoWriter,
                "org/apache/beehive/controls/runtime/generator/ControlBeanInfo.vm", map);
        genList.add(beanInfoSource);

        return genList;
    }

    /**
     * Returns the information necessary to generate a packaging information from this
     * AptControlInterface.  Since this information is not needed during type validation,
     * it can be delated until the generate phase.
     */
    public List<GeneratorOutput> getGenerateOutput(Filer filer) throws IOException
    {
        HashMap<String,Object> map = new HashMap<String,Object>();

        map.put("intf", this);                  // the control interface
        map.put("bean", _bean);

        ArrayList<GeneratorOutput> genList = new ArrayList<GeneratorOutput>();

        //
        // the ControlBean MANIFEST.MF section
        //
        Writer manifestWriter = filer.createTextFile(Filer.Location.CLASS_TREE, _bean.getPackage(),
                                          new File(_bean.getShortName() + ".class.manifest"),
                                          null);
        GeneratorOutput beanManifest =
            new GeneratorOutput(manifestWriter,
                                "org/apache/beehive/controls/runtime/generator/ControlManifest.vm",
                                map);
        genList.add(beanManifest);

        return genList;
    }

    /**
     * Returns true if this interface is a ControlExtension (jcx) interface, false
     * otherwise.
     */
    public boolean isExtension()
    {
        return _isExtension;
    }

    /**
     * Returns the most-derived interface in the inheritance chain that is annotated
     * with @ControlInterface.  It represents the point in the inheritance chain
     * where @ControlInterface becomes @ControlExtension (i.e., anything interface derived from
     * the 'most-derived interface' is annotated with @ControlExtension).  May return
     * null if the inheritance chain is malformed.
     */
    public AptControlInterface getMostDerivedInterface()
    {
        //
        // Walk up ControlInterface chain looking for the 1st instance annotated
        // w/ @ControlInterface (as opposed to @ControlExtension)
        //
        // REVIEW: TBD rules for inheritance of @ControlInterface will affect this.
        // Probably need to keep walking and examine each @ControlInterface in the chain.
        // Run all checkers in chain?  Make checkers responsible for invoking their base
        // class-defined checkers?
        //

        AptControlInterface ancestor = getSuperClass();
        while (ancestor != null)
        {
            if (!ancestor.isExtension())
                break;

            ancestor = ancestor.getSuperClass();
        }

        return ancestor;
    }

    /**
     * Returns a classloader that can be used to load external classes
     */
    public ClassLoader getExternalClassLoader()
    {
        Map<String,String> opts = _ap.getAnnotationProcessorEnvironment().getOptions();
        String classpath = opts.get("-classpath");

        if ( classpath != null )
        {
            String [] cpEntries = classpath.split( File.pathSeparator );
            ArrayList a = new ArrayList();
            for ( String e : cpEntries )
            {
                try
                {
                    File f = (new File(e)).getCanonicalFile();
                    URL u = f.toURL();
                    a.add(u);
                }
                catch (Exception ex)
                {
                    System.err.println( "getExternalClassLoader(): bad cp entry=" + e );
                    System.err.println( "Exception processing e=" + ex );
                }
            }
            URL [] urls = new URL[a.size()];
            urls = (URL[]) a.toArray(urls);

            return new URLClassLoader( urls, ControlChecker.class.getClassLoader() );
        }

        return null;
    }

    //
    // These are defined by the JAR spec, Name-value pair section
    //
    static final String alphaNum = "ABCDEFGHIJKLMNOPQRSUVWXYZabcdefghijklmnopqrstuvwyz0123456789";
    static final String headerChar = alphaNum + "_-";

    /**
     *  Validates a manifest attribute.  If the attribute is invalid, it will generate
     *  appropriate APT messager entries and return false, else return true.
     */
    private boolean isValidManifestAttribute(ManifestAttribute attr)
    {
        String name = attr.name();
        String value = attr.value();
        boolean isValid = true;
        if (name.length() == 0)
        {
            _ap.printError( _intfDecl, "manifestattribute.illegal.name.1" );
            isValid = false;
        }
        else
        {
            if (alphaNum.indexOf(name.charAt(0)) < 0)
            {
                _ap.printError( _intfDecl, "manifestattribute.illegal.name.2" );
                isValid = false;
            }
            for (int i = 1; i < name.length(); i++)
            {
                if (headerChar.indexOf(name.charAt(i)) < 0)
                {
                    _ap.printError( _intfDecl, "manifestattribute.illegal.name.3", name.charAt(i) );
                    isValid = false;
                    break;
                }
            }
        }

        if (value.length() == 0)
        {
            _ap.printError( _intfDecl, "manifestattribute.illegal.name.4" );
            isValid = false;
        }
        else
        {
            // TODO: validate string contents are valid UTF-8?
        }

        return isValid;
    }

    /**
     * Returns the array of ManifestAttributes associated with the AptControlInterface
     */
    public HashMap<String, String> getManifestAttributes()
    {
        HashMap<String,String> attributes = new HashMap<String,String>();

        if ( _intfDecl == null )
            return attributes;

        try
        {
            ManifestAttributes annotAttrs =_intfDecl.getAnnotation(ManifestAttributes.class);
            if (annotAttrs != null)
            {
                ManifestAttribute [] attrs = (ManifestAttribute [])annotAttrs.value();
                for (int i = 0; i < attrs.length; i++)
                {
                    if (isValidManifestAttribute(attrs[i]))
                        attributes.put(attrs[i].name(), attrs[i].value());
                }
            }
            ManifestAttribute annotAttr = _intfDecl.getAnnotation(ManifestAttribute.class);
            if (annotAttr != null)
            {
                if (isValidManifestAttribute(annotAttr))
                    attributes.put(annotAttr.name(), annotAttr.value());
            }
            return attributes;
        }
        catch (Exception e) { e.printStackTrace(); return attributes; }
    }

    /**
     * Computes whether this interface is a ControlInterface or a ControlExtension
     */
    private boolean initIsExtension()
    {
        if ( _intfDecl == null )
            return false;

        return _intfDecl.getAnnotation(ControlExtension.class) != null;
    }

    /**
     * Returns the FeatureInfo annotation for this control interface, or null if there is none.
     */
    private FeatureInfo initFeatureInfo()
    {
        if ( _intfDecl == null )
            return null;
        return _intfDecl.getAnnotation(FeatureInfo.class);
    }

    /**
     * Returns the Version annotation for this control interface, or null if there is none.
     */
    private Version initVersion()
    {
        if ( _intfDecl == null )
            return null;
        return _intfDecl.getAnnotation(Version.class);
    }

    /**
     * Returns the VersionRequired annotation for this control interface, or null if there is none.
     */
    private VersionRequired initVersionRequired()
    {
        if ( _intfDecl == null )
            return null;
        return _intfDecl.getAnnotation(VersionRequired.class);
    }

    /**
     * Enforces the VersionRequired annotation for control extensions.
     */
    private void enforceVersionRequired()
    {
        if ( _versionRequired != null )
        {
            if ( !isExtension() )
            {
                _ap.printError( _intfDecl, "versionrequired.illegal.usage" );
                return;
            }

            int majorRequired = _versionRequired.major();
            int minorRequired = _versionRequired.minor();

            if ( majorRequired < 0 )    // no real version requirement
                return;

            AptControlInterface ci = getMostDerivedInterface();
            if ( ci == null )
                return;

            int majorPresent = -1;
            int minorPresent = -1;
            Version ciVersion = ci._version;
            if ( ciVersion != null )
            {
                majorPresent = ciVersion.major();
                minorPresent = ciVersion.minor();

                if ( majorRequired <= majorPresent &&
                     (minorRequired < 0 || minorRequired <= minorPresent) )
                {
                    // Version requirement is satisfied
                    return;
                }
            }

            //
            // Version requirement failed
            //
            _ap.printError( _intfDecl, "versionrequired.failed", _intfDecl.getSimpleName(),
                    majorRequired, minorRequired, majorPresent, minorPresent );
        }
    }

    /**
     * Runs control-specific checker class (if specified)
     */
    public void check()
    {
        //
        // Find the nearest @ControlInterface, which is where the relevant control checker
        // annotation will be found.
        //

        AptControlInterface mostDerived = (AptControlInterface) getMostDerivedInterface();
        if ( mostDerived == null )
            return;

        InterfaceDeclaration intfDecl = mostDerived._intfDecl;

        if ( intfDecl == null )
            return;

        AnnotationMirror controlMirror = null;

        for (AnnotationMirror annot : intfDecl.getAnnotationMirrors())
        {
            if (annot.getAnnotationType().getDeclaration().getQualifiedName().equals(
                    "org.apache.beehive.controls.api.bean.ControlInterface"))
            {
                controlMirror = annot;
                break;
            }
        }

        assert ( controlMirror != null ) : "Found a control interface that isn't annotated properly: " + intfDecl;

        AptAnnotationHelper controlAnnot = new AptAnnotationHelper(controlMirror);

        //
        // Read the name of the checker class from the @ControlInterface annotation,
        // dynamically load and run it.
        //

        DeclaredType checkerMirror = (DeclaredType)controlAnnot.getObjectValue("checker");
        if ( checkerMirror == null )
        {
            // try the deprecated 'checkerClass' attribute
            checkerMirror = (DeclaredType)controlAnnot.getObjectValue("checkerClass");
        }

        if ( checkerMirror != null && checkerMirror.getDeclaration() != null )
        {
            // TODO: optimize to not invoke default checker?
            String checkerName = checkerMirror.toString();

            try
            {
                ClassLoader loader = getExternalClassLoader();

                Class checkerClass = loader.loadClass( checkerName );
                if ( !ControlChecker.class.isAssignableFrom(checkerClass) )
                {
                    _ap.printError( intfDecl, "control.interface.illegal.checker", intfDecl.getSimpleName(), checkerName );
                }
                else
                {

                    Constructor ctor = checkerClass.getConstructor();

                    ControlChecker checker = (ControlChecker) ctor.newInstance();
                    checker.check( _intfDecl, _ap.getAnnotationProcessorEnvironment() );
                }
            }
            catch ( Exception e )
            {
                e.printStackTrace();
            }
        }
    }

    private AptControlInterface         _superClass;
    private AptMethodSet<AptOperation>  _operations;
    private ArrayList<AptPropertySet>   _propertySets;
    private boolean                     _isExtension;        // true if ControlExtension, else ControlInterface
    private boolean                     _hasBoundProperties;
    private boolean                     _hasConstrainedProperties;;
    private ArrayList<AptEventSet>      _eventSets;
    private ControlBean                 _bean;
    private FeatureInfo                 _featureInfo;
    private Version                     _version;
    private VersionRequired             _versionRequired;
    private InterfaceDeclaration        _intfDecl;
    private InterfaceDeclaration        _superDecl;
    private TwoPhaseAnnotationProcessor  _ap;
}
TOP

Related Classes of org.apache.beehive.controls.runtime.generator.AptControlInterface

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.