View Javadoc

1   // Copyright 2006 Daniel Gredler
2   //
3   // Licensed under the Apache License, Version 2.0 (the "License");
4   // you may not use this file except in compliance with the License.
5   // You may obtain a copy of the License at
6   //
7   //     http://www.apache.org/licenses/LICENSE-2.0
8   //
9   // Unless required by applicable law or agreed to in writing, software
10  // distributed under the License is distributed on an "AS IS" BASIS,
11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  // See the License for the specific language governing permissions and
13  // limitations under the License.
14  
15  package net.sf.beanform.validator;
16  
17  import java.util.ArrayList;
18  import java.util.HashMap;
19  import java.util.List;
20  import java.util.Map;
21  
22  import net.sf.beanform.prop.BeanProperty;
23  
24  import org.apache.commons.logging.Log;
25  import org.apache.commons.logging.LogFactory;
26  import org.apache.tapestry.IComponent;
27  import org.apache.tapestry.event.ReportStatusEvent;
28  import org.apache.tapestry.form.validator.Validator;
29  import org.apache.tapestry.form.validator.ValidatorFactory;
30  
31  /***
32   * Default implementation of the {@link CachingValidatorFactory} interface.
33   *
34   * @author Daniel Gredler
35   */
36  public class CachingValidatorFactoryImpl implements CachingValidatorFactory {
37  
38      private final static Log LOG = LogFactory.getLog( CachingValidatorFactoryImpl.class );
39  
40      private String serviceId;
41      private ValidatorFactory validatorFactory;
42      private Map<BeanProperty, List<Validator>> cache = new HashMap<BeanProperty, List<Validator>>();
43  
44      public void setServiceId( String serviceId ) {
45          this.serviceId = serviceId;
46      }
47  
48      public void setValidatorFactory( ValidatorFactory validatorFactory ) {
49          this.validatorFactory = validatorFactory;
50      }
51  
52      @SuppressWarnings( "unchecked" )
53      public List<Validator> constructValidatorList( IComponent component, BeanProperty property ) {
54          List<Validator> validators;
55          synchronized( this.cache ) {
56              validators = this.cache.get( property );
57              if( validators == null ) {
58                  // Build up lists of inherent validators and user-defined validators (defined explicitly or via annotations).
59                  List<Validator> inherent = this.getInherentValidators( component, property );
60                  List<Validator> userDefined = this.validatorFactory.constructValidatorList( component, property.getValidators() );
61                  // Combine these validator lists into a single master list.
62                  validators = new ArrayList<Validator>();
63                  validators.addAll( inherent );
64                  validators.addAll( userDefined );
65                  // Cache it and we're done!
66                  this.cache.put( property, validators );
67                  if( LOG.isDebugEnabled() ) {
68                      LOG.debug( "Bean property '" + property.getName() + "' " +
69                                 "has " + validators.size() + " validators: " + validators );
70                  }
71              }
72          }
73          return validators;
74      }
75  
76      public void resetEventDidOccur() {
77          synchronized( this.cache ) {
78              this.cache.clear();
79          }
80      }
81  
82      public void reportStatus( ReportStatusEvent event ) {
83          event.title( this.serviceId );
84          synchronized( this.cache ) {
85              event.property( "cached validator count", this.cache.size() );
86              event.collection( "cached validators", this.cache.keySet() );
87          }
88      }
89  
90      /***
91       * Returns validators for the specified property that are inherent to the property type (ie, "this
92       * property is a short, so its minimum value must be {@link Short#MIN_VALUE}"). It's important that
93       * the number validation come before the min/max value validations.
94       */
95      @SuppressWarnings( "unchecked" )
96      private List<Validator> getInherentValidators( IComponent component, BeanProperty property ) {
97  
98          String number = null;
99          if( property.isNumber() ) {
100             if( property.isFloat() || property.isDouble() ) number = NumberValidator.NAME;
101             else number = WholeNumberValidator.NAME;
102         }
103 
104         String minValue;
105         if( property.isShort() ) minValue = String.valueOf( Short.MIN_VALUE );
106         else if( property.isInteger() ) minValue = String.valueOf( Integer.MIN_VALUE );
107         else if( property.isLong() ) minValue = String.valueOf( Long.MIN_VALUE );
108         else if( property.isFloat() ) minValue = String.valueOf( Float.MIN_VALUE );
109         else if( property.isDouble() ) minValue = String.valueOf( Double.MIN_VALUE );
110         else minValue = null;
111 
112         String maxValue;
113         if( property.isShort() ) maxValue = String.valueOf( Short.MAX_VALUE );
114         else if( property.isInteger() ) maxValue = String.valueOf( Integer.MAX_VALUE );
115         else if( property.isLong() ) maxValue = String.valueOf( Long.MAX_VALUE );
116         else if( property.isFloat() ) maxValue = String.valueOf( Float.MAX_VALUE );
117         else if( property.isDouble() ) maxValue = String.valueOf( Double.MAX_VALUE );
118         else maxValue = null;
119 
120         StringBuilder sb = new StringBuilder();
121         if( number != null   ) sb.append( number );
122         if( minValue != null ) sb.append( sb.length() > 0 ? "," : "" ).append( StringMin.NAME ).append( "=" ).append( minValue );
123         if( maxValue != null ) sb.append( sb.length() > 0 ? "," : "" ).append( StringMax.NAME ).append( "=" ).append( maxValue );
124 
125         String expression = sb.toString();
126         return this.validatorFactory.constructValidatorList( component, expression );
127     }
128 
129 }