KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > springframework > web > servlet > tags > form > SelectedValueComparator


1 /*
2  * Copyright 2002-2006 the original author or authors.
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
17 package org.springframework.web.servlet.tags.form;
18
19 import org.springframework.core.enums.LabeledEnum;
20 import org.springframework.util.CollectionUtils;
21 import org.springframework.util.ObjectUtils;
22 import org.springframework.web.servlet.support.BindStatus;
23
24 import java.beans.PropertyEditor JavaDoc;
25 import java.util.Collection JavaDoc;
26 import java.util.Iterator JavaDoc;
27 import java.util.Map JavaDoc;
28
29 /**
30  * Utility class for testing whether a candidate value matches a {@link BindStatus#getValue data bound value}.
31  * Eagerly attempts to prove a comparison through a number of avenues to deal with issues such as instance
32  * inequality, logical (String-representation-based) equality and {@link PropertyEditor}-based comparison.
33  *
34  * <p>Full support is provided for comparing arrays, {@link Collection Collections} and {@link Map Maps}.
35  *
36  * <p><h1><a name="equality-contract">Equality Contract</a></h1>
37  * For single-valued objects equality is first tested using standard {@link Object#equals Java equality}. As
38  * such, user code should endeavour to implement {@link Object#equals} to speed up the comparison process. If
39  * {@link Object#equals} returns <code>false</code> then an attempt is made at an
40  * {@link #exhaustiveCompare exhaustive comparison} with the aim being to <strong>prove</strong> equality rather
41  * than disprove it.
42  *
43  * <p>Special support is given for instances of {@link LabeledEnum} with a <code>String</code>-based
44  * comparison of the candidate value against the code of the {@link LabeledEnum}. This can be useful when a
45  * {@link LabeledEnum} is used to define a list of '<code>&lt;option&gt;</code>' elements in HTML.
46  *
47  * <p>Next, an attempt is made to compare the <code>String</code> representations of both the candidate and bound
48  * values. This may result in <code>true</code> in a number of cases due to the fact both values will be represented
49  * as <code>Strings</code> when shown to the user.
50  *
51  * <p>Next, if the candidate value is a <code>String</code>, an attempt is made to compare the bound value to
52  * result of applying the corresponding {@link PropertyEditor} to the candidate. This comparison may be
53  * executed twice, once against the direct <code>String</code> instances, and then against the <code>String</code>
54  * representations if the first comparison results in <code>false</code>.
55  *
56  * @author Rob Harrop
57  * @since 2.0
58  */

59 abstract class SelectedValueComparator {
60
61     /**
62      * Returns <code>true</code> if the supplied candidate value is equal to the value bound to
63      * the supplied {@link BindStatus}. Equality in this case differs from standard Java equality and
64      * is described in more detail <a HREF="#equality-contract">here</a>.
65      */

66     public static boolean isSelected(BindStatus bindStatus, Object JavaDoc candidateValue) {
67         Object JavaDoc boundValue = getBoundValue(bindStatus);
68
69         if (boundValue == null) {
70             return (candidateValue == null);
71         }
72
73         boolean selected = false;
74
75         if (boundValue.getClass().isArray()) {
76             selected = collectionCompare(CollectionUtils.arrayToList(boundValue), candidateValue, bindStatus);
77         }
78         else if (boundValue instanceof Collection JavaDoc) {
79             selected = collectionCompare((Collection JavaDoc) boundValue, candidateValue, bindStatus);
80         }
81         else if (boundValue instanceof Map JavaDoc) {
82             selected = mapCompare((Map JavaDoc) boundValue, candidateValue, bindStatus);
83         }
84
85         if (!selected) {
86             if (ObjectUtils.nullSafeEquals(boundValue, candidateValue)) {
87                 selected = true;
88             }
89             else {
90                 selected = exhaustiveCompare(boundValue, candidateValue, bindStatus.getEditor());
91             }
92         }
93
94         return selected;
95     }
96
97
98     private static boolean mapCompare(Map JavaDoc boundMap, Object JavaDoc candidateValue, BindStatus bindStatus) {
99         if (boundMap.containsKey(candidateValue)) {
100             return true;
101         }
102         else {
103             return exhaustiveCollectionCompare(boundMap.keySet(), candidateValue, bindStatus.getEditor());
104         }
105     }
106
107     private static boolean collectionCompare(Collection JavaDoc boundCollection, Object JavaDoc candidateValue, BindStatus bindStatus) {
108         if (boundCollection.contains(candidateValue)) {
109             return true;
110         }
111         else {
112             return exhaustiveCollectionCompare(boundCollection, candidateValue, bindStatus.getEditor());
113         }
114     }
115
116     private static Object JavaDoc getBoundValue(BindStatus bindStatus) {
117         if (bindStatus == null) {
118             return null;
119         }
120         if (bindStatus.getEditor() != null) {
121             Object JavaDoc editorValue = bindStatus.getEditor().getValue();
122             if (editorValue != null) {
123                 return editorValue;
124             }
125         }
126         return bindStatus.getValue();
127     }
128
129     private static boolean exhaustiveCollectionCompare(
130                     Collection JavaDoc collection, Object JavaDoc candidateValue, PropertyEditor JavaDoc propertyEditor) {
131
132         for (Iterator JavaDoc iterator = collection.iterator(); iterator.hasNext();) {
133             Object JavaDoc o = iterator.next();
134             if (exhaustiveCompare(o, candidateValue, propertyEditor)) {
135                 return true;
136             }
137         }
138         return false;
139     }
140
141     private static boolean exhaustiveCompare(Object JavaDoc boundValue, Object JavaDoc candidate, PropertyEditor JavaDoc propertyEditor) {
142         String JavaDoc candidateDisplayString = ObjectUtils.getDisplayString(candidate);
143         if (boundValue instanceof LabeledEnum) {
144             LabeledEnum labeledEnum = (LabeledEnum) boundValue;
145             String JavaDoc enumCodeAsString = ObjectUtils.getDisplayString(labeledEnum.getCode());
146             if (enumCodeAsString.equals(candidateDisplayString)) {
147                 return true;
148             }
149             String JavaDoc enumLabelAsString = ObjectUtils.getDisplayString(labeledEnum.getLabel());
150             if (enumLabelAsString.equals(candidateDisplayString)) {
151                 return true;
152             }
153         }
154         else if (ObjectUtils.getDisplayString(boundValue).equals(candidateDisplayString)) {
155             return true;
156         }
157         else if (propertyEditor != null && candidate instanceof String JavaDoc) {
158
159             // try PE-based comparison (PE should *not* be allowed to escape creating thread)
160
Object JavaDoc originalValue = propertyEditor.getValue();
161             String JavaDoc candidateAsString = (String JavaDoc) candidate;
162             try {
163                 propertyEditor.setAsText(candidateAsString);
164                 if (ObjectUtils.nullSafeEquals(boundValue, propertyEditor.getValue())) {
165                     return true;
166                 }
167             }
168             finally {
169                 propertyEditor.setValue(originalValue);
170             }
171
172             if (propertyEditor.getValue() != null) {
173                 return ObjectUtils.nullSafeEquals(candidateAsString, propertyEditor.getAsText());
174             }
175         }
176         return false;
177     }
178
179 }
180
Popular Tags