1 /*
2 * Copyright (c) 2002-2014, Mairie de Paris
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright notice
10 * and the following disclaimer.
11 *
12 * 2. Redistributions in binary form must reproduce the above copyright notice
13 * and the following disclaimer in the documentation and/or other materials
14 * provided with the distribution.
15 *
16 * 3. Neither the name of 'Mairie de Paris' nor 'Lutece' nor the names of its
17 * contributors may be used to endorse or promote products derived from
18 * this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
24 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 *
32 * License 1.0
33 */
34 package fr.paris.lutece.util.sort;
35
36 import fr.paris.lutece.portal.service.util.AppLogService;
37
38 import java.io.Serializable;
39
40 import java.lang.reflect.InvocationTargetException;
41 import java.lang.reflect.Method;
42
43 import java.util.Comparator;
44
45
46 /**
47 * This class provide Attribute Comparator
48 */
49 public class AttributeComparator implements Comparator<Object>, Serializable
50 {
51 private static final long serialVersionUID = 8552197766086300259L;
52 private String _strSortedAttribute;
53 private boolean _bIsASC;
54
55 /**
56 * Constructor
57 * @param strSortedAttribute the name of the attribute on which the sort will be made
58 * @param bIsASC true for the ASC order, false for the DESC order
59 */
60 public AttributeComparator( String strSortedAttribute, boolean bIsASC )
61 {
62 this._strSortedAttribute = strSortedAttribute;
63 this._bIsASC = bIsASC;
64 }
65
66 /**
67 * Constructor
68 * @param strSortedAttribute the name of the attribute on which the sort will be made
69 */
70 public AttributeComparator( String strSortedAttribute )
71 {
72 this._strSortedAttribute = strSortedAttribute;
73 this._bIsASC = true;
74 }
75
76 /**
77 * Compare two objects o1 and o2.
78 * @param o1 Object
79 * @param o2 Object
80 * @return < 0 if o1 is before o2 in the alphabetical order 0 if o1 equals o2 > 0 if o1 is after o2
81 */
82 @Override
83 public int compare( Object o1, Object o2 )
84 {
85 int nStatus = 0;
86
87 Method method1 = getMethod( o1 );
88 Method method2 = getMethod( o2 );
89
90 if ( ( method1 != null ) && ( method2 != null ) && ( method1.getReturnType( ) == method2.getReturnType( ) ) )
91 {
92 try
93 {
94 Object oRet1 = method1.invoke( o1 );
95 Object oRet2 = method2.invoke( o2 );
96
97 String strReturnType = method1.getReturnType( ).getName( ).toString( );
98 Class<?> returnType = method1.getReturnType( );
99
100 if ( oRet1 == null )
101 {
102 if ( oRet2 == null )
103 {
104 nStatus = 0;
105 }
106 else
107 {
108 nStatus = -1;
109 }
110 }
111 else
112 {
113 if ( oRet2 == null )
114 {
115 nStatus = 1;
116 }
117 else
118 {
119 if ( strReturnType.equals( "java.lang.String" ) )
120 {
121 nStatus = ( (String) oRet1 ).toLowerCase( ).compareTo( ( (String) oRet2 ).toLowerCase( ) );
122 }
123 else if ( returnType.isPrimitive( ) || isComparable( returnType ) )
124 {
125 nStatus = ( (Comparable) oRet1 ).compareTo( (Comparable) oRet2 );
126 }
127 else if ( returnType.isEnum( ) )
128 {
129 nStatus = oRet1.toString( ).compareTo( oRet2.toString( ) );
130 }
131 }
132 }
133 }
134 catch ( IllegalArgumentException e )
135 {
136 AppLogService.error( e );
137 }
138 catch ( IllegalAccessException e )
139 {
140 AppLogService.error( e );
141 }
142 catch ( InvocationTargetException e )
143 {
144 AppLogService.error( e );
145 }
146 }
147
148 if ( !_bIsASC )
149 {
150 nStatus = nStatus * ( -1 );
151 }
152
153 return nStatus;
154 }
155
156 /**
157 * Return the getter method of the object obj for the attribute _strSortedAttribute
158 * @param obj the object
159 * @return method Method of the object obj for the attribute _strSortedAttribute
160 */
161 private Method getMethod( Object obj )
162 {
163 Method method = null;
164 String strFirstLetter = _strSortedAttribute.substring( 0, 1 ).toUpperCase( );
165
166 String strMethodName = "get" + strFirstLetter +
167 _strSortedAttribute.substring( 1, _strSortedAttribute.length( ) );
168
169 try
170 {
171 method = obj.getClass( ).getMethod( strMethodName );
172 }
173 catch ( Exception e )
174 {
175 AppLogService.error( e );
176 }
177
178 return method;
179 }
180
181 /**
182 * Returns <code>true</code> if the class implements {@link Comparable} or extends a super class that
183 * implements {@link Comparable}, <code>false</code> otherwise.
184 * @param clazz the class
185 * @return <code>true</code> if the class implements {@link Comparable}, <code>false</code> otherwise.
186 */
187 private boolean isComparable( Class<?> clazz )
188 {
189 for ( Class<?> interfac : clazz.getInterfaces( ) )
190 {
191 if ( interfac.equals( Comparable.class ) )
192 {
193 return true;
194 }
195 }
196
197 // The class might be extending a super class that implements {@link Comparable}
198 Class<?> superClass = clazz.getSuperclass( );
199
200 if ( superClass != null )
201 {
202 return isComparable( superClass );
203 }
204
205 return false;
206 }
207 }