View Javadoc
1   /*
2    * ObjectLab, http://www.objectlab.co.uk/open is supporting FlatPack.
3    *
4    * Based in London, we are world leaders in the design and development
5    * of bespoke applications for the securities financing markets.
6    *
7    * <a href="http://www.objectlab.co.uk/open">Click here to learn more</a>
8    *           ___  _     _           _   _          _
9    *          / _ \| |__ (_) ___  ___| |_| |    __ _| |__
10   *         | | | | '_ \| |/ _ \/ __| __| |   / _` | '_ \
11   *         | |_| | |_) | |  __/ (__| |_| |__| (_| | |_) |
12   *          \___/|_.__// |\___|\___|\__|_____\__,_|_.__/
13   *                   |__/
14   *
15   *                     www.ObjectLab.co.uk
16   *
17   * $Id: ColorProvider.java 74 2006-10-24 22:19:05Z benoitx $
18   *
19   * Copyright 2006 the original author or authors.
20   *
21   * Licensed under the Apache License, Version 2.0 (the "License"); you may not
22   * use this file except in compliance with the License. You may obtain a copy of
23   * the License at
24   *
25   * http://www.apache.org/licenses/LICENSE-2.0
26   *
27   * Unless required by applicable law or agreed to in writing, software
28   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
29   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
30   * License for the specific language governing permissions and limitations under
31   * the License.
32   */
33  package net.sf.flatpack.ordering;
34  
35  import java.text.ParseException;
36  import java.text.SimpleDateFormat;
37  import java.util.ArrayList;
38  import java.util.Calendar;
39  import java.util.Comparator;
40  import java.util.Date;
41  import java.util.GregorianCalendar;
42  import java.util.List;
43  import java.util.Locale;
44  
45  import net.sf.flatpack.Parser;
46  import net.sf.flatpack.structure.Row;
47  import net.sf.flatpack.util.FPConstants;
48  import net.sf.flatpack.util.ParserUtils;
49  import net.sf.flatpack.xml.MetaData;
50  
51  /**
52   * @author paul zepernick
53   *
54   * resorts an array of objects. Arrays get sorted by OrderElements. Right now,
55   * this class will only handle string comparisons.
56   *
57   * @version 2.0
58   */
59  public class OrderBy implements Comparator<Row> {
60      /** collection of order elements to sort by */
61      private final List<OrderColumn> orderbys = new ArrayList<>();
62  
63      private MetaData metaData;
64  
65      private Parser parser;
66  
67      /**
68       * Adds an order element to the sort.
69       *
70       * @param oc -
71       *            OrderColumn
72       */
73      public void addOrderColumn(final OrderColumn oc) {
74          orderbys.add(oc);
75      }
76  
77      /**
78       * overridden from the Comparator class.
79       *
80       * Performs the sort
81       *
82       * @return int
83       */
84      @Override
85      public int compare(final Row row0, final Row row1) {
86          int result = 0;
87  
88          for (int i = 0; i < orderbys.size(); i++) {
89              final OrderColumn oc = orderbys.get(i);
90              // null indicates "detail" record which is what the parser assigns
91              // to <column> 's setup outside of <record> elements
92              final String mdkey0 = row0.getMdkey() == null ? FPConstants.DETAIL_ID : row0.getMdkey();
93              final String mdkey1 = row1.getMdkey() == null ? FPConstants.DETAIL_ID : row1.getMdkey();
94  
95              // shift all non detail records to the bottom of the DataSet
96              if (!mdkey0.equals(FPConstants.DETAIL_ID) && !mdkey1.equals(FPConstants.DETAIL_ID)) {
97                  // keep headers / trailers in the same order at the bottom of
98                  // the DataSet
99                  return 0;
100             } else if (!mdkey0.equals(FPConstants.DETAIL_ID) || !mdkey1.equals(FPConstants.DETAIL_ID)) {
101                 return !mdkey0.equals(FPConstants.DETAIL_ID) ? 1 : 0;
102             }
103 
104             result = compareCol(row0, row1, oc);
105 
106             // if it is = 0 then the primary sort is done, and it can start the
107             // secondary sorts
108             if (result != 0) {
109                 break;
110             }
111         }
112 
113         return result;
114     }
115 
116     private int compareCol(final Row row0, final Row row1, final OrderColumn oc) {
117         int result;
118         // convert to one type of case so the comparator does not take case
119         // into account when sorting
120         Comparable comp0 = null;
121         Comparable comp1 = null;
122         final String str0 = row0
123                 .getValue(ParserUtils.getColumnIndex(row0.getMdkey(), metaData, oc.getColumnName(), parser.isColumnNamesCaseSensitive()))
124                 .toLowerCase(Locale.getDefault());
125         final String str1 = row1
126                 .getValue(ParserUtils.getColumnIndex(row1.getMdkey(), metaData, oc.getColumnName(), parser.isColumnNamesCaseSensitive()))
127                 .toLowerCase(Locale.getDefault());
128         switch (oc.getSelectedColType()) {
129         case OrderColumn.COLTYPE_NUMERIC:
130             comp0 = Double.valueOf(ParserUtils.stripNonDoubleChars(str0));
131             comp1 = Double.valueOf(ParserUtils.stripNonDoubleChars(str1));
132             break;
133         case OrderColumn.COLTYPE_DATE:
134             final SimpleDateFormat sdf = new SimpleDateFormat(oc.getDateFormatPattern());
135             try {
136                 comp0 = sdf.parse(str0);
137             } catch (final ParseException e) {
138                 comp0 = getBadDateDefault();
139 
140             }
141 
142             try {
143                 comp1 = sdf.parse(str1);
144             } catch (final ParseException e) {
145                 comp1 = getBadDateDefault();
146             }
147             break;
148         case OrderColumn.COLTYPE_STRING:
149         default:
150             comp0 = str0;
151             comp1 = str1;
152             break;
153         }
154 
155         // multiply by the sort indicator to get a ASC or DESC result
156         result = comp0.compareTo(comp1) * oc.getSortIndicator();
157         return result;
158     }
159 
160     private Date getBadDateDefault() {
161         final Calendar defaultBadDt = new GregorianCalendar();
162         defaultBadDt.set(Calendar.MONTH, 1);
163         defaultBadDt.set(Calendar.YEAR, 1900);
164         defaultBadDt.set(Calendar.DAY_OF_MONTH, 1);
165         return defaultBadDt.getTime();
166     }
167 
168     /**
169      * @param metaData the metaData to set
170      */
171     public void setMetaData(final MetaData metaData) {
172         this.metaData = metaData;
173     }
174 
175     /**
176      * @param parser the parser to set
177      */
178     public void setParser(final Parser parser) {
179         this.parser = parser;
180     }
181 
182 }