2009/05/20 - Apache Shale has been retired.

For more information, please explore the Attic.

View Javadoc

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  public class GenericComparator implements Comparator {
42      
43      /***
44       * <p>Common logger utility.</p>
45       */
46      public static Log log;
47      static {
48          log = LogFactory.getLog(GenericComparator.class);
49      }   
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      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         StringTokenizer tokenizer = new StringTokenizer(properties, ",");
86         sortBy = new ArrayList();
87         while (tokenizer.hasMoreTokens()) {
88            String token = tokenizer.nextToken().trim();
89            sortBy.add(token);
90         }
91         
92      }
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         Iterator it = sortBy.iterator();
128         int result = 0;
129         while (result == 0 && it.hasNext()) {
130             String nextProperty = (String) it.next();
131 
132             Object col1 = null;
133             Object col2 = null;
134 
135             col1 = value(o1, nextProperty);
136             col2 = value(o2, nextProperty);
137 
138             if ((col1 == null) && (col2 == null))
139                 result = 0;
140             else if ((col1 == null) && (col2 != null))
141                 result = -1;
142             else if ((col2 == null) && (col1 != null))
143                 result = 1;
144             else if ((col1 instanceof Comparable)
145                     && (col2 instanceof Comparable))
146                 result = ((Comparable) col1).compareTo(col2);
147             else {
148 
149                 result = ((Comparable) col1.toString()).compareTo(col2
150                         .toString());
151             }
152 
153             col1 = null;
154             col2 = null;
155 
156         }
157         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         if (base instanceof Map) {
174             return ((Map) base).get(name);
175         }
176         try {
177             BeanInfo info = Introspector.getBeanInfo(base.getClass());
178             PropertyDescriptor[] descriptors = info.getPropertyDescriptors();
179             for (int i = 0; i < descriptors.length; i++) {
180                 if (name.equals(descriptors[i].getName())) {
181                     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 }