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: import java.util.Map;
023:
024: import com.sun.mirror.declaration.AnnotationTypeElementDeclaration;
025: import com.sun.mirror.declaration.AnnotationMirror;
026: import com.sun.mirror.declaration.AnnotationValue;
027: import com.sun.mirror.type.AnnotationType;
028: import com.sun.mirror.type.PrimitiveType;
029:
030: import org.apache.beehive.controls.api.packaging.FeatureInfo;
031: import org.apache.beehive.controls.api.packaging.PropertyInfo;
032: import org.apache.beehive.controls.runtime.generator.apt.TwoPhaseAnnotationProcessor;
033:
034: /**
035: * The AptProperty class represents a control Property where the property attributes
036: * are derived using APT metadata
037: */
038: public class AptProperty {
039: /**
040: * Constructs a new AptProperty instance
041: * from APT metadata
042: * @param propertySet the declaring PropertySet
043: * @param propDecl the declration of the property annotation type element
044: */
045: public AptProperty(AptPropertySet propertySet,
046: AnnotationTypeElementDeclaration propDecl,
047: TwoPhaseAnnotationProcessor ap) {
048: _propertySet = propertySet;
049: _propDecl = propDecl;
050: _ap = ap;
051:
052: //
053: // Primitive properties must specify a default value, to provide consistent semantics
054: // in cases where no value has been set by annotation, client, or configuration. Object
055: // typed properties have an optional default, and 'null' in this context means that the
056: // property value has not been set.
057: //
058: if (propDecl.getReturnType() instanceof PrimitiveType
059: && propDecl.getDefaultValue() == null) {
060: _ap.printError(propDecl,
061: "property.primitive.without.default", propDecl
062: .getSimpleName());
063: }
064: }
065:
066: /**
067: * Returns the PropertySet associated with the Property
068: */
069: public AptPropertySet getPropertySet() {
070: return _propertySet;
071: }
072:
073: /**
074: * Returns the base property name. The associated accessor methods will have the
075: * form set{name} and get{name}
076: */
077: public String getAccessorName() {
078: StringBuffer sb = new StringBuffer();
079: sb.append(_propertySet.getPrefix());
080:
081: String name = getName();
082: sb.append(Character.toUpperCase(name.charAt(0)));
083: if (name.length() > 0)
084: sb.append(name.substring(1));
085: return sb.toString();
086: }
087:
088: /**
089: * Returns the name of the property reading accessor method
090: */
091: public String getReadMethod() {
092: StringBuffer sb = new StringBuffer();
093: if (getType().equals("boolean"))
094: sb.append("is");
095: else
096: sb.append("get");
097: sb.append(getAccessorName());
098: return sb.toString();
099: }
100:
101: /**
102: * Returns the name of the property writing accessor method
103: */
104: public String getWriteMethod() {
105: return "set" + getAccessorName();
106: }
107:
108: /**
109: * Returns the name associated with this Property in the PropertySet
110: */
111: public String getName() {
112: if (_propDecl == null)
113: return "";
114:
115: //
116: // Use the member name of the property method in the property set
117: //
118: return _propDecl.getSimpleName();
119: }
120:
121: /**
122: * Returns the static final field name containing the key for this Property
123: */
124: public String getKeyName() {
125: return getAccessorName() + "Key";
126: }
127:
128: /**
129: * Returns the type of the Property
130: */
131: public String getType() {
132: if (_propDecl == null || _propDecl.getReturnType() == null)
133: return "";
134:
135: return _propDecl.getReturnType().toString();
136: }
137:
138: /**
139: * Returns true if the property is an annotation type, false otherwise
140: */
141: public boolean isAnnotation() {
142: if (_propDecl == null)
143: return false;
144:
145: return _propDecl.getReturnType() instanceof AnnotationType;
146: }
147:
148: /**
149: * Returns any PropertyInfo associated with the property (or null if none)
150: */
151: public PropertyInfo getPropertyInfo() {
152: if (_propDecl == null)
153: return null;
154:
155: return _propDecl.getAnnotation(PropertyInfo.class);
156: }
157:
158: /**
159: * Returns any FeatureInfo associated with the property (or null if none)
160: */
161: public FeatureInfo getFeatureInfo() {
162: if (_propDecl == null)
163: return null;
164:
165: return _propDecl.getAnnotation(FeatureInfo.class);
166: }
167:
168: /**
169: * Returns 'true' is the property is a bound property that will support registration of
170: * a PropertyChangeListener for change notifications.
171: */
172: public boolean isBound() {
173: //
174: // Constrained properties are implicitly bound. Refer to section 7.4.3 of the JavaBeans
175: // spec for the rationale.
176: //
177: PropertyInfo propInfo = getPropertyInfo();
178: return propInfo != null
179: && (propInfo.bound() || propInfo.constrained());
180: }
181:
182: /**
183: * Returns 'true' is the property is a constrained property that will support registration of
184: * a VetoableChangeListener for vetoable change notifications.
185: */
186: public boolean isConstrained() {
187: PropertyInfo propInfo = getPropertyInfo();
188: return propInfo != null && propInfo.constrained();
189: }
190:
191: /**
192: * Returns the class name of the property editor class, or null
193: */
194: public String getEditorClass() {
195: PropertyInfo pi = getPropertyInfo();
196: if (pi == null)
197: return null;
198:
199: //
200: // This is trickier, because APT doesn't allow access to Class-valued annotations,
201: // because the type may not yet have been compiled.
202: //
203: Collection<AnnotationMirror> annotMirrors = _propDecl
204: .getAnnotationMirrors();
205: for (AnnotationMirror am : annotMirrors) {
206: if (am
207: .getAnnotationType()
208: .toString()
209: .equals(
210: "org.apache.beehive.controls.api.packaging.PropertyInfo")) {
211: Map<AnnotationTypeElementDeclaration, AnnotationValue> avs = am
212: .getElementValues();
213: for (AnnotationTypeElementDeclaration ated : avs
214: .keySet()) {
215: if (ated.toString().equals("editorClass()")) {
216: //
217: // Get the annotation value, and ignore the default value which implies
218: // no editor class (because 'null' cannot be a default value)
219: //
220: String editorClass = avs.get(ated).getValue()
221: .toString();
222: if (editorClass
223: .equals("org.apache.beehive.controls.api.packaging.PropertyInfo.NoEditor.class"))
224: return null;
225:
226: return editorClass;
227: }
228: }
229: break;
230: }
231: }
232: return null;
233: }
234:
235: AnnotationTypeElementDeclaration _propDecl;
236: private AptPropertySet _propertySet;
237: TwoPhaseAnnotationProcessor _ap;
238: }
|