JdbcMapper/beehive-netui-compiler/src/main/java/org/apache/beehive/netui/compiler/AnnotationGrammar.java

495 lines
18 KiB
Java

/*
* 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.
*
* $Header:$
*/
package org.apache.beehive.netui.compiler;
import org.apache.beehive.netui.compiler.typesystem.declaration.AnnotationInstance;
import org.apache.beehive.netui.compiler.typesystem.declaration.AnnotationTypeElementDeclaration;
import org.apache.beehive.netui.compiler.typesystem.declaration.AnnotationValue;
import org.apache.beehive.netui.compiler.typesystem.declaration.Declaration;
import org.apache.beehive.netui.compiler.typesystem.declaration.MemberDeclaration;
import org.apache.beehive.netui.compiler.typesystem.env.CoreAnnotationProcessorEnv;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Our base class for customizable annotation tag grammars. It has stock behavior for basic
* things like making sure required attributes exist, and provides plugin points for more
* complex checks.
*/
public abstract class AnnotationGrammar
implements JpfLanguageConstants
{
/**
* If this tag requires a particular runtime version...
*/
private String _requiredRuntimeVersion = null;
private RuntimeVersionChecker _runtimeVersionChecker;
private CoreAnnotationProcessorEnv _env;
private Diagnostics _diagnostics;
private Map _memberGrammars = new HashMap();
private Map _memberArrayGrammars = new HashMap();
private Map _memberTypes = new HashMap();
/**
* @param requiredRuntimeVersion causes an error to be produced if the version in the manifest of beehive-netui-pageflow.jar
* is not high enough.
*/
protected AnnotationGrammar( CoreAnnotationProcessorEnv env, Diagnostics diags, String requiredRuntimeVersion,
RuntimeVersionChecker runtimeVersionChecker )
{
_env = env;
_diagnostics = diags;
_runtimeVersionChecker = runtimeVersionChecker;
_requiredRuntimeVersion = requiredRuntimeVersion;
}
public final CoreAnnotationProcessorEnv getEnv()
{
return _env;
}
public Diagnostics getDiagnostics()
{
return _diagnostics;
}
public final Object check( AnnotationInstance annotation, AnnotationInstance[] parentAnnotations,
MemberDeclaration classMember )
throws FatalCompileTimeException
{
return check( annotation, parentAnnotations, classMember, -1 );
}
public final Object check( AnnotationInstance annotation, AnnotationInstance[] parentAnnotations,
MemberDeclaration classMember, int annotationArrayIndex )
throws FatalCompileTimeException
{
if ( ! beginCheck( annotation, parentAnnotations, classMember ) ) return null;
Map valuesPresent = annotation.getElementValues();
HashSet wasPresent = new HashSet();
HashMap checkResults = new HashMap();
if ( parentAnnotations == null ) parentAnnotations = new AnnotationInstance[0];
int oldLen = parentAnnotations.length;
AnnotationInstance[] parentsIncludingMe = new AnnotationInstance[oldLen + 1];
System.arraycopy( parentAnnotations, 0, parentsIncludingMe, 0, oldLen );
parentsIncludingMe[oldLen] = annotation;
for ( Iterator ii = valuesPresent.entrySet().iterator(); ii.hasNext(); )
{
Map.Entry i = ( Map.Entry ) ii.next();
AnnotationTypeElementDeclaration decl = ( AnnotationTypeElementDeclaration ) i.getKey();
AnnotationValue value = ( AnnotationValue ) i.getValue();
String memberName = decl.getSimpleName();
wasPresent.add( memberName );
onCheckMember( decl, value, annotation, parentAnnotations, classMember );
Object grammarOrType = null;
if ( ( grammarOrType = _memberGrammars.get( memberName ) ) != null )
{
AnnotationGrammar childGrammar = ( AnnotationGrammar ) grammarOrType;
if ( childGrammar != null ) // it will be non-null unless there are other, more basic, errors
{
Object result =
childGrammar.check( ( AnnotationInstance ) value.getValue(), parentsIncludingMe, classMember );
if ( result != null )
{
checkResults.put( memberName, result );
}
}
}
else if ( ( grammarOrType = _memberArrayGrammars.get( memberName ) ) != null )
{
AnnotationGrammar arrayGrammar = ( AnnotationGrammar ) grammarOrType;
if ( arrayGrammar != null )
{
List annotations = CompilerUtils.getAnnotationArray( value );
for ( int j = 0; j < annotations.size(); ++j )
{
Object annotationInstance = annotations.get(j);
// The user may have included something other than an annotation in the array. The compiler
// will print an error; this is to prevent a ClassCastException here.
if (annotationInstance instanceof AnnotationInstance) {
AnnotationInstance ann = ( AnnotationInstance ) annotationInstance;
arrayGrammar.check( ann, parentsIncludingMe, classMember, j );
}
}
}
}
else
{
AnnotationMemberType memberType = ( AnnotationMemberType ) _memberTypes.get( memberName );
if ( memberType != null ) // it will be non-null unless there are other, more basic, errors
{
Object result =
memberType.check( decl, value, parentsIncludingMe, classMember, annotationArrayIndex );
if ( result != null ) checkResults.put( memberName, result );
}
}
}
return endCheck( annotation, parentAnnotations, classMember, wasPresent, checkResults );
}
public final boolean beginCheck( AnnotationInstance annotation, AnnotationInstance[] parentAnnotations,
MemberDeclaration classMember )
throws FatalCompileTimeException
{
//
// First check to see if there's a required runtime version.
//
if ( ! _runtimeVersionChecker.checkRuntimeVersion( _requiredRuntimeVersion, annotation, _diagnostics,
"error.required-runtime-version-annotation",
new Object[]{ PAGEFLOW_RUNTIME_JAR } ) )
{
return false;
}
return onBeginCheck( annotation, parentAnnotations, classMember ); // for derived classes
}
protected void addError( Declaration element, String key )
{
getDiagnostics().addError( element, key, null );
}
protected void addError( Declaration element, String key, Object[] args )
{
getDiagnostics().addErrorArrayArgs( element, key, args );
}
protected void addError( Declaration element, String key, Object arg )
{
getDiagnostics().addError( element, key, arg );
}
protected void addError( Declaration element, String key, Object arg1, Object arg2 )
{
getDiagnostics().addError( element, key, arg1, arg2 );
}
protected void addError( Declaration element, String key, Object arg1, Object arg2, Object arg3 )
{
getDiagnostics().addError( element, key, arg1, arg2, arg3 );
}
protected void addError( AnnotationValue element, String key )
{
getDiagnostics().addError( element, key, null );
}
protected void addError( AnnotationValue element, String key, Object[] args )
{
getDiagnostics().addErrorArrayArgs( element, key, args );
}
protected void addError( AnnotationValue element, String key, Object arg1 )
{
getDiagnostics().addError( element, key, arg1 );
}
protected void addError( AnnotationValue element, String key, Object arg1, Object arg2 )
{
getDiagnostics().addError( element, key, arg1, arg2 );
}
protected void addError( AnnotationValue element, String key, Object arg1, Object arg2, Object arg3 )
{
getDiagnostics().addError( element, key, arg1, arg2, arg3 );
}
protected void addError( AnnotationInstance element, String key )
{
getDiagnostics().addError( element, key, null );
}
protected void addError( AnnotationInstance element, String key, Object[] args )
{
getDiagnostics().addErrorArrayArgs( element, key, args );
}
protected void addError( AnnotationInstance element, String key, Object arg1 )
{
getDiagnostics().addError( element, key, arg1 );
}
protected void addError( AnnotationInstance element, String key, Object arg1, Object arg2 )
{
getDiagnostics().addError( element, key, arg1, arg2 );
}
protected void addError( AnnotationInstance element, String key, Object arg1, Object arg2, Object arg3 )
{
getDiagnostics().addError( element, key, arg1, arg2, arg3 );
}
protected void addWarning( Declaration element, String key )
{
getDiagnostics().addWarning( element, key, null );
}
protected void addWarning( Declaration element, String key, Object[] args )
{
getDiagnostics().addWarningArrayArgs( element, key, args );
}
protected void addWarning( Declaration element, String key, Object arg )
{
getDiagnostics().addWarning( element, key, arg );
}
protected void addWarning( Declaration element, String key, Object arg1, Object arg2 )
{
getDiagnostics().addWarning( element, key, arg1, arg2 );
}
protected void addWarning( Declaration element, String key, Object arg1, Object arg2, Object arg3 )
{
getDiagnostics().addWarning( element, key, arg1, arg2, arg3 );
}
protected void addWarning( AnnotationValue element, String key )
{
getDiagnostics().addWarning( element, key, null );
}
protected void addWarning( AnnotationValue element, String key, Object[] args )
{
getDiagnostics().addWarningArrayArgs( element, key, args );
}
protected void addWarning( AnnotationValue element, String key, Object arg1 )
{
getDiagnostics().addWarning( element, key, arg1 );
}
protected void addWarning( AnnotationValue element, String key, Object arg1, Object arg2 )
{
getDiagnostics().addWarning( element, key, arg1, arg2 );
}
protected void addWarning( AnnotationValue element, String key, Object arg1, Object arg2, Object arg3 )
{
getDiagnostics().addWarning( element, key, arg1, arg2, arg3 );
}
protected void addWarning( AnnotationInstance element, String key )
{
getDiagnostics().addWarning( element, key, null );
}
protected void addWarning( AnnotationInstance element, String key, Object[] args )
{
getDiagnostics().addWarningArrayArgs( element, key, args );
}
protected void addWarning( AnnotationInstance element, String key, Object arg1 )
{
getDiagnostics().addWarning( element, key, arg1 );
}
protected void addWarning( AnnotationInstance element, String key, Object arg1, Object arg2 )
{
getDiagnostics().addWarning( element, key, arg1, arg2 );
}
protected void addWarning( AnnotationInstance element, String key, Object arg1, Object arg2, Object arg3 )
{
getDiagnostics().addWarning( element, key, arg1, arg2, arg3 );
}
/**
* @return a result (any Object) that will be passed back to the parent checker. May be null</code>.
*/
public final Object endCheck( AnnotationInstance annotation, AnnotationInstance[] parentAnnotations,
MemberDeclaration classMember, Set wasPresent, Map checkResults )
{
//
// Check mutually-exclusive attributes and child annotations.
//
String[][] mutuallyExclusiveAttrs = getMutuallyExclusiveAttrs();
for ( int i = 0; mutuallyExclusiveAttrs != null && i < mutuallyExclusiveAttrs.length; ++i )
{
String alreadyFound = null;
for ( int j = 0; j < mutuallyExclusiveAttrs[i].length; ++j )
{
String thisAttr = mutuallyExclusiveAttrs[i][j];
if ( wasPresent.contains( thisAttr ) )
{
if ( alreadyFound == null )
{
alreadyFound = thisAttr;
}
else
{
String errorKey = "error.atmost-one-may-exist-" + mutuallyExclusiveAttrs[i].length;
getDiagnostics().addErrorArrayArgs( annotation, errorKey, mutuallyExclusiveAttrs[i] );
}
}
}
}
//
// Check required attributes and child annotations.
//
String[][] requiredAttrs = getRequiredAttrs();
for ( int i = 0; requiredAttrs != null && i < requiredAttrs.length; ++i )
{
boolean foundOne = false;
for ( int j = 0; j < requiredAttrs[i].length; ++j )
{
String thisAttr = requiredAttrs[i][j];
if ( wasPresent.contains( thisAttr ) )
{
foundOne = true;
break;
}
}
if ( ! foundOne )
{
String errorKey = "error.atleast-one-must-exist-" + requiredAttrs[i].length;
getDiagnostics().addErrorArrayArgs( annotation, errorKey, requiredAttrs[i] );
}
}
//
// Check inter-dependencies for attributes and child annotations.
//
String[][] attrDependencies = getAttrDependencies();
for ( int i = 0; attrDependencies != null && i < attrDependencies.length; ++i )
{
String thisAttr = attrDependencies[i][0];
if ( wasPresent.contains( thisAttr ) )
{
boolean foundOne = false;
for ( int j = 1; j < attrDependencies[i].length; ++j )
{
if ( wasPresent.contains( attrDependencies[i][j] ) )
{
foundOne = true;
break;
}
}
if ( ! foundOne )
{
String key = "error.attr-dependency-not-found-" + ( attrDependencies[i].length - 1 );
getDiagnostics().addErrorArrayArgs( annotation, key, attrDependencies[i] );
}
}
}
return onEndCheck( annotation, parentAnnotations, classMember, checkResults ); // for derived classes
}
protected boolean onBeginCheck( AnnotationInstance annotation, AnnotationInstance[] parentAnnotations,
MemberDeclaration classMember )
throws FatalCompileTimeException
{
return true;
}
/**
* @param checkResults map of member-name (String) -> result-from-checking (Object)
* @return a result (any Object) that will be passed back to the parent checker. May be null</code>.
*/
protected Object onEndCheck( AnnotationInstance annotation, AnnotationInstance[] parentAnnotations,
MemberDeclaration classMember, Map checkResults )
{
return null;
}
protected void onCheckMember( AnnotationTypeElementDeclaration memberDecl, AnnotationValue member,
AnnotationInstance annotation, AnnotationInstance[] parentAnnotations,
MemberDeclaration classMember )
{
}
/**
* Each entry in this array (a String[]) lists mutually exclusive attributes.
*/
public String[][] getMutuallyExclusiveAttrs()
{
return null;
}
/**
* Each entry in this array (a String[]) lists attributes of which one must exist in this tag.
*/
public String[][] getRequiredAttrs()
{
return null;
}
/**
* Each entry in this array (a String[]) is an array whose first element is an attribute that
* requires at least one of the subsequent elements to exist as an attribute.
*/
public String[][] getAttrDependencies()
{
return null;
}
protected void addMemberGrammar( String memberName, AnnotationGrammar grammar )
{
_memberGrammars.put( memberName, grammar );
}
protected void addMemberArrayGrammar( String memberName, AnnotationGrammar grammar )
{
_memberArrayGrammars.put( memberName, grammar );
}
protected void addMemberType( String memberName, AnnotationMemberType type )
{
_memberTypes.put( memberName, type );
}
public String getRequiredRuntimeVersion()
{
return _requiredRuntimeVersion;
}
public RuntimeVersionChecker getRuntimeVersionChecker()
{
return _runtimeVersionChecker;
}
}