KickJava   Java API By Example, From Geeks To Geeks.

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


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.util.ArrayList JavaDoc;
21 import java.util.HashSet JavaDoc;
22 import java.util.Collection JavaDoc;
23 import java.util.HashMap JavaDoc;
24 import java.util.List JavaDoc;
25 import java.io.IOException JavaDoc;
26 import java.io.Writer JavaDoc;
27
28 import com.sun.mirror.apt.Filer;
29 import com.sun.mirror.declaration.*;
30 import com.sun.mirror.type.TypeMirror;
31 import com.sun.mirror.type.ClassType;
32
33 import org.apache.beehive.controls.api.events.EventHandler;
34 import org.apache.beehive.controls.runtime.generator.apt.TwoPhaseAnnotationProcessor;
35
36 /**
37  * The AptControlClient class contains metadata about a class that contains nested control
38  * references (AptControlField).
39  */

40 public class AptControlClient extends AptType implements Generator
41 {
42     /**
43      * Constructs a new ControlClient instance where information is derived
44      * from APT metadata
45      * @param decl the annotated declaration
46      */

47     public AptControlClient(Declaration decl, TwoPhaseAnnotationProcessor ap)
48     {
49         _ap = ap;
50         if (! (decl instanceof ClassDeclaration))
51         {
52             _ap.printError( decl, "control.illegal.usage" );
53             return;
54         }
55         _clientDecl = (ClassDeclaration)decl;
56         setDeclaration(_clientDecl);
57
58         _controls = initControls();
59         initEventAdaptors();
60
61         //
62
// Construct a new initializer class from this implementation class
63
//
64
_init = new ClientInitializer(this);
65     }
66
67     /**
68      * Returns true if this type of client requires that nested controls have unique identifiers
69      */

70     protected boolean needsUniqueID()
71     {
72         //
73
// BUGBUG:
74
// Pageflows need to have a more unique ID generated for fields, because multiple pageflows
75
// may be shared within a single ControlContainerContext, and just using the field name could
76
// result in collisions. A better (and less hard-wired) approach is needed than searching for
77
// specific annotations. Perhaps a model that enables particular client types to subclass
78
// AptControlClient and override getID() would be much better.
79
//
80
for (AnnotationMirror annotMirror : _clientDecl.getAnnotationMirrors())
81         {
82             String JavaDoc annotType = annotMirror.getAnnotationType().toString();
83             if (annotType.equals("org.apache.beehive.netui.pageflow.annotations.Jpf.Controller") ||
84                 annotType.equals("org.apache.beehive.netui.pageflow.annotations.Jpf.Backing"))
85                 return true;
86         }
87         return false;
88     }
89
90     /**
91      * Returns a unique ID for a control field
92      */

93     public String JavaDoc getID(AptControlField control)
94     {
95         if (!needsUniqueID())
96             return "\"" + control.getName() + "\"";
97
98         return "client.getClass() + \"@\" + client.hashCode() + \"." + control.getName() + "\"";
99     }
100
101     /**
102      * Returns the list of ControlFields declared directly by this ControlImpl
103      */

104     public ArrayList JavaDoc<AptControlField> getControls() { return _controls; }
105
106     /**
107      * Returns true if the implemenation class contains any nested controls
108      */

109     public boolean hasControls() { return _controls.size() != 0; }
110
111     /**
112      * Returns true if the control client needs field initialization support
113      */

114     public boolean needsFieldInit()
115     {
116         return hasControls();
117     }
118
119     /**
120      * Returns the field with the specified name
121      */

122     public AptField getField(String JavaDoc name)
123     {
124         for (AptField field : _controls)
125             if (field.getName().equals(name))
126                 return field;
127
128         return null;
129     }
130
131     /**
132      * Returns the list of fully qualified class names for types that are derived
133      * from this Generator
134      */

135     public String JavaDoc [] getGeneratedTypes()
136     {
137         return new String JavaDoc [] { _init.getClassName() };
138     }
139
140     /**
141      * Returns the information necessary to generate a ImplInitializer from this
142      * ControlImplementation.
143      */

144     public List JavaDoc<GeneratorOutput> getCheckOutput(Filer filer) throws IOException JavaDoc
145     {
146         return null;
147     }
148
149     /**
150      * Returns the information necessary to generate a ClientInitializer from this control
151      */

152     public List JavaDoc<GeneratorOutput> getGenerateOutput(Filer filer) throws IOException JavaDoc
153     {
154         HashMap JavaDoc<String JavaDoc,Object JavaDoc> map = new HashMap JavaDoc<String JavaDoc,Object JavaDoc>();
155         map.put("client", this); // control client
156
map.put("init", _init); // control client initializer
157

158         Writer JavaDoc writer = new IndentingWriter(filer.createSourceFile(_init.getClassName()));
159         GeneratorOutput genOut =
160             new GeneratorOutput(writer,"org/apache/beehive/controls/runtime/generator/ClientInitializer.vm",
161                                 map);
162         ArrayList JavaDoc<GeneratorOutput> genList = new ArrayList JavaDoc<GeneratorOutput>(1);
163         genList.add(genOut);
164         return genList;
165     }
166
167     /**
168      * Initializes the list of ControlFields declared directly by this ControlClient
169      */

170     protected ArrayList JavaDoc<AptControlField> initControls()
171     {
172         ArrayList JavaDoc<AptControlField> controls = new ArrayList JavaDoc<AptControlField>();
173
174         if ( _clientDecl == null || _clientDecl.getFields() == null )
175             return controls;
176
177         Collection JavaDoc<FieldDeclaration> declaredFields = _clientDecl.getFields();
178         for (FieldDeclaration fieldDecl : declaredFields)
179         {
180             if (fieldDecl.getAnnotation(org.apache.beehive.controls.api.bean.Control.class) != null)
181                 controls.add(new AptControlField(this, fieldDecl, _ap));
182         }
183         return controls;
184     }
185
186     public boolean hasSuperClient()
187     {
188         return ( getSuperClientName() != null );
189     }
190
191     /**
192      * Returns the fully qualified classname of the closest control client in the inheritance chain.
193      * @return class name of the closest control client
194      */

195     public String JavaDoc getSuperClientName()
196     {
197         ClassType superType = _clientDecl.getSuperclass();
198
199         while ( superType != null )
200         {
201             ClassDeclaration superDecl = superType.getDeclaration();
202
203             Collection JavaDoc<FieldDeclaration> declaredFields = superDecl.getFields();
204             for (FieldDeclaration fieldDecl : declaredFields)
205             {
206                 if (fieldDecl.getAnnotation(org.apache.beehive.controls.api.bean.Control.class) != null)
207                 {
208                     // Found an @control annotated field, so return this class name
209
return superDecl.getQualifiedName();
210                 }
211             }
212
213             superType = superType.getSuperclass();
214         }
215
216         return null;
217     }
218
219     /**
220      * Returns the super class for this class
221      */

222     public AptControlClient getSuperClass() { return null; }
223
224     /**
225      * Initializes the list of EventAdaptors for this ControlImpl
226      */

227     protected void initEventAdaptors()
228     {
229         if ( _clientDecl == null || _clientDecl.getMethods() == null )
230             return;
231         
232         for (MethodDeclaration clientMethod : _clientDecl.getMethods())
233         {
234             //
235
// Do a quick check for the presence of the EventHandler annotation on methods
236
//
237
if (clientMethod.getAnnotation(EventHandler.class) == null ||
238                 clientMethod.toString().equals("<clinit>()"))
239                 continue;
240
241             //
242
// If found, we must actually read the value using an AnnotationMirror, since it
243
// contains a Class element (eventSet) that cannot be loaded
244
//
245
AnnotationMirror handlerMirror = null;
246             for (AnnotationMirror annot : clientMethod.getAnnotationMirrors())
247             {
248                 if ( annot == null ||
249                     annot.getAnnotationType() == null ||
250                     annot.getAnnotationType().getDeclaration() == null ||
251                     annot.getAnnotationType().getDeclaration().getQualifiedName() == null )
252                     return;
253
254                 if ( annot.getAnnotationType().getDeclaration().getQualifiedName().equals(
255                         "org.apache.beehive.controls.api.events.EventHandler"))
256                 {
257                     handlerMirror = annot;
258                     break;
259                 }
260             }
261             if (handlerMirror == null)
262             {
263                 throw new CodeGenerationException("Unable to find EventHandler annotation on " +
264                                                   clientMethod);
265             }
266
267             AptAnnotationHelper handlerAnnot = new AptAnnotationHelper(handlerMirror);
268
269             //
270
// Locate the EventField based upon the field element value
271
//
272
String JavaDoc fieldName = (String JavaDoc)handlerAnnot.getObjectValue("field");
273             AptEventField eventField = (AptEventField)getField(fieldName);
274             if (eventField == null)
275             {
276                 // Deliberately not issuing a diagnostic if an event handler specifies
277
// a field that isn't a control. Other annotation processors also
278
// handle event handlers, so delegate diagnostic responsibility to them.
279
continue;
280             }
281
282             //
283
// Locate the EventSet based upon the eventSet element value
284
//
285
TypeMirror tm = (TypeMirror)( handlerAnnot.getObjectValue("eventSet") );
286             if ( tm == null )
287                 continue;
288             String JavaDoc setName = tm.toString();
289
290             AptControlInterface controlIntf = eventField.getControlInterface();
291             AptEventSet eventSet = controlIntf.getEventSet(setName);
292             if (eventSet == null)
293             {
294                 _ap.printError( clientMethod, "eventhandler.eventset.not.found", setName );
295                 continue;
296             }
297
298             //
299
// Register a new EventAdaptor for the EventSet, if none exists already
300
//
301
EventAdaptor adaptor = eventField.getEventAdaptor(eventSet);
302             if (adaptor == null)
303             {
304                 adaptor = new EventAdaptor(eventField, eventSet);
305                 eventField.addEventAdaptor(eventSet, adaptor);
306             }
307
308             //
309
// Locate the EventSet method based upon the eventName element value. Once
310
// found, add a new AptEventHandler to the adaptor for this event.
311
//
312
boolean found = false;
313             String JavaDoc eventName = (String JavaDoc)handlerAnnot.getObjectValue("eventName");
314             AptMethod handlerMethod = new AptMethod(clientMethod, _ap);
315
316             //
317
// Will start at the currrent event set and look up through any ones it
318
// extends to try and find a matching event
319
//
320
while (eventSet != null)
321             {
322                 for (AptEvent controlEvent : eventSet.getEvents())
323                 {
324                     if (controlEvent == null ||
325                         controlEvent.getName() == null ||
326                         !controlEvent.getName().equals(eventName))
327                         continue;
328
329                     if ( controlEvent.getArgTypes() == null )
330                         continue;
331
332                     //
333
// BUGBUG: If the arguments are parameterized, then the event handler
334
// might declare a specific bound version of the type, so a direct
335
// comparison will fail. If parameterized, we don't validate.
336
//
337
if (controlEvent.hasParameterizedArguments() ||
338                         (controlEvent.getArgTypes().equals(handlerMethod.getArgTypes()) &&
339                          controlEvent.getReturnType().equals(handlerMethod.getReturnType())
340                         )
341                        )
342                     {
343                         HashSet JavaDoc<String JavaDoc> throwSet = new HashSet JavaDoc<String JavaDoc>(controlEvent.getThrowsList());
344                         ArrayList JavaDoc<String JavaDoc> handlerThrows = handlerMethod.getThrowsList();
345                         boolean throwsMatches = true;
346                         for ( String JavaDoc t : handlerThrows )
347                         {
348                             if ( !throwSet.contains(t) )
349                                 throwsMatches = false;
350                         }
351                     
352                         if ( !throwsMatches )
353                         {
354                             _ap.printError( clientMethod, "eventhandler.throws.mismatch", handlerMethod.getName() );
355                         }
356
357                         adaptor.addHandler(controlEvent,
358                                        new AptEventHandler(controlEvent, clientMethod, _ap ));
359                         found = true;
360                         break;
361                     }
362                 }
363                 if (found) // outer loop too
364
break;
365
366                 //
367
// Look up on the super event set if not found at the current level
368
//
369
eventSet = eventSet.getSuperEventSet();
370             }
371             if (!found)
372             {
373                 _ap.printError( clientMethod, "eventhandler.method.not.found", setName );
374             }
375         }
376     }
377
378     ClassDeclaration _clientDecl;
379     TwoPhaseAnnotationProcessor _ap;
380     ArrayList JavaDoc<AptControlField> _controls;
381     ClientInitializer _init;
382 }
383
Popular Tags