Package org.apache.beehive.netui.compiler.xdoclet.typesystem.impl.declaration

Source Code of org.apache.beehive.netui.compiler.xdoclet.typesystem.impl.declaration.AnnotationInterfaceParser

/*
* 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:$
*/
package org.apache.beehive.netui.compiler.xdoclet.typesystem.impl.declaration;

import org.apache.beehive.netui.compiler.JpfLanguageConstants;
import org.apache.beehive.netui.compiler.typesystem.declaration.AnnotationTypeDeclaration;
import org.apache.beehive.netui.compiler.typesystem.declaration.AnnotationTypeElementDeclaration;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StreamTokenizer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;

public class AnnotationInterfaceParser implements JpfLanguageConstants {
    private HashMap _memberArrayAnnotations = new HashMap();
    private HashMap _memberAnnotations = new HashMap();
    private HashSet _memberOrTopLevelAnnotations = new HashSet();
    private String _annotationInterfacePrefix;


    /** Map of String intermediate-name (e.g., "Jpf.Action") to AnnotationTypeDeclaration */
    private HashMap _annotations = new HashMap();
    private AnnotationTypeDeclaration[] _allAnnotations;

    public AnnotationInterfaceParser(String annotationInterfacePrefix)
    {
        _annotationInterfacePrefix = annotationInterfacePrefix;
        parseAnnotations();
        _allAnnotations = ( AnnotationTypeDeclaration[] )
                _annotations.values().toArray( new AnnotationTypeDeclaration[ _annotations.size() ] );
    }
   
    public void addMemberAnnotation(String tagName, String parentAttribute)
    {
        _memberAnnotations.put(_annotationInterfacePrefix + tagName, parentAttribute);
    }
   
    public void addMemberArrayAnnotation(String tagName, String parentAttribute)
    {
        _memberArrayAnnotations.put(_annotationInterfacePrefix + tagName, parentAttribute);
    }
   
    public void addMemberOrTopLevelAnnotation(String tagName)
    {
        _memberOrTopLevelAnnotations.add(_annotationInterfacePrefix + tagName);
    }

    public AnnotationTypeDeclaration[] getAllAnnotations()
    {
        return _allAnnotations;
    }
   
    public AnnotationTypeDeclaration getAnnotationTypeDecl(String tagName)
    {
        return (AnnotationTypeDeclaration) _annotations.get(tagName);
    }

    /**
     * Get the name of the parent annotation member for the given tag.
     */
    public String getParentMemberName(String tagName)
    {
        return (String) _memberAnnotations.get(tagName);
    }
   
    /**
     * Get the name of the parent annotation array member for the given tag.
     */
    public String getParentMemberArrayName(String tagName)
    {
        return (String) _memberArrayAnnotations.get(tagName);
    }
   
    public boolean isMemberOrTopLevelAnnotation(String tagName)
    {
        return _memberOrTopLevelAnnotations.contains(tagName);
    }

    private static StreamTokenizer getJavaTokenizer( Reader reader )
    {
        StreamTokenizer tok = new StreamTokenizer( reader );
        tok.eolIsSignificant( false );
        tok.lowerCaseMode( false );
        tok.parseNumbers();
        tok.slashSlashComments( true );
        tok.slashStarComments( true );
        tok.wordChars( '_', '_' );
        tok.wordChars( '@', '@' );
        tok.wordChars( '[', '[' );
        tok.wordChars( ']', ']' );
        tok.wordChars( '.', '.' );
        tok.wordChars( '"', '"' );
        tok.wordChars( '-', '-' );
        return tok;
    }

    private void parseAnnotations()
    {
        String annotationsSource = ANNOTATIONS_CLASSNAME.replace( '.', '/' ) + ".java";
        InputStream in = DeclarationImpl.class.getClassLoader().getResourceAsStream( annotationsSource );
        assert in != null : "annotations source not found: " + annotationsSource;
        BufferedReader reader = new BufferedReader( new InputStreamReader( in ) );
       
        try
        {
            HashMap enums = new HashMap()// String enumTypeName -> HashSet values
            StreamTokenizer tok = getJavaTokenizer( reader );


            String interfaceQualifier = null;
            String packageName = null;

            while ( tok.nextToken() != StreamTokenizer.TT_EOF )
            {
                switch ( tok.ttype )
                {
                    case StreamTokenizer.TT_WORD:
                        String str = tok.sval;

                        if ( packageName == null && str.equals( "package" ) )
                        {
                            packageName = assertWord( tok );
                        }
                        else if ( str.equals( "public" ) )
                        {
                            str = assertWord( tok );

                            if ( str.equals( "interface" ) )
                            {
                                interfaceQualifier = assertWord( tok ) + '.';
                                assertChar( tok, '{' );
                            }
                            else if ( str.equals( "@interface" ) )
                            {
                                AnnotationTypeDeclarationImpl ann =
                                        readAnnotation( tok, interfaceQualifier, packageName, enums );
                                _annotations.put( ann.getIntermediateName(), ann );

                                /* TODO: re-add in DeclarationImpl
                                //
                                // Special case:
                                //     validationErrorForward=@Jpf.Forward(...)
                                // looks like this in our world:
                                //     @Jpf.ValidationErrorForward(...)
                                // Here we dynamically create a new ValidationErrorForward annotation based on Forward.
                                //
                                if ( ann.getSimpleName().equals( FORWARD_TAG_NAME ) )
                                {
                                    AnnotationTypeDeclarationImpl validationErrorForwardAnn =
                                        new AnnotationTypeDeclarationImpl( ann, VALIDATION_ERROR_FORWARD_TAG_NAME,
                                                                           interfaceQualifier );
                                    _annotations.put( ANNOTATION_INTERFACE_PREFIX + VALIDATION_ERROR_FORWARD_TAG_NAME,
                                                     validationErrorForwardAnn );
                                }
                                */
                            }
                            else if ( str.equals( "enum" ) )
                            {
                                readEnum( tok, enums );
                            }
                        }
                        else if ( str.charAt( 0 ) == '@' )
                        {
                            if (tok.nextToken() == '(')
                            {
                                ignoreAnnotation(tok);
                            }
                            else
                            {
                                tok.pushBack();
                            }
                        }
                        break;

                    case StreamTokenizer.TT_NUMBER:
                        break;

                    default:
                        char c = ( char ) tok.ttype;

                        if ( c == '}' )
                        {
                            assert interfaceQualifier != null;
                            interfaceQualifier = null;
                        }
                }
            }
        }
        catch ( IOException e )
        {
            e.printStackTrace();
            assert false : e;
        }
        finally
        {
            try {
                reader.close();
            } catch (IOException e ) {
                e.printStackTrace();
                assert false : e;
            }
        }
    }

    private static String assertWord( StreamTokenizer tok )
            throws IOException
    {
        tok.nextToken();
        assert tok.ttype == StreamTokenizer.TT_WORD : tok.ttype;
        return tok.sval;
    }

    private static void assertChar( StreamTokenizer tok, char c )
        throws IOException
    {
        tok.nextToken();
        assert tok.ttype == c : tok.ttype;
    }

    private static AnnotationTypeDeclarationImpl readAnnotation( StreamTokenizer tok, String interfaceQualifier,
                                                                 String packageName, HashMap enums )
        throws IOException
    {
        String annotationName = assertWord( tok );
        ArrayList memberDecls = new ArrayList();
        assertChar( tok, '{' );

        while ( tok.nextToken() == StreamTokenizer.TT_WORD )
        {
            String memberType = tok.sval;
            HashSet enumVals = ( HashSet ) enums.get( memberType );

            tok.nextToken();
            if ( tok.ttype == '<' ) // ignore generics
            {
                while ( tok.nextToken() != '>' )
                {
                    assert tok.ttype != StreamTokenizer.TT_EOF;
                    assert tok.ttype != ';';
                }
                tok.nextToken();
            }
            assert tok.ttype == StreamTokenizer.TT_WORD;
            String memberName = tok.sval;
            assertChar( tok, '(' );
            assertChar( tok, ')' );

            Object defaultVal = null;

            if ( tok.nextToken() == StreamTokenizer.TT_WORD )
            {
                assert tok.sval.equals( "default" );

                tok.nextToken();
                if ( tok.ttype == '{' )
                {
                    assertChar( tok, '}' );
                    defaultVal = new ArrayList();
                }
                else
                {
                    assert tok.ttype == StreamTokenizer.TT_WORD || tok.ttype == StreamTokenizer.TT_NUMBER : tok.ttype;

                    if ( tok.ttype == StreamTokenizer.TT_NUMBER )
                    {
                        defaultVal = getNumericDefaultVal( memberType, tok.nval );
                    }
                    else
                    {
                        String defaultString = tok.sval;

                        if ( defaultString.charAt( 0 ) == '@' )
                        {
                            // It's a default value that is an annotation.  We ignore these for now.
                            ignoreAnnotation( tok );
                        }
                        else
                        {
                            if ( memberType.equals( "String" ) )
                            {
                                assert defaultString.charAt( 0 ) == '"' : defaultString;
                                int len = defaultString.length();
                                assert len > 1 && defaultString.charAt( len - 1 ) == '"' : defaultString;
                                defaultVal = defaultString.substring( 0, len - 1 );
                            }
                            else if ( memberType.equals( "boolean" ) )
                            {
                                defaultVal = Boolean.valueOf( defaultString );
                            }
                            else if ( memberType.equals( "Class") )
                            {
                                assert defaultString.endsWith( ".class" );
                                defaultVal = defaultString.substring( 0, defaultString.indexOf( ".class" ) );
                            }
                            else
                            {
                                defaultVal = readDefaultEnumVal( defaultString, memberType, enumVals );
                            }
                        }
                    }
                }

                tok.nextToken();
            }

            assert tok.ttype == ';';

            if ( enumVals != null ) memberType = "String";
            memberDecls.add( new AnnotationTypeElementDeclarationImpl( memberName, memberType, defaultVal, enumVals ) );
        }

        assert tok.ttype == '}';

        AnnotationTypeElementDeclaration[] memberArray = ( AnnotationTypeElementDeclaration[] )
                memberDecls.toArray( new AnnotationTypeElementDeclaration[ memberDecls.size() ] );
        return new AnnotationTypeDeclarationImpl( annotationName, interfaceQualifier, packageName, memberArray );
    }

    private static String readDefaultEnumVal( String defaultString, String memberType, HashSet enumVals )
    {
        int dot = defaultString.indexOf( '.' );
        assert dot != -1 : "expected an enum value: " + defaultString;
        String type = defaultString.substring( 0, dot );
        assert type.equals( memberType ) : "expected enum " + memberType + ", got " + type;
        assert enumVals != null : "no enum " + memberType
                                  + " defined; currently, enum must be defined before its use";
        String defaultVal = defaultString.substring( dot + 1 );
        assert enumVals.contains( defaultVal ) :
                "invalid enum field " + defaultVal + " on enum " + type;
        return defaultVal;
    }

    private static Object getNumericDefaultVal( String expectedType, double defaultNumber )
    {
        if ( expectedType.equals( "int" ) )
        {
            return new Integer( ( int ) defaultNumber );
        }
        else if ( expectedType.equals( "long" ) )
        {
            return new Long( ( long ) defaultNumber );
        }
        else if ( expectedType.equals( "float" ) )
        {
            return new Float( ( float ) defaultNumber );
        }
        else if ( expectedType.equals( "double" ) )
        {
            return new Double( defaultNumber );
        }

        assert false : "type " + expectedType + " cannot accept value " + defaultNumber;
        return null;
    }

    private static void ignoreAnnotation( StreamTokenizer tok )
        throws IOException
    {
        while ( tok.nextToken() != ')' )
        {
            assert tok.ttype != StreamTokenizer.TT_EOF;
            assert tok.ttype != ';';
        }
    }

    private static void readEnum( StreamTokenizer tok, HashMap enums )
            throws IOException
    {
        String enumName = assertWord( tok );

        assertChar( tok, '{' );
        HashSet fieldNames = new HashSet();

        while ( true )
        {
            fieldNames.add( assertWord( tok ) );
            tok.nextToken();
            if ( tok.ttype == '}' ) break;
            assert tok.ttype == ',' : tok.ttype;    // for now, we only do very simple enums.
        }

        enums.put( enumName, fieldNames );
    }
}
TOP

Related Classes of org.apache.beehive.netui.compiler.xdoclet.typesystem.impl.declaration.AnnotationInterfaceParser

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.