KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > beehive > controls > runtime > generator > AptControlImplementation


1 package org.apache.beehive.controls.runtime.generator;
2 /*
3  * Copyright 2004 The Apache Software Foundation.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  * $Header:$
18  */

19
20 import java.io.IOException JavaDoc;
21 import java.io.Writer JavaDoc;
22 import java.util.ArrayList JavaDoc;
23 import java.util.Collection JavaDoc;
24 import java.util.HashMap JavaDoc;
25 import java.util.List JavaDoc;
26
27
28 import com.sun.mirror.apt.Filer;
29 import com.sun.mirror.declaration.AnnotationMirror;
30 import com.sun.mirror.declaration.ClassDeclaration;
31 import com.sun.mirror.declaration.Declaration;
32 import com.sun.mirror.declaration.FieldDeclaration;
33 import com.sun.mirror.declaration.InterfaceDeclaration;
34 import com.sun.mirror.declaration.MethodDeclaration;
35 import com.sun.mirror.type.InterfaceType;
36 import com.sun.mirror.type.TypeMirror;
37
38 import org.apache.beehive.controls.api.bean.ControlImplementation;
39 import org.apache.beehive.controls.api.events.Client;
40 import org.apache.beehive.controls.api.events.EventHandler;
41 import org.apache.beehive.controls.api.versioning.VersionSupported;
42 import org.apache.beehive.controls.api.versioning.Version;
43 import org.apache.beehive.controls.runtime.generator.apt.TwoPhaseAnnotationProcessor;
44
45 /**
46  * The AptControlImplementation class provides validation and metadata management when
47  * processing a ControlImplementation class.
48  */

49 public class AptControlImplementation extends AptType implements Generator
50 {
51     /**
52      * Constructs a new AptControlImplementation instance where information is derived
53      * from APT metadata
54      * @param decl the annotated declaration
55      */

56     public AptControlImplementation(Declaration decl, TwoPhaseAnnotationProcessor ap)
57     {
58         _ap = ap;
59         if (! (decl instanceof ClassDeclaration))
60         {
61             _ap.printError( decl, "control.implementation.badclass" );
62             return;
63         }
64         _implDecl = (ClassDeclaration)decl;
65         setDeclaration(_implDecl);
66
67         _superClass = initSuperClass();
68
69         _contexts = initContexts();
70
71         _controls = initControls();
72
73         _clients = initClients();
74
75         initEventAdaptors();
76
77         //
78
// Check serializability of the implementation class. Any non-transient implementation
79
// must implement the java.io.Serializable marker interface to indicate that the author
80
// has considered serializability.
81
//
82
ControlImplementation implAnnot = _implDecl.getAnnotation(ControlImplementation.class);
83         if (!implAnnot.isTransient())
84         {
85             boolean isSerializable = false;
86             for (InterfaceType superIntf: _implDecl.getSuperinterfaces())
87             {
88                 if (superIntf.toString().equals("java.io.Serializable"))
89                 {
90                     isSerializable = true;
91                     break;
92                 }
93             }
94
95             if (!isSerializable)
96             {
97                 _ap.printError( decl, "control.implementation.unserializable" );
98             }
99         }
100
101         //
102
// Construct a new initializer class from this implementation class
103
//
104
_init = new ImplInitializer(this);
105
106         if ( getControlInterface() == null )
107         {
108             _ap.printError( decl, "control.implementation.missing.interface" );
109             return;
110         }
111
112         _versionSupported = initVersionSupported();
113
114         enforceVersionSupported();
115     }
116
117     /**
118      * Initializes the super interface that this ControlImpl extends (or null if a
119      * base class)
120      */

121     private AptControlImplementation initSuperClass()
122     {
123         if ( _implDecl == null || _implDecl.getSuperclass() == null )
124             return null;
125         
126         ClassDeclaration superDecl = _implDecl.getSuperclass().getDeclaration();
127         if (superDecl != null &&
128             superDecl.getAnnotation(org.apache.beehive.controls.api.bean.ControlImplementation.class) != null)
129         {
130             return new AptControlImplementation(superDecl, _ap);
131         }
132         
133         return null;
134     }
135
136     /**
137      * Returns the super interface for this interface
138      */

139     public AptControlImplementation getSuperClass() { return _superClass; }
140
141     /**
142      * Initializes the list of ContextField declared directly by this ControlImpl
143      */

144     private ArrayList JavaDoc<AptContextField> initContexts()
145     {
146         ArrayList JavaDoc<AptContextField> contexts = new ArrayList JavaDoc<AptContextField>();
147         
148         if ( _implDecl == null || _implDecl.getFields() == null )
149             return contexts;
150
151         Collection JavaDoc<FieldDeclaration> declaredFields = _implDecl.getFields();
152         for (FieldDeclaration fieldDecl : declaredFields)
153         {
154             if (fieldDecl.getAnnotation(org.apache.beehive.controls.api.context.Context.class) != null)
155                 contexts.add(new AptContextField(this, fieldDecl, _ap));
156         }
157         return contexts;
158     }
159
160     /**
161      * Returns the list of ContextFields declared directly by this ControlImplementation
162      */

163     public ArrayList JavaDoc<AptContextField> getContexts() { return _contexts; }
164
165     /**
166      * Returns true if the implemenation class contains any nested services
167      */

168     public boolean hasContexts() { return _contexts.size() != 0; }
169
170     /**
171      * Initializes the list of ControlFields for this ControlImpl
172      */

173     private ArrayList JavaDoc<AptControlField> initControls()
174     {
175         ArrayList JavaDoc<AptControlField> fields = new ArrayList JavaDoc<AptControlField>();
176
177         if ( _implDecl == null || _implDecl.getFields() == null )
178             return fields;
179
180         Collection JavaDoc<FieldDeclaration> declaredFields = _implDecl.getFields();
181         for (FieldDeclaration fieldDecl : declaredFields)
182         {
183             if (fieldDecl.getAnnotation(org.apache.beehive.controls.api.bean.Control.class) != null)
184                 fields.add(new AptControlField(this, fieldDecl, _ap));
185         }
186         return fields;
187     }
188
189     /**
190      * Returns true if the implemenation class contains any nested controls
191      */

192     public boolean hasControls() { return _controls.size() != 0; }
193
194     /**
195      * Initializes the list of ClientFields declared directly by this ControlImpl
196      */

197     protected ArrayList JavaDoc<AptClientField> initClients()
198     {
199         ArrayList JavaDoc<AptClientField> clients = new ArrayList JavaDoc<AptClientField>();
200         
201         if ( _implDecl == null || _implDecl.getFields() == null )
202             return clients;
203
204         Collection JavaDoc<FieldDeclaration> declaredFields = _implDecl.getFields();
205         for (FieldDeclaration fieldDecl : declaredFields)
206         {
207             if (fieldDecl.getAnnotation(Client.class) != null)
208                 clients.add(new AptClientField(this, fieldDecl));
209         }
210         return clients;
211     }
212
213     /**
214      * Returns the list of ClientFields declared directly by this ControlImplementation
215      */

216     public ArrayList JavaDoc<AptClientField> getClients() { return _clients; }
217
218     /**
219      * Returns the VersionSupported annotation, if any.
220      */

221     public VersionSupported getVersionSupported() { return _versionSupported; }
222
223     /**
224      * Returns true if the implemenation class contains any nested event proxies
225      */

226     public boolean hasClients() { return _clients.size() != 0; }
227
228     /**
229      * Returns the field with the specified name
230      */

231     public AptField getField(String JavaDoc name)
232     {
233         for (AptField genField : _contexts)
234             if (genField.getName().equals(name))
235                 return genField;
236         for (AptField genField : _clients)
237             if (genField.getName().equals(name))
238                 return genField;
239
240         return null;
241     }
242
243     public AptEventField getControlField(String JavaDoc name)
244     {
245         for (AptControlField controlField : _controls)
246             if (controlField.getName().equals(name))
247                 return controlField;
248         
249         return null;
250     }
251
252     /**
253      * Returns the list of fully qualified class names for types that are derived
254      * from this Generator
255      */

256     public String JavaDoc [] getGeneratedTypes()
257     {
258         return new String JavaDoc [] { _init.getClassName() };
259     }
260
261     /**
262      * Returns the information necessary to generate a ImplInitializer from this
263      * ControlImplementation.
264      */

265     public List JavaDoc<GeneratorOutput> getCheckOutput(Filer filer) throws IOException JavaDoc
266     {
267         HashMap JavaDoc<String JavaDoc,Object JavaDoc> map = new HashMap JavaDoc<String JavaDoc,Object JavaDoc>();
268         map.put("impl", this); // control implementation
269
map.put("init", _init); // control impl initializer
270

271         Writer JavaDoc writer = new IndentingWriter(filer.createSourceFile(_init.getClassName()));
272         GeneratorOutput genOut =
273             new GeneratorOutput(writer,"org/apache/beehive/controls/runtime/generator/ImplInitializer.vm",
274                                 map);
275         ArrayList JavaDoc<GeneratorOutput> genList = new ArrayList JavaDoc<GeneratorOutput>(1);
276         genList.add(genOut);
277         return genList;
278     }
279
280     /**
281      * Returns the list of generated files derived from this Generator during the
282      * generate phase of annotation processing.
283      */

284     public List JavaDoc<GeneratorOutput> getGenerateOutput(Filer filer) throws IOException JavaDoc
285     {
286         return null;
287     }
288
289     /**
290      * Returns the ControlInterface implemented by this ControlImpl.
291      */

292     public AptControlInterface getControlInterface()
293     {
294         if ( _implDecl == null || _implDecl.getSuperinterfaces() == null )
295             return null;
296         
297         Collection JavaDoc<InterfaceType> superInterfaces = _implDecl.getSuperinterfaces();
298         for (InterfaceType intfType : superInterfaces)
299         {
300             InterfaceDeclaration intfDecl = intfType.getDeclaration();
301             if (intfDecl != null &&
302                 intfDecl.getAnnotation(org.apache.beehive.controls.api.bean.ControlInterface.class) != null)
303                 return new AptControlInterface(intfDecl, _ap);
304         }
305
306         return null;
307     }
308
309     /**
310      * Initializes the list of EventAdaptors for this ControlImpl
311      */

312     protected void initEventAdaptors()
313     {
314         if ( _implDecl == null || _implDecl.getMethods() == null )
315             return;
316         
317         for (MethodDeclaration implMethod : _implDecl.getMethods())
318         {
319             //
320
// Do a quick check for the presence of the EventHandler annotation on methods
321
//
322
if (implMethod.getAnnotation(EventHandler.class) == null ||
323                 implMethod.toString().equals("<clinit>()"))
324                 continue;
325
326             //
327
// If found, we must actually read the value using an AnnotationMirror, since it
328
// contains a Class element (eventSet) that cannot be loaded
329
//
330
AnnotationMirror handlerMirror = null;
331             for (AnnotationMirror annot : implMethod.getAnnotationMirrors())
332             {
333                 if ( annot == null ||
334                     annot.getAnnotationType() == null ||
335                     annot.getAnnotationType().getDeclaration() == null ||
336                     annot.getAnnotationType().getDeclaration().getQualifiedName() == null )
337                     return;
338
339                 if ( annot.getAnnotationType().getDeclaration().getQualifiedName().equals(
340                         "org.apache.beehive.controls.api.events.EventHandler"))
341                 {
342                     handlerMirror = annot;
343                     break;
344                 }
345             }
346             if (handlerMirror == null)
347             {
348                 throw new CodeGenerationException("Unable to find EventHandler annotation on " +
349                                                   implMethod);
350             }
351
352             AptAnnotationHelper handlerAnnot = new AptAnnotationHelper(handlerMirror);
353
354             //
355
// Locate the EventField based upon the field element value
356
//
357
String JavaDoc fieldName = (String JavaDoc)handlerAnnot.getObjectValue("field");
358             AptEventField eventField = (AptEventField)getField(fieldName);
359             if (eventField == null)
360             {
361                 // eventField == null means this field isn't interesting for the purposes
362
// of this processor (control impls). However, only emit an error message
363
// if the field isn't on a nested control
364
if ( getControlField(fieldName) == null )
365                     _ap.printError( implMethod, "eventhandler.field.not.found", fieldName );
366
367                 continue;
368             }
369
370             //
371
// Locate the EventSet based upon the eventSet element value
372
//
373
TypeMirror tm = (TypeMirror)( handlerAnnot.getObjectValue("eventSet") );
374             if ( tm == null )
375                 continue;
376             String JavaDoc setName = tm.toString();
377
378             AptControlInterface controlIntf = eventField.getControlInterface();
379             AptEventSet eventSet = controlIntf.getEventSet(setName);
380             if (eventSet == null)
381             {
382                 _ap.printError( implMethod, "eventhandler.eventset.not.found", setName );
383                 continue;
384             }
385
386             //
387
// Register a new EventAdaptor for the EventSet, if none exists already
388
//
389
EventAdaptor adaptor = eventField.getEventAdaptor(eventSet);
390             if (adaptor == null)
391             {
392                 adaptor = new EventAdaptor(eventField, eventSet);
393                 eventField.addEventAdaptor(eventSet, adaptor);
394             }
395
396             //
397
// Locate the EventSet method based upon the eventName element value. Once
398
// found, add a new AptEventHandler to the adaptor for this event.
399
//
400
boolean found = false;
401             String JavaDoc eventName = (String JavaDoc)handlerAnnot.getObjectValue("eventName");
402             AptMethod handlerMethod = new AptMethod(implMethod, _ap);
403             for (AptEvent controlEvent : eventSet.getEvents())
404             {
405                 if (controlEvent == null || controlEvent.getName() == null ||
406                     !controlEvent.getName().equals(eventName))
407                     continue;
408                 if ( controlEvent.getArgTypes() == null )
409                     continue;
410
411                 //
412
// BUGBUG: If the arguments are parameterized, then the event handler
413
// might declare a specific bound version of the type, so a direct
414
// comparison will fail. If parameterized, we don't validate.
415
//
416
if (controlEvent.hasParameterizedArguments() ||
417                     controlEvent.getArgTypes().equals(handlerMethod.getArgTypes()))
418                 {
419                     adaptor.addHandler(controlEvent,
420                                        new AptEventHandler(controlEvent, implMethod, _ap));
421                     found = true;
422                     break;
423                 }
424             }
425             if (!found)
426             {
427                 _ap.printError( implMethod, "eventhandler.method.not.found", setName );
428             }
429         }
430     }
431
432     private VersionSupported initVersionSupported()
433     {
434         if ( _implDecl == null )
435             return null;
436         return _implDecl.getAnnotation(VersionSupported.class);
437     }
438
439     /**
440      * Enforces the VersionRequired annotation for control extensions.
441      */

442     private void enforceVersionSupported()
443     {
444         if ( _versionSupported != null )
445         {
446             int majorSupported = _versionSupported.major();
447             int minorSupported = _versionSupported.minor();
448
449             if ( majorSupported < 0 ) // no real version support requirement
450
return;
451
452             AptControlInterface ci = getControlInterface();
453             if ( ci == null )
454                 return;
455
456             int majorPresent = -1;
457             int minorPresent = -1;
458             Version ciVersion = ci.getVersion();
459             if ( ciVersion != null )
460             {
461                 majorPresent = ciVersion.major();
462                 minorPresent = ciVersion.minor();
463
464                 if ( majorSupported >= majorPresent &&
465                      (minorSupported < 0 || minorSupported >= minorPresent) )
466                 {
467                     // Version requirement is satisfied
468
return;
469                 }
470             }
471
472             //
473
// Version requirement failed
474
//
475

476             _ap.printError( _implDecl, "versionsupported.failed", _implDecl.getSimpleName(), majorSupported, minorSupported,
477                             majorPresent, minorPresent );
478         }
479     }
480
481     private ClassDeclaration _implDecl;
482     private TwoPhaseAnnotationProcessor _ap;
483     private AptControlImplementation _superClass;
484     private ArrayList JavaDoc<AptContextField> _contexts;
485     private ArrayList JavaDoc<AptClientField> _clients;
486     private ArrayList JavaDoc<AptControlField> _controls;
487     private ImplInitializer _init;
488     private VersionSupported _versionSupported;
489 }
490
Popular Tags