Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
GenericComparator |
|
| 4.166666666666667;4.167 |
1 | /* | |
2 | * Licensed to the Apache Software Foundation (ASF) under one or more | |
3 | * contributor license agreements. See the NOTICE file distributed with | |
4 | * this work for additional information regarding copyright ownership. | |
5 | * The ASF licenses this file to you under the Apache License, Version 2.0 | |
6 | * (the "License"); you may not use this file except in compliance with | |
7 | * the License. You may obtain a copy of the License at | |
8 | * | |
9 | * http://www.apache.org/licenses/LICENSE-2.0 | |
10 | * | |
11 | * Unless required by applicable law or agreed to in writing, software | |
12 | * distributed under the License is distributed on an "AS IS" BASIS, | |
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
14 | * See the License for the specific language governing permissions and | |
15 | * limitations under the License. | |
16 | */ | |
17 | ||
18 | package org.apache.shale.usecases.rolodex; | |
19 | ||
20 | import java.beans.BeanInfo; | |
21 | import java.beans.Introspector; | |
22 | import java.beans.PropertyDescriptor; | |
23 | import java.lang.reflect.InvocationTargetException; | |
24 | import java.util.ArrayList; | |
25 | import java.util.Comparator; | |
26 | import java.util.Iterator; | |
27 | import java.util.List; | |
28 | import java.util.Map; | |
29 | import java.util.StringTokenizer; | |
30 | import javax.faces.FacesException; | |
31 | import javax.faces.el.PropertyNotFoundException; | |
32 | import org.apache.commons.logging.Log; | |
33 | import org.apache.commons.logging.LogFactory; | |
34 | ||
35 | /** | |
36 | * <p>Generic comparator that uses a list of property names to compare | |
37 | * the state of two objects using the reflection API. The property names | |
38 | * are passed via a comma delimited. The collating sequence is determined | |
39 | * by the <code>sortAcending</code> attribute.</p> | |
40 | */ | |
41 | 10 | public class GenericComparator implements Comparator { |
42 | ||
43 | /** | |
44 | * <p>Common logger utility.</p> | |
45 | */ | |
46 | public static Log log; | |
47 | static { | |
48 | 2 | log = LogFactory.getLog(GenericComparator.class); |
49 | 1 | } |
50 | ||
51 | /** | |
52 | * <p>Determines the collating sequence. A <code>true</code> value | |
53 | * will sort acending; otherwise, the list will be sorted in descending | |
54 | * order.</p> | |
55 | */ | |
56 | 10 | private boolean sortAscending = true; |
57 | ||
58 | /** | |
59 | * <p>Holds an array of property names in the target object that | |
60 | * will be use to compare the two objects. | |
61 | * </p> | |
62 | */ | |
63 | protected List sortBy; | |
64 | ||
65 | /** | |
66 | * <p>Returns <code>true</code> if the collection should be sorted ascending by | |
67 | * the <code>sortBy</code> properties list.<p> | |
68 | */ | |
69 | public boolean getSortAscending() { | |
70 | return sortAscending; | |
71 | } | |
72 | ||
73 | /** | |
74 | * <p>Sets the sequence the collection should be sorted. A <code>true</code> | |
75 | * will result in sort ascending.</p> | |
76 | */ | |
77 | public void setSortAscending(boolean value) { | |
78 | sortAscending = value; | |
79 | } | |
80 | ||
81 | /** | |
82 | * <p>Passed a comma delimited list of property names to compare two object by.<p> | |
83 | */ | |
84 | public void setSortBy(String properties) { | |
85 | 10 | StringTokenizer tokenizer = new StringTokenizer(properties, ","); |
86 | 10 | sortBy = new ArrayList(); |
87 | 25 | while (tokenizer.hasMoreTokens()) { |
88 | 15 | String token = tokenizer.nextToken().trim(); |
89 | 15 | sortBy.add(token); |
90 | 15 | } |
91 | ||
92 | 10 | } |
93 | ||
94 | /** | |
95 | * <p>Returns a comma delimited list of property names used to compare | |
96 | * two objects.</p> | |
97 | */ | |
98 | public String getSortBy() { | |
99 | StringBuffer tmp = new StringBuffer(); | |
100 | if (sortBy != null) { | |
101 | Iterator li = sortBy.iterator(); | |
102 | while (li.hasNext()) { | |
103 | if (tmp.length() > 0) { | |
104 | tmp.append(", "); | |
105 | } | |
106 | tmp.append(li.next()); | |
107 | } | |
108 | } | |
109 | ||
110 | return tmp.toString(); | |
111 | } | |
112 | ||
113 | /** | |
114 | * <p>Compares the property names in the <code>sortBy</code> list with | |
115 | * the target sortable objects. The collating sequence is determined | |
116 | * by the <code>sortAcending</code> attribute. | |
117 | * </p> | |
118 | * | |
119 | * @param o1 - | |
120 | * target object 1 | |
121 | * @param o2 - | |
122 | * target object 2 | |
123 | * @return - integer value representing the comparison of the two objects | |
124 | * key properties. | |
125 | */ | |
126 | public int compare(Object o1, Object o2) { | |
127 | 2692 | Iterator it = sortBy.iterator(); |
128 | 2692 | int result = 0; |
129 | 5411 | while (result == 0 && it.hasNext()) { |
130 | 2719 | String nextProperty = (String) it.next(); |
131 | ||
132 | 2719 | Object col1 = null; |
133 | 2719 | Object col2 = null; |
134 | ||
135 | 2719 | col1 = value(o1, nextProperty); |
136 | 2719 | col2 = value(o2, nextProperty); |
137 | ||
138 | 2719 | if ((col1 == null) && (col2 == null)) |
139 | result = 0; | |
140 | 2719 | else if ((col1 == null) && (col2 != null)) |
141 | result = -1; | |
142 | 2719 | else if ((col2 == null) && (col1 != null)) |
143 | result = 1; | |
144 | 2719 | else if ((col1 instanceof Comparable) |
145 | && (col2 instanceof Comparable)) | |
146 | 2719 | result = ((Comparable) col1).compareTo(col2); |
147 | else { | |
148 | ||
149 | result = ((Comparable) col1.toString()).compareTo(col2 | |
150 | .toString()); | |
151 | } | |
152 | ||
153 | 2719 | col1 = null; |
154 | 2719 | col2 = null; |
155 | ||
156 | 2719 | } |
157 | 2692 | return (sortAscending ? 1 : -1) * result; |
158 | } | |
159 | ||
160 | ||
161 | // --------------------------------------------------------- Private Methods | |
162 | ||
163 | ||
164 | /** | |
165 | * <p>Return the specified property value from the specified object, | |
166 | * if possible.</p> | |
167 | * | |
168 | * @param base Base object from which to retrieve a property | |
169 | * @param name Name of the property to be retrieved | |
170 | */ | |
171 | private Object value(Object base, String name) { | |
172 | ||
173 | 5438 | if (base instanceof Map) { |
174 | return ((Map) base).get(name); | |
175 | } | |
176 | try { | |
177 | 5438 | BeanInfo info = Introspector.getBeanInfo(base.getClass()); |
178 | 5438 | PropertyDescriptor[] descriptors = info.getPropertyDescriptors(); |
179 | 30100 | for (int i = 0; i < descriptors.length; i++) { |
180 | 30100 | if (name.equals(descriptors[i].getName())) { |
181 | 5438 | return descriptors[i].getReadMethod().invoke(base, null); |
182 | } | |
183 | } | |
184 | throw new PropertyNotFoundException(name); | |
185 | } catch (RuntimeException e) { | |
186 | throw e; | |
187 | } catch (Exception e) { | |
188 | throw new FacesException(e); | |
189 | } | |
190 | ||
191 | } | |
192 | ||
193 | ||
194 | ||
195 | } |