View Javadoc

1   /*
2    * ModeShape (http://www.modeshape.org)
3    * See the COPYRIGHT.txt file distributed with this work for information
4    * regarding copyright ownership.  Some portions may be licensed
5    * to Red Hat, Inc. under one or more contributor license agreements.
6    * See the AUTHORS.txt file in the distribution for a full listing of 
7    * individual contributors.
8    *
9    * ModeShape is free software. Unless otherwise indicated, all code in ModeShape
10   * is licensed to you under the terms of the GNU Lesser General Public License as
11   * published by the Free Software Foundation; either version 2.1 of
12   * the License, or (at your option) any later version.
13   * 
14   * ModeShape is distributed in the hope that it will be useful,
15   * but WITHOUT ANY WARRANTY; without even the implied warranty of
16   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17   * Lesser General Public License for more details.
18   *
19   * You should have received a copy of the GNU Lesser General Public
20   * License along with this software; if not, write to the Free
21   * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
22   * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
23   */
24  package org.modeshape.graph.query.process;
25  
26  import java.util.ArrayList;
27  import java.util.Collections;
28  import java.util.Comparator;
29  import java.util.List;
30  import org.modeshape.graph.query.QueryContext;
31  import org.modeshape.graph.query.QueryResults.Columns;
32  import org.modeshape.graph.query.model.Order;
33  import org.modeshape.graph.query.model.Ordering;
34  import org.modeshape.graph.query.model.TypeSystem;
35  import org.modeshape.graph.query.model.TypeSystem.TypeFactory;
36  import org.modeshape.graph.query.plan.PlanNode.Type;
37  
38  /**
39   * A {@link ProcessingComponent} implementation that performs a {@link Type#PROJECT PROJECT} operation to reduce the columns that
40   * appear in the results.
41   */
42  public class SortValuesComponent extends DelegatingComponent {
43  
44      private final Comparator<Object[]> sortingComparator;
45  
46      public SortValuesComponent( ProcessingComponent delegate,
47                                  List<Ordering> orderings ) {
48          super(delegate);
49          this.sortingComparator = createSortComparator(delegate.getContext(), delegate.getColumns(), orderings);
50      }
51  
52      /**
53       * @return sortingComparator
54       */
55      public Comparator<Object[]> getSortingComparator() {
56          return sortingComparator;
57      }
58  
59      /**
60       * {@inheritDoc}
61       * 
62       * @see org.modeshape.graph.query.process.ProcessingComponent#execute()
63       */
64      @Override
65      public List<Object[]> execute() {
66          List<Object[]> tuples = delegate().execute();
67          if (tuples.size() > 1 && sortingComparator != null) {
68              // Sort the tuples ...
69              Collections.sort(tuples, sortingComparator);
70          }
71          return tuples;
72      }
73  
74      protected Comparator<Object[]> createSortComparator( QueryContext context,
75                                                           Columns columns,
76                                                           List<Ordering> orderings ) {
77          assert context != null;
78          assert orderings != null;
79          if (orderings.isEmpty()) {
80              return null;
81          }
82          if (orderings.size() == 1) {
83              return createSortComparator(context, columns, orderings.get(0));
84          }
85          // Create a comparator that uses an ordered list of comparators ...
86          final List<Comparator<Object[]>> comparators = new ArrayList<Comparator<Object[]>>(orderings.size());
87          for (Ordering ordering : orderings) {
88              comparators.add(createSortComparator(context, columns, ordering));
89          }
90          return new Comparator<Object[]>() {
91              public int compare( Object[] tuple1,
92                                  Object[] tuple2 ) {
93                  for (Comparator<Object[]> comparator : comparators) {
94                      int result = comparator.compare(tuple1, tuple2);
95                      if (result != 0) return result;
96                  }
97                  return 0;
98              }
99          };
100 
101     }
102 
103     @SuppressWarnings( "unchecked" )
104     protected Comparator<Object[]> createSortComparator( QueryContext context,
105                                                          Columns columns,
106                                                          Ordering ordering ) {
107         assert context != null;
108         assert ordering != null;
109         final DynamicOperation operation = createDynamicOperation(context.getTypeSystem(),
110                                                                   context.getSchemata(),
111                                                                   columns,
112                                                                   ordering.getOperand());
113         final TypeSystem typeSystem = context.getTypeSystem();
114         final TypeFactory<?> typeFactory = typeSystem.getTypeFactory(operation.getExpectedType());
115         assert typeFactory != null;
116         final Comparator<Object> typeComparator = (Comparator<Object>)typeFactory.getComparator();
117         assert typeComparator != null;
118         if (ordering.getOrder() == Order.DESCENDING) {
119             return new Comparator<Object[]>() {
120                 public int compare( Object[] tuple1,
121                                     Object[] tuple2 ) {
122                     Object value1 = typeFactory.create(operation.evaluate(tuple1));
123                     Object value2 = typeFactory.create(operation.evaluate(tuple2));
124                     return 0 - typeComparator.compare(value1, value2);
125                 }
126             };
127         }
128         return new Comparator<Object[]>() {
129             public int compare( Object[] tuple1,
130                                 Object[] tuple2 ) {
131                 Object value1 = typeFactory.create(operation.evaluate(tuple1));
132                 Object value2 = typeFactory.create(operation.evaluate(tuple2));
133                 return typeComparator.compare(value1, value2);
134             }
135         };
136     }
137 }