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.ArrayList;
022: import java.util.Collection;
023: import java.util.HashSet;
024:
025: import com.sun.mirror.declaration.InterfaceDeclaration;
026: import com.sun.mirror.declaration.MethodDeclaration;
027: import com.sun.mirror.declaration.TypeDeclaration;
028: import com.sun.mirror.declaration.TypeParameterDeclaration;
029: import com.sun.mirror.type.InterfaceType;
030:
031: import org.apache.beehive.controls.api.events.EventSet;
032: import org.apache.beehive.controls.api.packaging.EventSetInfo;
033: import org.apache.beehive.controls.runtime.generator.apt.TwoPhaseAnnotationProcessor;
034:
035: /**
036: * The AptEventSet class represents a control EventSet where the events
037: * are derived using APT metadata.
038: */
039: public class AptEventSet extends AptType {
040: /**
041: * Constructs a new AptEventSet instance from APT metadata
042: * @param controlIntf the declaring control interface
043: * @param eventSet the EventSet class
044: * @param ap the associated AnnotationProcessor
045: */
046: public AptEventSet(AptControlInterface controlIntf,
047: InterfaceDeclaration eventSet,
048: TwoPhaseAnnotationProcessor ap) {
049: _controlIntf = controlIntf;
050: _eventSet = eventSet;
051: _ap = ap;
052: setDeclaration(eventSet);
053:
054: EventSet eventSetAnnot = eventSet.getAnnotation(EventSet.class);
055: if (eventSetAnnot != null)
056: _unicast = eventSetAnnot.unicast();
057:
058: //
059: // If an EventSet interface has formal type parameters, they must be a subset of
060: // the original formal type parameters declared on the original control interface.
061: // This is required because it must be possible to bind the types of events immediately
062: // upon construction of the bean... there is no opportunity to separately specify
063: // parameterization for the event set for the purpose of creating listeners, client
064: // notifiers, etc.
065: //
066: TypeDeclaration intfDecl = controlIntf.getTypeDeclaration();
067: for (TypeParameterDeclaration estpd : _eventSet
068: .getFormalTypeParameters()) {
069: boolean found = false;
070: for (TypeParameterDeclaration citpd : intfDecl
071: .getFormalTypeParameters()) {
072: if (estpd.getSimpleName().equals(citpd.getSimpleName())) {
073: found = true;
074: break;
075: }
076: }
077: if (!found) {
078: //
079: // BUGBUG: Ideally, this would be estpd.getPosition, but this seems to return
080: // 0,0 for the current APT implementation, so we use the event set position
081: // instead.
082: // Once this works, the 'break' below can also be removed to present errors
083: // for multiple invalid parameters
084: //
085: _ap.printError(eventSet,
086: "eventset.formal.parameter.mismatch");
087: break;
088: }
089: }
090:
091: _super EventSet = initSuperEventSet();
092:
093: _events = initEvents();
094: }
095:
096: /**
097: * Checks to see if this EventSet extends an EventSet declared on a parent control interface. If
098: * found it will return the parent EventSet, or return null if not found.
099: */
100: public AptEventSet initSuperEventSet() {
101: // This will be common, so short circuit quickly
102: AptControlInterface super Control = _controlIntf.getSuperClass();
103: if (super Control == null)
104: return null;
105:
106: // Compute a hash set containing the qualified names of all super interfaces
107: // for this EventSet
108: HashSet<String> extendNames = new HashSet<String>();
109: for (InterfaceType super Type : _eventSet.getSuperinterfaces()) {
110: InterfaceDeclaration super Decl = super Type.getDeclaration();
111: if (super Decl != null)
112: extendNames.add(super Decl.getQualifiedName());
113: }
114:
115: // Starting with the parent of the ControlInterface declaring this EventSet, look
116: // for a parent interface that declares ones of these super interfaces as an event
117: // set
118: while (super Control != null) {
119: Collection<AptEventSet> super EventSets = super Control
120: .getEventSets();
121: for (AptEventSet super EventSet : super EventSets) {
122: if (extendNames.contains(super EventSet.getClassName()))
123: return super EventSet;
124: }
125:
126: super Control = super Control.getSuperClass();
127: }
128:
129: // Nothing found, so no super event set
130: return null;
131: }
132:
133: /**
134: * Returns any EventSet from which this event set derives (or null if none)
135: */
136: public AptEventSet getSuperEventSet() {
137: return _super EventSet;
138: }
139:
140: /**
141: * Initializes the list of Events associated with this EventSet
142: */
143: protected AptMethodSet<AptEvent> initEvents() {
144: AptMethodSet<AptEvent> events = new AptMethodSet<AptEvent>();
145: if (_eventSet == null || _eventSet.getMethods() == null)
146: return events;
147:
148: //
149: // Add all of the public methods directly declared and inherited from extended
150: // interfaces, except for the EventSet super interface (if any)
151: //
152: ArrayList<InterfaceDeclaration> intfList = new ArrayList<InterfaceDeclaration>();
153: intfList.add(_eventSet);
154: for (int i = 0; i < intfList.size(); i++) {
155: InterfaceDeclaration intfDecl = intfList.get(i);
156:
157: //
158: // Don't add events that are derived from a super event set. These are not added because
159: // this class picks a single super interface to extend from when building a hierarchy
160: // of callback notifiers (etc). So, the super event set that was chosen first is left out
161: // of the list of event methods since they're captured in superclasses in the Control's implementation
162: //
163: if (_super EventSet != null
164: && _super EventSet.getClassName().equals(
165: intfDecl.getQualifiedName()))
166: continue;
167:
168: // Add all declared methods, but ignore the mystery <clinit> methods
169: for (MethodDeclaration methodDecl : intfDecl.getMethods())
170: if (!methodDecl.toString().equals("<clinit>()"))
171: events.add(new AptEvent(this , methodDecl, _ap));
172:
173: //
174: // Add all superinterfaces of the target interface to the list
175: //
176: for (InterfaceType super Type : intfDecl
177: .getSuperinterfaces()) {
178: InterfaceDeclaration super Decl = super Type
179: .getDeclaration();
180: if (super Decl != null && !intfList.contains(super Decl))
181: intfList.add(super Decl);
182: }
183: }
184:
185: return events;
186: }
187:
188: /**
189: * Returns the list of Events associated with this EventSet
190: */
191: public Collection<AptEvent> getEvents() {
192: return _events.getMethods();
193: }
194:
195: /**
196: * Returns 'true' if the event set support only unicast (single listener) events,
197: * false otherwise.
198: */
199: public boolean isUnicast() {
200: return _unicast;
201: }
202:
203: /**
204: * Returns the number of Events for this EventSet and any super event set
205: */
206: public int getEventCount() {
207: int count = _events.size();
208: if (_super EventSet != null)
209: count += _super EventSet.getEventCount();
210: return count;
211: }
212:
213: /**
214: * Returns the programmatic descriptor name to be returned by the EventDescriptor
215: * for the event set.
216: */
217: public String getDescriptorName() {
218: //
219: // The javadocs for java.beans.EventSetDescriptor suggest that the programmatic name
220: // should start w/ a lowercase letter. So we use the unqualified event set interface
221: // name w/ the first character lowercased.
222: //
223: String name = getShortName();
224: return Character.toLowerCase(name.charAt(0))
225: + name.substring(1);
226: }
227:
228: /**
229: * Returns the name of the generated notifier class for this ControlEventSet
230: */
231: public String getNotifierClass() {
232: StringBuffer sb = new StringBuffer(getShortName());
233: sb.append("Notifier");
234:
235: //
236: // If the event set declaration has any parameterized types, then include them on
237: // the notifier class as well. Currently, these can only be parameterized types
238: // from the outer (control interface), since there is no other mechanism for specifying
239: // type values at notifier construction (other than propagation from the outer type).
240: //
241: sb.append(getFormalTypeParameterNames());
242: return sb.toString();
243: }
244:
245: /**
246: * Returns any 'extends' clause that should be placed on the generated notifier class
247: */
248: public String getNotifierExtends() {
249: //
250: // All EventNotifiers are rooted from a common utility class, so if there is no
251: // super event set, then extend the utility notifier class.
252: //
253: if (_super EventSet == null) {
254: if (_unicast)
255: return "org.apache.beehive.controls.runtime.bean.UnicastEventNotifier";
256: else
257: return "org.apache.beehive.controls.runtime.bean.EventNotifier";
258: }
259:
260: //
261: // Otherwise, a generated notifier will extend the notifier of any parent event set
262: //
263: return _super EventSet.getNotifierClass();
264: }
265:
266: /**
267: * Returns the short name for this notifier's base class.
268: */
269: public String getNotifierExtendsShortName() {
270:
271: if (_super EventSet == null) {
272: if (_unicast)
273: return "UnicastEventNotifier";
274: else
275: return "EventNotifier";
276: }
277:
278: return _super EventSet.getNotifierClass();
279: }
280:
281: /**
282: * Return true if this notifier extends the UnicastEventNotifier or EventNotifier base class.
283: */
284: public boolean isExtendsNotifierBase() {
285: return _super EventSet == null;
286: }
287:
288: /**
289: * Returns the name of the method used to register a new EventSet listener
290: */
291: public String getAddListenerMethod() {
292: return "add" + getShortName() + "Listener";
293: }
294:
295: /**
296: * Returns the name of the method used to register a new EventSet listener
297: */
298: public String getRemoveListenerMethod() {
299: return "remove" + getShortName() + "Listener";
300: }
301:
302: /**
303: * Returns the name of the method used to retrieve the (unicast) EventSet listener
304: */
305: public String getGetListenersMethod() {
306: return "get" + getShortName() + "Listeners";
307: }
308:
309: /**
310: * Returns the name of a custom-generated method to initialize MethodDescriptor bean
311: * info for the events in this EventSet
312: */
313: public String getInfoInitializer() {
314: return "init" + getShortName() + "Events";
315: }
316:
317: /**
318: * Returns any EventSetInfo associated with the event set (or null if none)
319: */
320: public EventSetInfo getEventSetInfo() {
321: if (_eventSet == null)
322: return null;
323:
324: return _eventSet.getAnnotation(EventSetInfo.class);
325: }
326:
327: /**
328: * Returns the underlying APT InterfaceDeclaration associated with this event set
329: */
330: public InterfaceDeclaration getDeclaration() {
331: return _eventSet;
332: }
333:
334: private TwoPhaseAnnotationProcessor _ap;
335: private InterfaceDeclaration _eventSet;
336: private AptEventSet _super EventSet;
337: private AptControlInterface _controlIntf;
338: private AptMethodSet<AptEvent> _events;
339: private boolean _unicast;
340: }
|