View Javadoc

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   * Default implementation of {@link DynamicFinderServices}.
23   * 
24   * @author Stefan Schmidt
25   * @since 1.0
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  				//ignoring java.util.Map field types (see ROO-194)
43  				if (field == null || field.getFieldType().equals(new JavaType(Map.class.getName()))) {
44  					continue;
45  				}
46  				if (!PhysicalTypeIdentifier.isValid(field.getDeclaredByMetadataId())) {
47  					// We are only interested in fields declared by physical types - not fields declared by ITDs
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 						//remove the last field token
192 						names.remove(names.size()-1);
193 						//and replace by a min and a max value
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 }