1 package org.springframework.roo.addon.finder;
2
3 import java.util.ArrayList;
4 import java.util.Calendar;
5 import java.util.Date;
6 import java.util.HashSet;
7 import java.util.List;
8 import java.util.Map;
9 import java.util.Set;
10 import java.util.SortedSet;
11 import java.util.TreeSet;
12
13 import org.springframework.roo.addon.beaninfo.BeanInfoMetadata;
14 import org.springframework.roo.classpath.PhysicalTypeIdentifier;
15 import org.springframework.roo.classpath.details.FieldMetadata;
16 import org.springframework.roo.classpath.details.MethodMetadata;
17 import org.springframework.roo.model.JavaSymbolName;
18 import org.springframework.roo.model.JavaType;
19 import org.springframework.roo.support.util.Assert;
20
21
22
23
24
25
26
27 public class DynamicFinderServicesImpl implements DynamicFinderServices {
28
29 public List<JavaSymbolName> getFindersFor(BeanInfoMetadata beanInfoMetadata, String plural, int maxDepth) {
30 Assert.notNull(beanInfoMetadata, "Bean info metadata required");
31 Assert.hasText(plural, "Plural required");
32 Assert.notNull(maxDepth, "maxDepth required");
33
34 SortedSet<JavaSymbolName> finders = new TreeSet<JavaSymbolName>();
35 SortedSet<JavaSymbolName> tempFinders = new TreeSet<JavaSymbolName>();
36
37 for (int i = 0; i < maxDepth; i++) {
38 for (MethodMetadata accessor : beanInfoMetadata.getPublicAccessors()) {
39
40 JavaSymbolName propertyName = beanInfoMetadata.getPropertyNameForJavaBeanMethod(accessor);
41 FieldMetadata field = beanInfoMetadata.getFieldForPropertyName(propertyName);
42
43 if (field == null || field.getFieldType().equals(new JavaType(Map.class.getName()))) {
44 continue;
45 }
46 if (!PhysicalTypeIdentifier.isValid(field.getDeclaredByMetadataId())) {
47
48 continue;
49 }
50 if (i == 0) {
51 tempFinders.addAll(createFinders(field, finders, "find" + plural + "By", true));
52 } else {
53 tempFinders.addAll(createFinders(field, finders, "And", false));
54 tempFinders.addAll(createFinders(field, finders, "Or", false));
55 }
56 }
57 finders.addAll(tempFinders);
58 }
59
60 return new ArrayList<JavaSymbolName>(finders);
61 }
62
63 public String getJpaQueryFor(JavaSymbolName finderName, String plural, BeanInfoMetadata beanInfoMetadata) {
64 Assert.notNull(beanInfoMetadata, "Bean info metadata required");
65 Assert.hasText(plural, "Plural required");
66 Assert.notNull(finderName, "JavaSymbolName required");
67
68 String tablename = beanInfoMetadata.getJavaBean().getSimpleTypeName();
69
70 StringBuilder builder = new StringBuilder();
71 builder.append("SELECT ").append(tablename);
72 builder.append(" FROM ").append(tablename);
73 builder.append(" AS ").append(tablename.toLowerCase());
74 builder.append(" WHERE ");
75
76 FinderTokenizer tokenizer = new FinderTokenizer();
77
78 List<Token> tokens = tokenizer.tokenize(finderName.getSymbolName(), plural, beanInfoMetadata);
79
80 FieldToken lastFieldToken = null;
81 boolean isNewField = true;
82 boolean isFieldApplied = false;
83 for (Token token : tokens) {
84 if (token instanceof ReservedToken) {
85 String reservedToken = token.getValue();
86 String fieldName = lastFieldToken.getField().getFieldName().getSymbolName();
87 boolean setField = true;
88
89 if (!lastFieldToken.getField().getFieldType().isCommonCollectionType()) {
90 if(isNewField){
91 if (reservedToken.equalsIgnoreCase("Like")) {
92 builder.append("LOWER(").append(tablename.toLowerCase()).append(".").append(fieldName).append(")");
93 } else {
94 builder.append(tablename.toLowerCase()).append(".").append(fieldName);
95 }
96 isNewField = false;
97 isFieldApplied = false;
98 }
99 if (reservedToken.equalsIgnoreCase("And")) {
100 if(!isFieldApplied){
101 builder.append(" = :").append(fieldName);
102 isFieldApplied = true;
103 }
104 builder.append(" AND ");
105 setField = false;
106 } else if (reservedToken.equalsIgnoreCase("Or")) {
107 if(!isFieldApplied){
108 builder.append(" = :").append(fieldName);
109 isFieldApplied = true;
110 }
111 builder.append(" OR ");
112 setField = false;
113 } else if (reservedToken.equalsIgnoreCase("Between")) {
114 builder.append(" BETWEEN ").append(":min").append(lastFieldToken.getField().getFieldName().getSymbolNameCapitalisedFirstLetter()).append(" AND ").append(":max").append(lastFieldToken.getField().getFieldName().getSymbolNameCapitalisedFirstLetter()).append(" ");
115 setField = false;
116 isFieldApplied = true;
117 } else if (reservedToken.equalsIgnoreCase("Like")) {
118 builder.append(" LIKE ");
119 setField = true;
120 } else if (reservedToken.equalsIgnoreCase("IsNotNull")) {
121 builder.append(" IS NOT NULL ");
122 setField = false;
123 isFieldApplied = true;
124 } else if (reservedToken.equalsIgnoreCase("IsNull")) {
125 builder.append(" IS NULL ");
126 setField = false;
127 isFieldApplied = true;
128 } else if (reservedToken.equalsIgnoreCase("Not")) {
129 builder.append(" IS NOT ");
130 } else if (reservedToken.equalsIgnoreCase("NotEquals")) {
131 builder.append(" != ");
132 } else if (reservedToken.equalsIgnoreCase("LessThan")) {
133 builder.append(" < ");
134 } else if (reservedToken.equalsIgnoreCase("LessThanEquals")) {
135 builder.append(" <= ");
136 } else if (reservedToken.equalsIgnoreCase("GreaterThan")) {
137 builder.append(" > ");
138 } else if (reservedToken.equalsIgnoreCase("GreaterThanEquals")) {
139 builder.append(" >= ");
140 } else if (reservedToken.equalsIgnoreCase("Equals")) {
141 builder.append(" = ");
142 }
143 if(setField) {
144 if (builder.toString().endsWith("LIKE ")) {
145 builder.append("LOWER(:").append(fieldName).append(") ");
146 } else {
147 builder.append(":").append(fieldName).append(" ");
148 }
149 isFieldApplied = true;
150 }
151 }
152 } else {
153 lastFieldToken = (FieldToken) token;
154 isNewField = true;
155 }
156 }
157 if(isNewField){
158 if(!lastFieldToken.getField().getFieldType().isCommonCollectionType()) {
159 builder.append(tablename.toLowerCase()).append(".").append(lastFieldToken.getField().getFieldName().getSymbolName());
160 }
161 isFieldApplied = false;
162 }
163 if(!isFieldApplied) {
164 if(!lastFieldToken.getField().getFieldType().isCommonCollectionType()) {
165 builder.append(" = :").append(lastFieldToken.getField().getFieldName().getSymbolName());
166 }
167 }
168 return builder.toString().trim();
169 }
170
171 public List<JavaSymbolName> getParameterNames(JavaSymbolName finderName, String plural, BeanInfoMetadata beanInfoMetadata) {
172 Assert.notNull(beanInfoMetadata, "Bean info metadata required");
173 Assert.hasText(plural, "Plural required");
174 Assert.notNull(finderName, "JavaSymbolName required");
175
176 List<JavaSymbolName> names = new ArrayList<JavaSymbolName>();
177
178 FinderTokenizer tokenizer = new FinderTokenizer();
179 List<Token> tokens = tokenizer.tokenize(finderName.getSymbolName(), plural, beanInfoMetadata);
180
181 for (int i = 0; i < tokens.size(); i++) {
182 Token token = tokens.get(i);
183 if (token instanceof FieldToken) {
184 String fieldName = (((FieldToken) token).getField().getFieldName().getSymbolName());
185 names.add(new JavaSymbolName(fieldName));
186 } else {
187 if("Between".equals(token.getValue())) {
188 Token field = tokens.get(i-1);
189 if(field instanceof FieldToken) {
190 JavaSymbolName fieldName = names.get(names.size() - 1);
191
192 names.remove(names.size()-1);
193
194 names.add(new JavaSymbolName("min" + fieldName.getSymbolNameCapitalisedFirstLetter()));
195 names.add(new JavaSymbolName("max" + fieldName.getSymbolNameCapitalisedFirstLetter()));
196 }
197 } else if("IsNull".equals(token.getValue()) || "IsNotNull".equals(token.getValue())) {
198 Token field = tokens.get(i-1);
199 if(field instanceof FieldToken) {
200 names.remove(names.size()-1);
201 }
202 }
203 }
204 }
205
206 return names;
207 }
208
209 public List<JavaType> getParameterTypes(JavaSymbolName finderName, String plural, BeanInfoMetadata beanInfoMetadata) {
210 Assert.notNull(beanInfoMetadata, "Bean info metadata required");
211 Assert.hasText(plural, "Plural required");
212 Assert.notNull(finderName, "JavaSymbolName required");
213
214 List<JavaType> types = new ArrayList<JavaType>();
215
216 FinderTokenizer tokenizer = new FinderTokenizer();
217 List<Token> tokens = tokenizer.tokenize(finderName.getSymbolName(), plural, beanInfoMetadata);
218
219 for (int i = 0; i < tokens.size(); i++) {
220 Token token = tokens.get(i);
221 if (token instanceof FieldToken) {
222 types.add(((FieldToken) token).getField().getFieldType());
223 } else {
224 if("Between".equals(token.getValue())) {
225 Token field = tokens.get(i-1);
226 if(field instanceof FieldToken) {
227 types.add(types.get(types.size() - 1));
228 }
229 } else if("IsNull".equals(token.getValue()) || "IsNotNull".equals(token.getValue())) {
230 Token field = tokens.get(i-1);
231 if(field instanceof FieldToken) {
232 types.remove(types.size()-1);
233 }
234 }
235 }
236 }
237 return types;
238 }
239
240 private Set<JavaSymbolName> createFinders(FieldMetadata field, Set<JavaSymbolName> finders, String prepend, boolean isFirst) {
241 Set<JavaSymbolName> tempFinders = new HashSet<JavaSymbolName>();
242
243 if (isNumberOrDate(field.getFieldType().getFullyQualifiedTypeName())) {
244 for (ReservedToken keyWord : ReservedTokenHolder.getNumericTokens()) {
245 tempFinders.addAll(populateFinders(finders, field, prepend, isFirst, keyWord.getValue()));
246 }
247 } else if (field.getFieldType().getFullyQualifiedTypeName().equals(String.class.getName())) {
248 for (ReservedToken keyWord : ReservedTokenHolder.getStringTokens()) {
249 tempFinders.addAll(populateFinders(finders, field, prepend, isFirst, keyWord.getValue()));
250 }
251 } else if (field.getFieldType().getFullyQualifiedTypeName().equals(Boolean.class.getName()) || field.getFieldType().getFullyQualifiedTypeName().equals(boolean.class.getName())) {
252 for (ReservedToken keyWord : ReservedTokenHolder.getBooleanTokens()) {
253 tempFinders.addAll(populateFinders(finders, field, prepend, isFirst, keyWord.getValue()));
254 }
255 }
256 tempFinders.addAll(populateFinders(finders, field, prepend, isFirst, ""));
257
258 return tempFinders;
259 }
260
261 private Set<JavaSymbolName> populateFinders(Set<JavaSymbolName> finders, FieldMetadata field, String prepend, boolean isFirst, String keyWord) {
262 Set<JavaSymbolName> tempFinders = new HashSet<JavaSymbolName>();
263
264 if (isFirst) {
265 tempFinders.add(new JavaSymbolName(prepend + field.getFieldName().getSymbolNameCapitalisedFirstLetter() + keyWord));
266 } else {
267 for (JavaSymbolName finder : finders) {
268 if (!finder.getSymbolName().contains(field.getFieldName().getSymbolNameCapitalisedFirstLetter())) {
269 tempFinders.add(new JavaSymbolName(finder.getSymbolName() + prepend + field.getFieldName().getSymbolNameCapitalisedFirstLetter() + keyWord));
270 }
271 }
272 }
273 return tempFinders;
274 }
275
276 private boolean isNumberOrDate(String fullyQualifiedTypeName) {
277 if (fullyQualifiedTypeName.equals(Double.class.getName())) {
278 return true;
279 }
280 if (fullyQualifiedTypeName.equals(double.class.getName())) {
281 return true;
282 }
283 if (fullyQualifiedTypeName.equals(Float.class.getName())) {
284 return true;
285 }
286 if (fullyQualifiedTypeName.equals(float.class.getName())) {
287 return true;
288 }
289 if (fullyQualifiedTypeName.equals(Integer.class.getName())) {
290 return true;
291 }
292 if (fullyQualifiedTypeName.equals(int.class.getName())) {
293 return true;
294 }
295 if (fullyQualifiedTypeName.equals(Long.class.getName())) {
296 return true;
297 }
298 if (fullyQualifiedTypeName.equals(long.class.getName())) {
299 return true;
300 }
301 if (fullyQualifiedTypeName.equals(Short.class.getName())) {
302 return true;
303 }
304 if (fullyQualifiedTypeName.equals(short.class.getName())) {
305 return true;
306 }
307 if (fullyQualifiedTypeName.equals(Date.class.getName())) {
308 return true;
309 }
310 if (fullyQualifiedTypeName.equals(Calendar.class.getName())) {
311 return true;
312 }
313 return false;
314 }
315 }