001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: *
017: * $Header:$
018: */
019: package org.apache.beehive.controls.runtime.generator;
020:
021: import java.util.Collection;
022:
023: import com.sun.mirror.declaration.ClassDeclaration;
024: import com.sun.mirror.declaration.FieldDeclaration;
025: import com.sun.mirror.declaration.InterfaceDeclaration;
026: import com.sun.mirror.declaration.TypeDeclaration;
027: import com.sun.mirror.type.DeclaredType;
028: import com.sun.mirror.type.InterfaceType;
029: import com.sun.mirror.type.TypeMirror;
030: import com.sun.mirror.type.MirroredTypeException;
031:
032: import org.apache.beehive.controls.api.bean.ControlExtension;
033: import org.apache.beehive.controls.api.bean.ControlInterface;
034: import org.apache.beehive.controls.api.bean.Control;
035: import org.apache.beehive.controls.api.versioning.VersionRequired;
036: import org.apache.beehive.controls.runtime.generator.apt.TwoPhaseAnnotationProcessor;
037:
038: /**
039: * The AptControlField class contains information about a field that refers to a nested control.
040: */
041: public class AptControlField extends AptEventField {
042: /**
043: * Base constructor, protected so only a custom subclass can invoke
044: * @param controlClient the declaring AptType
045: */
046: public AptControlField(AptType controlClient,
047: FieldDeclaration controlDecl, TwoPhaseAnnotationProcessor ap) {
048: super (controlDecl);
049: _controlClient = controlClient;
050: _ap = ap;
051: _controlBean = new ControlBean(getControlInterface());
052: }
053:
054: /**
055: * Does this control field have a VersionRequired annotation?
056: * @return <code>true</code> if there is a version required annotation; <code>false</code> otherwise
057: */
058: public boolean hasVersionRequired() {
059: return (_fieldDecl.getAnnotation(VersionRequired.class) != null);
060: }
061:
062: /**
063: * Initializes the ControlInterface associated with this ControlField
064: */
065: protected AptControlInterface initControlInterface() {
066: TypeMirror controlType = _fieldDecl.getType();
067: if (!(controlType instanceof DeclaredType)) {
068: _ap.printError(_fieldDecl, "control.field.bad.type");
069: return null;
070: }
071:
072: //
073: // The field can either be declared as the bean type or the public interface type.
074: // If it is the bean type, then we need to reflect to find the public interface
075: // type it implements.
076: //
077: TypeDeclaration typeDecl = ((DeclaredType) controlType)
078: .getDeclaration();
079: InterfaceDeclaration controlIntf = null;
080:
081: //
082: // It is possible that the declared type is associated with a to-be-generated
083: // bean type. In this case, look for the associated control interface on the
084: // processor input list.
085: //
086: if (typeDecl == null) {
087: String className = controlType.toString();
088: String intfName = className.substring(0,
089: className.length() - 4);
090: String interfaceHint = getControlInterfaceHint();
091: controlIntf = (InterfaceDeclaration) _ap
092: .getAnnotationProcessorEnvironment()
093: .getTypeDeclaration(intfName);
094:
095: if (controlIntf == null) {
096: // The specified class name may not be fully qualified. In this case, the
097: // best we can do is look for a best fit match against the input types
098: for (TypeDeclaration td : _ap
099: .getAnnotationProcessorEnvironment()
100: .getSpecifiedTypeDeclarations()) {
101: // if an interface hint was provided, use it to find the control interface,
102: // if not provided try to find the control interface by matching simple names.
103: if (interfaceHint != null) {
104: if (td instanceof InterfaceDeclaration
105: && td.getQualifiedName().equals(
106: interfaceHint)) {
107: controlIntf = (InterfaceDeclaration) td;
108: break;
109: }
110: } else {
111: if (td instanceof InterfaceDeclaration
112: && td.getSimpleName().equals(intfName)) {
113: controlIntf = (InterfaceDeclaration) td;
114: break;
115: }
116: }
117: }
118: }
119: } else if (typeDecl instanceof ClassDeclaration) {
120: Collection<InterfaceType> implIntfs = ((ClassDeclaration) typeDecl)
121: .getSuperinterfaces();
122: for (InterfaceType intfType : implIntfs) {
123: InterfaceDeclaration intfDecl = intfType
124: .getDeclaration();
125:
126: if (intfDecl == null)
127: return null;
128:
129: if (intfDecl.getAnnotation(ControlInterface.class) != null
130: || intfDecl
131: .getAnnotation(ControlExtension.class) != null) {
132: controlIntf = intfDecl;
133: break;
134: }
135: }
136: } else if (typeDecl instanceof InterfaceDeclaration) {
137: controlIntf = (InterfaceDeclaration) typeDecl;
138: }
139:
140: if (controlIntf == null) {
141: _ap.printError(_fieldDecl, "control.field.bad.type.2");
142: return null;
143: }
144:
145: return new AptControlInterface(controlIntf, _ap);
146: }
147:
148: /**
149: * Get the interface hint attribute value (as a string) from the Control annotation,
150: * if it wasn't specified return null.
151: */
152: private String getControlInterfaceHint() {
153:
154: Control controlAnnotation = _fieldDecl
155: .getAnnotation(Control.class);
156: String interfaceHint = null;
157: try {
158: // always excepts
159: controlAnnotation.interfaceHint();
160: } catch (MirroredTypeException mte) {
161: interfaceHint = ("java.lang.Object".equals(mte
162: .getQualifiedName())) ? null : mte
163: .getQualifiedName();
164: }
165: return interfaceHint;
166: }
167:
168: /**
169: * Returns the ControlBean associated with this ControlField
170: */
171: public ControlBean getControlBean() {
172: return _controlBean;
173: }
174:
175: private TwoPhaseAnnotationProcessor _ap;
176: private AptType _controlClient;
177: private ControlBean _controlBean;
178: }
|