View Javadoc

1   package org.springframework.roo.addon.finder;
2   
3   import java.util.ArrayList;
4   import java.util.List;
5   import java.util.SortedSet;
6   import java.util.TreeSet;
7   
8   import org.springframework.roo.addon.beaninfo.BeanInfoMetadata;
9   import org.springframework.roo.addon.entity.RooEntity;
10  import org.springframework.roo.classpath.details.FieldMetadata;
11  import org.springframework.roo.classpath.details.MethodMetadata;
12  import org.springframework.roo.support.util.Assert;
13  
14  
15  /**
16   * Tokenizer used for custom find methods. Splits the presented String up by capital letters.
17   * 
18   * @author Stefan Schmidt
19   * @since 1.0
20   * 
21   */
22  public final class FinderTokenizer {
23  	
24  	private SortedSet<FieldToken> fieldTokens;
25  	
26  	private BeanInfoMetadata beanInfoMetadata;
27  	
28  	private String completeFinder;
29  
30  	/**
31  	 * Use this method to tokenize the finder method signature based on capital letters. This method asserts 
32  	 * that the signature provided is valid (i.e. the fields in the String match fields in the {@link RooEntity} 
33  	 * or are of type {@link ReservedToken}. 
34  	 * 
35  	 * @param finder The string to parse. (required)
36  	 * @param beanInfoMetadata The metadata for the {@link RooEntity} for which the finder String applies. (required)
37  	 * @return The list of tokens (could be of type {@link FieldToken} or {@link ReservedToken} as a result of the tokenizing.
38  	 */
39  	public List<Token> tokenize(String finder, String plural, BeanInfoMetadata beanInfoMetadata) {
40  		Assert.notNull(finder, "finder method signature required");
41  		Assert.hasText(finder, "Empty finder Strings not allowd");
42  		Assert.hasText(plural, "Plural required");
43  		Assert.notNull(beanInfoMetadata, "BeanInfoMetadata required");
44  		
45  		this.beanInfoMetadata = beanInfoMetadata;		
46  		this.completeFinder = finder;
47  		
48  		//just in case it starts with findBy we can remove it here
49  		finder = finder.replace("find" + plural +"By", "");
50  
51  		fieldTokens = new TreeSet<FieldToken>();
52  		
53  		for(MethodMetadata metadata : beanInfoMetadata.getPublicMutators()) {
54  			FieldMetadata fieldMetadata = beanInfoMetadata.getFieldForPropertyName(metadata.getParameterNames().get(0));
55  			
56  			//if we did find a field matching the first parameter name of the mutator method we can add it to the finder ITD
57  			if(fieldMetadata != null) {
58  				fieldTokens.add(new FieldToken(fieldMetadata));
59  			}
60  		}
61  		
62  		List<Token> tokens = new ArrayList<Token>();
63  		
64  		while(finder.length() > 0) {
65  			Token token = getFirstToken(finder);
66  			if(token != null) {
67  				if(token instanceof FieldToken) {
68  					tokens.add((FieldToken)token);					
69  				}
70  				if(token instanceof ReservedToken) {
71  					tokens.add((ReservedToken)token);
72  				}
73  				finder = finder.substring(token.getValue().length());
74  			}
75  		}		
76  		
77  		return tokens;
78  	}
79  	
80  	private Token getFirstToken(String finder) {
81  		for(FieldToken fieldToken: fieldTokens) {
82  			if (finder.startsWith(fieldToken.getValue())) {
83  				return fieldToken;								
84  			}
85  		}	
86  		for(ReservedToken reservedToken: ReservedTokenHolder.getAllTokens()) {
87  			if (finder.startsWith(reservedToken.getValue())) {
88  				return reservedToken;								
89  			}
90  		}	
91  		if (finder.length() > 0) {
92  			throw new IllegalStateException("Dynamic finder is unable to match '" + finder + "' token of '" + completeFinder + "' finder definition in " + beanInfoMetadata.getJavaBean().getSimpleTypeName() + ".java");
93  		}
94  		return null; //finder does not start with reserved or field token
95  	}	
96  }