/* * 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.controls.runtime.generator; import java.util.Collection; import com.sun.mirror.declaration.ClassDeclaration; import com.sun.mirror.declaration.FieldDeclaration; import com.sun.mirror.declaration.InterfaceDeclaration; import com.sun.mirror.declaration.TypeDeclaration; import com.sun.mirror.type.DeclaredType; import com.sun.mirror.type.InterfaceType; import com.sun.mirror.type.TypeMirror; import com.sun.mirror.type.MirroredTypeException; import org.apache.beehive.controls.api.bean.ControlExtension; import org.apache.beehive.controls.api.bean.ControlInterface; import org.apache.beehive.controls.api.bean.Control; import org.apache.beehive.controls.api.versioning.VersionRequired; import org.apache.beehive.controls.runtime.generator.apt.TwoPhaseAnnotationProcessor; /** * The AptControlField class contains information about a field that refers to a nested control. */ public class AptControlField extends AptEventField { /** * Base constructor, protected so only a custom subclass can invoke * @param controlClient the declaring AptType */ public AptControlField(AptType controlClient, FieldDeclaration controlDecl, TwoPhaseAnnotationProcessor ap) { super( controlDecl ); _controlClient = controlClient; _ap = ap; _controlBean = new ControlBean(getControlInterface()); } /** * Does this control field have a VersionRequired annotation? * @return true if there is a version required annotation; false otherwise */ public boolean hasVersionRequired() { return ( _fieldDecl.getAnnotation( VersionRequired.class ) != null ); } /** * Initializes the ControlInterface associated with this ControlField */ protected AptControlInterface initControlInterface() { TypeMirror controlType = _fieldDecl.getType(); if (! (controlType instanceof DeclaredType)) { _ap.printError( _fieldDecl, "control.field.bad.type" ); return null; } // // The field can either be declared as the bean type or the public interface type. // If it is the bean type, then we need to reflect to find the public interface // type it implements. // TypeDeclaration typeDecl = ((DeclaredType)controlType).getDeclaration(); InterfaceDeclaration controlIntf = null; // // It is possible that the declared type is associated with a to-be-generated // bean type. In this case, look for the associated control interface on the // processor input list. // if ( typeDecl == null ) { String className = controlType.toString(); String intfName = className.substring(0, className.length() - 4); String interfaceHint = getControlInterfaceHint(); controlIntf = (InterfaceDeclaration)_ap.getAnnotationProcessorEnvironment().getTypeDeclaration(intfName); if (controlIntf == null) { // The specified class name may not be fully qualified. In this case, the // best we can do is look for a best fit match against the input types for (TypeDeclaration td :_ap.getAnnotationProcessorEnvironment().getSpecifiedTypeDeclarations()) { // if an interface hint was provided, use it to find the control interface, // if not provided try to find the control interface by matching simple names. if (interfaceHint != null) { if (td instanceof InterfaceDeclaration && td.getQualifiedName().equals(interfaceHint)) { controlIntf = (InterfaceDeclaration)td; break; } } else { if (td instanceof InterfaceDeclaration && td.getSimpleName().equals(intfName)) { controlIntf = (InterfaceDeclaration)td; break; } } } } } else if (typeDecl instanceof ClassDeclaration) { Collection implIntfs = ((ClassDeclaration)typeDecl).getSuperinterfaces(); for (InterfaceType intfType : implIntfs) { InterfaceDeclaration intfDecl = intfType.getDeclaration(); if ( intfDecl == null ) return null; if (intfDecl.getAnnotation(ControlInterface.class) != null|| intfDecl.getAnnotation(ControlExtension.class) != null) { controlIntf = intfDecl; break; } } } else if (typeDecl instanceof InterfaceDeclaration) { controlIntf = (InterfaceDeclaration)typeDecl; } if (controlIntf == null) { _ap.printError( _fieldDecl, "control.field.bad.type.2" ); return null; } return new AptControlInterface(controlIntf, _ap); } /** * Get the interface hint attribute value (as a string) from the Control annotation, * if it wasn't specified return null. */ private String getControlInterfaceHint() { Control controlAnnotation = _fieldDecl.getAnnotation(Control.class); String interfaceHint = null; try { // always excepts controlAnnotation.interfaceHint(); } catch (MirroredTypeException mte) { interfaceHint = ("java.lang.Object".equals(mte.getQualifiedName())) ? null : mte.getQualifiedName(); } return interfaceHint; } /** * Returns the ControlBean associated with this ControlField */ public ControlBean getControlBean() { return _controlBean; } private TwoPhaseAnnotationProcessor _ap; private AptType _controlClient; private ControlBean _controlBean; }