KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > beehive > controls > system > jdbc > parser > ReflectionFragment


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.parser;
20
21 import org.apache.beehive.controls.api.ControlException;
22 import org.apache.beehive.controls.api.context.ControlBeanContext;
23 import org.apache.beehive.controls.system.jdbc.TypeMappingsFactory;
24
25 import java.lang.reflect.Method JavaDoc;
26 import java.util.Map JavaDoc;
27 import java.util.regex.Pattern JavaDoc;
28
29 /**
30  * Represents a method parameter substitution into the SQL annotation's statement member. Delimited by '{' and '}'.
31  * Method parameter names must exactly match the name used in the SQL statement in order for the substitution to occur.
32  * <p/>
33  * <pre>
34  * SQL(statement="SELECT * FROM {tableName}")
35  * public void getAll(String tableName) throws SQLException;
36  * </pre>
37  */

38 public final class ReflectionFragment extends SqlFragment {
39
40     private static final String JavaDoc PREPARED_STATEMENT_SUB_MARK = "?";
41     private static final Pattern JavaDoc s_parameterNamePattern = Pattern.compile("\\.");
42
43     private final String JavaDoc _parameterName;
44     private final String JavaDoc[] _nameQualifiers;
45     private int _sqlDataType;
46
47     /**
48      * Create a new ReflectionFragment with the specifed method parameter name.
49      *
50      * @param parameterName The name of the parameter whose value should be substituted at this location.
51      */

52     ReflectionFragment(String JavaDoc parameterName) {
53         _parameterName = parameterName;
54         _sqlDataType = TypeMappingsFactory.TYPE_UNKNOWN;
55         _nameQualifiers = s_parameterNamePattern.split(_parameterName);
56     }
57
58     /**
59      * Create a new ReflectionFragment with the specified method parameter name and SQL type.
60      *
61      * @param parameterName The name of the parameter whose value should be substituted at this location.
62      * @param sqlDataType A String specifing the SQL data type for this parameter.
63      */

64     ReflectionFragment(String JavaDoc parameterName, String JavaDoc sqlDataType) {
65         this(parameterName);
66         if (sqlDataType != null) {
67             _sqlDataType = TypeMappingsFactory.getInstance().convertStringToSQLType(sqlDataType);
68         }
69     }
70
71     /**
72      * Return text generated by this fragment for a PreparedStatement
73      *
74      * @param context A ControlBeanContext instance.
75      * @param m The annotated method.
76      * @param args The method's parameters
77      * @return Always returns a PREPARED_STATEMENT_SUB_MARK
78      */

79     String JavaDoc getPreparedStatementText(ControlBeanContext context, Method JavaDoc m, Object JavaDoc[] args) {
80         return PREPARED_STATEMENT_SUB_MARK;
81     }
82
83     /**
84      * Always true for ReflectionFragment.
85      *
86      * @return true
87      */

88     boolean hasParamValue() { return true; }
89
90     /**
91      * Get the parameter name (as specified in the SQL statement).
92      *
93      * @return The parameter name.
94      */

95     String JavaDoc getParameterName() { return _parameterName; }
96
97     /**
98      * Get a copy of the array of parameter name qualifiers.
99      *
100      * @return An array of parameter name qualifiers.
101      */

102     String JavaDoc[] getParameterNameQualifiers() {
103         String JavaDoc[] nameQualifiersCopy = new String JavaDoc[_nameQualifiers.length];
104         System.arraycopy(_nameQualifiers, 0, nameQualifiersCopy, 0, _nameQualifiers.length);
105         return nameQualifiersCopy;
106     }
107
108     /**
109      * Get the SQL data type of this param.
110      *
111      * @return The SQL data type for this param.
112      */

113     int getParamSqlDataType() { return _sqlDataType; }
114
115     /**
116      * For JUnit testing.
117      *
118      * @return The String value of this fragment.
119      */

120     public String JavaDoc toString() { return PREPARED_STATEMENT_SUB_MARK; }
121
122     /**
123      * Get the value of this parameter.
124      *
125      * @param context ControlBeanContext instance to evaluate the parameter's value against.
126      * @param method Method instance to evaluate against.
127      * @param args Method argument values
128      * @return All parameter object values contained within this fragment
129      */

130     Object JavaDoc[] getParameterValues(ControlBeanContext context, Method JavaDoc method, Object JavaDoc[] args) {
131
132         Object JavaDoc value = null;
133         try {
134             value = context.getParameterValue(method, _nameQualifiers[0], args);
135         } catch (IllegalArgumentException JavaDoc iae) {
136             throw new ControlException("Invalid argument name in SQL statement: " + _nameQualifiers[0], iae);
137         }
138
139         for (int i = 1; i < _nameQualifiers.length; i++) {
140             // handle maps, properties, and fields...
141
value = extractValue(value, _nameQualifiers[i - 1], _nameQualifiers[i]);
142         }
143         return new Object JavaDoc[]{value};
144     }
145
146     //
147
// /////////////////////////////////////////////// PRIVATE METHODS /////////////////////////////////////////////
148
//
149

150     /**
151      * Get the value from the referenced method parameter using java reflection
152      *
153      * @param aValue
154      * @param aName
155      * @param bName
156      * @return
157      */

158     private Object JavaDoc extractValue(Object JavaDoc aValue, String JavaDoc aName, String JavaDoc bName) {
159
160         Class JavaDoc aClass = aValue.getClass();
161         Object JavaDoc value = null;
162
163         //
164
// a.isB() or a.getB()
165
//
166
String JavaDoc bNameCapped = Character.toUpperCase(bName.charAt(0)) + bName.substring(1);
167         Method JavaDoc getMethod = null;
168         Class JavaDoc retType = null;
169
170         //
171
// try a.isB() first, if found verify that a.isB() returns a boolean value,
172
// and that there is not also a a.getB() method - if there is except
173
//
174
try {
175
176             getMethod = aClass.getMethod("is" + bNameCapped, (Class JavaDoc[]) null);
177             retType = getMethod.getReturnType();
178             if (!(retType.equals(Boolean JavaDoc.class) ||
179                     retType.equals(Boolean.TYPE))) {
180                 // only boolean returns can be isB()
181
getMethod = null;
182             } else {
183                 /**
184                  * make sure ("get" + bNameCapped) does not exist as well
185                  * see CR216159
186                  */

187                 boolean getMethodFound = true;
188                 try {
189                     aClass.getMethod("get" + bNameCapped, (Class JavaDoc[])null);
190                 } catch (NoSuchMethodException JavaDoc e) {
191                     getMethodFound = false;
192                 }
193
194                 if (getMethodFound) {
195                     throw new ControlException("Colliding field accsessors in user defined class '"
196                                                + aClass.getName() + "' for field '" + bName
197                                                + "'. Please use is<FieldName> for boolean fields and get<FieldName> name for other datatypes.");
198                 }
199             }
200         } catch (NoSuchMethodException JavaDoc e) {
201         }
202
203         //
204
// try a.getB() if a.isB() was not found.
205
//
206
if (getMethod == null) {
207             try {
208                 getMethod = aClass.getMethod("get" + bNameCapped, (Class JavaDoc[])null);
209                 retType = getMethod.getReturnType();
210             } catch (NoSuchMethodException JavaDoc e) {
211             }
212         }
213
214         if (getMethod != null) {
215             // OK- a.getB()
216
try {
217                 value = getMethod.invoke(aValue, (Object JavaDoc[]) null);
218             } catch (IllegalAccessException JavaDoc e) {
219                 throw new ControlException("Unable to access public method: " + e.toString());
220             } catch (java.lang.reflect.InvocationTargetException JavaDoc e) {
221                 throw new ControlException("Exception thrown when executing : " + getMethod.getName() + "() to use as parameter");
222             }
223             return value;
224         }
225
226         //
227
// try a.b
228
//
229

230         try {
231             value = aClass.getField(bName).get(aValue);
232             return value;
233         } catch (NoSuchFieldException JavaDoc e) {
234         } catch (IllegalAccessException JavaDoc e) {
235         }
236
237         //
238
// try a.get(b)
239
//
240

241         if (aValue instanceof Map JavaDoc) {
242             try {
243                 value = TypeMappingsFactory.getInstance().lookupType(aValue, new Object JavaDoc[]{bName});
244                 return value;
245             } catch (Exception JavaDoc mapex) {
246                 throw new ControlException("Exception thrown when executing Map.get() to resolve parameter" + mapex.toString());
247             }
248         }
249
250         // no other options...
251
if (true) {
252             throw new ControlException("Illegal argument in SQL statement: " + _parameterName.toString()
253                                        + "; unable to find suitable method of retrieving property " + bName.toString()
254                                        + " out of object " + aName.toString() + ".");
255         }
256         return null;
257     }
258 }
259
Popular Tags