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.Comparator;
27  import java.util.Iterator;
28  import java.util.LinkedList;
29  import java.util.List;
30  import org.modeshape.graph.query.QueryContext;
31  import org.modeshape.graph.query.QueryResults.Columns;
32  
33  /**
34   */
35  public abstract class SetOperationComponent extends ProcessingComponent {
36  
37      private final Iterable<ProcessingComponent> sources;
38      protected final Comparator<Object[]> removeDuplicatesComparator;
39  
40      protected SetOperationComponent( QueryContext context,
41                                       Columns columns,
42                                       Iterable<ProcessingComponent> sources,
43                                       boolean alreadySorted,
44                                       boolean all ) {
45          super(context, columns);
46          assert unionCompatible(columns, sources);
47          this.sources = wrapWithLocationOrdering(sources, alreadySorted);
48          this.removeDuplicatesComparator = all ? null : createSortComparator(context, columns);
49      }
50  
51      protected static boolean unionCompatible( Columns columns,
52                                                Iterable<ProcessingComponent> sources ) {
53          for (ProcessingComponent source : sources) {
54              if (!columns.isUnionCompatible(source.getColumns())) return false;
55          }
56          return true;
57      }
58  
59      /**
60       * @return sources
61       */
62      protected Iterable<ProcessingComponent> sources() {
63          return sources;
64      }
65  
66      /**
67       * The sources' results must be sorted before the intersection can be computed. Ensure that the sources' results are indeed
68       * sorted, and if not wrap them in a sorting component.
69       * 
70       * @param sources the sources being intersected; may not be null
71       * @param alreadySorted true if the sources' results are already sorted, or false if they must be sorted by this component
72       * @return the sources (or their wrappers); never null
73       */
74      protected static Iterable<ProcessingComponent> wrapWithLocationOrdering( Iterable<ProcessingComponent> sources,
75                                                                               boolean alreadySorted ) {
76          assert sources != null;
77          if (alreadySorted) return sources;
78          List<ProcessingComponent> wrapped = new LinkedList<ProcessingComponent>();
79          for (ProcessingComponent source : sources) {
80              wrapped.add(new SortLocationsComponent(source));
81          }
82          return wrapped;
83      }
84  
85      protected void removeDuplicatesIfRequested( List<Object[]> tuples ) {
86          if (removeDuplicatesComparator != null) {
87              Iterator<Object[]> iter = tuples.iterator();
88              Object[] previous = null;
89              while (iter.hasNext()) {
90                  Object[] current = iter.next();
91                  if (previous != null && removeDuplicatesComparator.compare(previous, current) == 0) {
92                      iter.remove();
93                  } else {
94                      previous = current;
95                  }
96              }
97          }
98      }
99  }