KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > beehive > controls > system > jdbc > JdbcControlChecker


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

18
19 package org.apache.beehive.controls.system.jdbc;
20
21 import com.sun.mirror.apt.AnnotationProcessorEnvironment;
22 import com.sun.mirror.declaration.Declaration;
23 import com.sun.mirror.declaration.FieldDeclaration;
24 import com.sun.mirror.declaration.MethodDeclaration;
25 import com.sun.mirror.declaration.TypeDeclaration;
26 import com.sun.mirror.type.ArrayType;
27 import com.sun.mirror.type.DeclaredType;
28 import com.sun.mirror.type.InterfaceType;
29 import com.sun.mirror.type.MirroredTypeException;
30 import com.sun.mirror.type.PrimitiveType;
31 import com.sun.mirror.type.TypeMirror;
32 import com.sun.mirror.type.VoidType;
33 import org.apache.beehive.controls.api.ControlException;
34 import org.apache.beehive.controls.api.bean.ControlChecker;
35 import org.apache.beehive.controls.system.jdbc.parser.ParameterChecker;
36 import org.apache.beehive.controls.system.jdbc.parser.SqlParser;
37 import org.apache.beehive.controls.system.jdbc.parser.SqlStatement;
38
39 import java.util.Collection JavaDoc;
40 import java.sql.SQLException JavaDoc;
41
42 /**
43  * Annotation checker for the JdbcControl. Invoked at compile time by the controls framework.
44  */

45 public class JdbcControlChecker implements ControlChecker {
46
47     /**
48      * Invoked by the control build-time infrastructure to process a declaration of
49      * a control extension (ie, an interface annotated with @ControlExtension), or
50      * a field instance of a control type.
51      */

52     public void check(Declaration decl, AnnotationProcessorEnvironment env) {
53
54         if (decl instanceof TypeDeclaration) {
55
56             //
57
// Check class annotations
58
//
59
checkConnectionDataSource((TypeDeclaration) decl, env);
60             checkConnectionDriver((TypeDeclaration) decl, env);
61             checkConnectionOptions((TypeDeclaration) decl, env);
62
63             //
64
// Check method annotations
65
//
66
Collection JavaDoc<? extends MethodDeclaration> methods = ((TypeDeclaration) decl).getMethods();
67             for (MethodDeclaration method : methods) {
68                 checkSQL(method, env);
69
70             }
71         } else if (decl instanceof FieldDeclaration) {
72
73             //
74
// NOOP
75
//
76
} else {
77
78             //
79
// NOOP
80
//
81
}
82     }
83
84     /**
85      * Check the ConnectionDataSource annotation.
86      *
87      * @param decl
88      * @param env
89      */

90     private void checkConnectionDataSource(TypeDeclaration decl, AnnotationProcessorEnvironment env) {
91         final JdbcControl.ConnectionDataSource cds =
92                 decl.getAnnotation(JdbcControl.ConnectionDataSource.class);
93         if (cds == null) {
94             return;
95         }
96
97         //
98
// NOOP
99
//
100
}
101
102     /**
103      * Check the ConnectionDriver annotation.
104      *
105      * @param decl
106      * @param env
107      */

108     private void checkConnectionDriver(TypeDeclaration decl, AnnotationProcessorEnvironment env) {
109         final JdbcControl.ConnectionDriver cd = decl.getAnnotation(JdbcControl.ConnectionDriver.class);
110         if (cd == null) {
111             return;
112         }
113
114         //
115
// NOOP
116
//
117
}
118
119     /**
120      * Check the ConnectionOptions annotation.
121      *
122      * @param decl
123      * @param env
124      */

125     private void checkConnectionOptions(TypeDeclaration decl, AnnotationProcessorEnvironment env) {
126         final JdbcControl.ConnectionOptions co = decl.getAnnotation(JdbcControl.ConnectionOptions.class);
127         if (co == null) {
128             return;
129         }
130
131         //
132
// NOOP
133
//
134
}
135
136     /**
137      * Check the SQL method annotation. Lots to check here, stop checking as soon as an error is found.
138      *
139      * @param method
140      * @param env
141      */

142     private void checkSQL(MethodDeclaration method, AnnotationProcessorEnvironment env) {
143
144         final JdbcControl.SQL methodSQL = method.getAnnotation(JdbcControl.SQL.class);
145         if (methodSQL == null) {
146             return;
147         }
148
149         //
150
// check for empty SQL statement member
151
//
152
if (methodSQL.statement() == null || methodSQL.statement().length() == 0) {
153             env.getMessager().printError(method.getPosition(), "@SQL annotation on method: " + method.getSimpleName()
154                                                                + " contains an empty statement member.");
155             return;
156         }
157
158         //
159
// Make sure maxrows is not set to some negative number other than -1
160
//
161
int maxRows = methodSQL.maxRows();
162         if (maxRows < JdbcControl.MAXROWS_ALL) {
163             env.getMessager().printError(method.getPosition(), "@SQL annotation on method: " + method.getSimpleName()
164                                                                + " maxRows set to invalid value: " + maxRows);
165             return;
166         }
167
168         //
169
// Make sure maxArrayLength is not set to some negative number
170
//
171
int arrayMax = methodSQL.arrayMaxLength();
172         if (arrayMax < 1) {
173             env.getMessager().printError(method.getPosition(), "@SQL annotation on method: " + method.getSimpleName()
174                                                                + " arrayMaxLength set to invalid value (must be greater than 0): "
175                                                                + arrayMax);
176             return;
177         }
178
179
180         //
181
//
182
// parse the SQL
183
//
184
//
185
SqlParser _p = new SqlParser();
186         SqlStatement _statement = null;
187         try {
188             _statement = _p.parse(methodSQL.statement());
189         } catch (ControlException ce) {
190             env.getMessager().printError(method.getPosition(), "Error parsing SQL statment on method: " + method.getSimpleName() + ": " + ce.toString());
191             return;
192         }
193
194         //
195
// Check that the any statement element params (delimited by '{' and '}' can be
196
// matched to method parameter names. NOTE: This check is only valid on non-compiled files,
197
// once compiled to a class file method parameter names are replaced with 'arg0', 'arg1', etc.
198
// and cannot be used for this check.
199
//
200
try {
201             ParameterChecker.checkReflectionParameters(_statement, method);
202         } catch (ControlException e) {
203             env.getMessager().printError(method.getPosition(), e.getMessage());
204             return;
205         }
206
207         //
208
// check for case of generatedKeyColumns being set, when getGeneratedKeys is not set to true
209
//
210
final boolean getGeneratedKeys = methodSQL.getGeneratedKeys();
211         final String JavaDoc[] generatedKeyColumnNames = methodSQL.generatedKeyColumnNames();
212         final int[] generatedKeyIndexes = methodSQL.generatedKeyColumnIndexes();
213         if (getGeneratedKeys == false && (generatedKeyColumnNames.length != 0 || generatedKeyIndexes.length != 0)) {
214             env.getMessager().printError(method.getPosition(), "@SQL annotation on method: " + method.getSimpleName()
215                                                                + " getGeneratedKeys must be set to true in order to specify generatedKeyColumnNames or generatedKeyColumnIndexes.");
216             return;
217         }
218
219         //
220
// check that both generatedKeyColumnNames and generatedKeyColumnIndexes are not set
221
if (generatedKeyColumnNames.length > 0 && generatedKeyIndexes.length > 0) {
222             env.getMessager().printError(method.getPosition(), "@SQL annotation on method: " + method.getSimpleName()
223                                                                + " only one of generatedKeyColumnNames or generatedKeyColumnIndexes may be set in the method annotation.");
224
225             return;
226         }
227
228         //
229
// batch update methods must return int[]
230
//
231
final boolean batchUpdate = methodSQL.batchUpdate();
232         final TypeMirror returnType = method.getReturnType();
233         if (batchUpdate) {
234             if (returnType instanceof ArrayType == true) {
235                 final TypeMirror aType = ((ArrayType) returnType).getComponentType();
236                 if (aType instanceof PrimitiveType == false || ((PrimitiveType) aType).getKind() != PrimitiveType.Kind.INT) {
237                     env.getMessager().printError(method.getPosition(), "@SQL annotation on method: " + method.getSimpleName()
238                                                                        + " if batchUpdate is set to true, method must return void or an array of integers.");
239                     return;
240                 }
241             } else if (returnType instanceof VoidType == false) {
242                 env.getMessager().printError(method.getPosition(), "@SQL annotation on method: " + method.getSimpleName()
243                                                                    + " if batchUpdate is set to true, method must return void or an array of integers.");
244
245                 return;
246             }
247
248         }
249
250         //
251
// iterator type check match
252
//
253
if (returnType instanceof InterfaceType) {
254             String JavaDoc iName = ((InterfaceType) returnType).getDeclaration().getQualifiedName();
255             if ("java.util.Iterator".equals(iName)) {
256                 String JavaDoc iteratorClassName = null;
257                 try {
258                     // this should always except
259
methodSQL.iteratorElementType();
260                 } catch (MirroredTypeException mte) {
261                     iteratorClassName = mte.getQualifiedName();
262                 }
263
264                 if ("org.apache.beehive.controls.system.jdbc.JdbcControl.UndefinedIteratorType".equals(iteratorClassName)) {
265                     env.getMessager().printError(method.getPosition(), "@SQL annotation on method: " + method.getSimpleName()
266                                                                        + " iteratorElementType must be specified if method returns an Iterator.");
267                     return;
268
269                 }
270             }
271         }
272
273         //
274
// scrollable result set check
275
//
276
final JdbcControl.ScrollType scrollable = methodSQL.scrollableResultSet();
277         switch (scrollable) {
278             case SCROLL_INSENSITIVE:
279             case SCROLL_SENSITIVE:
280             case SCROLL_INSENSITIVE_UPDATABLE:
281             case SCROLL_SENSITIVE_UPDATABLE:
282             case FORWARD_ONLY_UPDATABLE:
283                 String JavaDoc typeName = null;
284                 if (returnType instanceof DeclaredType) {
285                     typeName = ((DeclaredType) returnType).getDeclaration().getQualifiedName();
286                 }
287
288                 if (typeName == null || "java.sql.ResultSet".equals(typeName) == false) {
289                     env.getMessager().printError(method.getPosition(), "@SQL annotation on method: " + method.getSimpleName()
290                                                                        + " element scrollableResultSet specified but method does not return a ResultSet.");
291                     break;
292                 }
293             case FORWARD_ONLY:
294             default:
295                 break;
296         }
297     } // checkSQL
298
}
299
Popular Tags