View Javadoc
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 }