495 lines
18 KiB
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;
|
|
}
|
|
}
|