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 }