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.List;
28  import org.modeshape.graph.query.QueryContext;
29  import org.modeshape.graph.query.QueryResults.Columns;
30  import org.modeshape.graph.query.plan.PlanNode.Type;
31  
32  /**
33   * A {@link ProcessingComponent} that executes a {@link Type#DEPENDENT_QUERY dependent query} node by first executing the left
34   * component and then executing the right component. If a variable name is specified, this component will save the query results
35   * from the the corresponding component into the {@link QueryContext#getVariables() variables} in the {@link QueryContext}.
36   */
37  public class DependentQueryComponent extends ProcessingComponent {
38  
39      private final ProcessingComponent left;
40      private final ProcessingComponent right;
41      private final String leftVariableName;
42      private final String rightVariableName;
43  
44      public DependentQueryComponent( QueryContext context,
45                                      ProcessingComponent left,
46                                      ProcessingComponent right,
47                                      String leftVariableName,
48                                      String rightVariableName ) {
49          super(context, right.getColumns());
50          this.left = left;
51          this.right = right;
52          this.leftVariableName = leftVariableName;
53          this.rightVariableName = rightVariableName;
54      }
55  
56      /**
57       * Get the processing component that serves as the left side of the join.
58       * 
59       * @return the left-side processing component; never null
60       */
61      protected final ProcessingComponent left() {
62          return left;
63      }
64  
65      /**
66       * Get the processing component that serves as the right side of the join.
67       * 
68       * @return the right-side processing component; never null
69       */
70      protected final ProcessingComponent right() {
71          return right;
72      }
73  
74      /**
75       * Get the columns definition for the results from the left, independent query that is processed first.
76       * 
77       * @return the left-side columns; never null
78       */
79      protected final Columns colunnsOfIndependentQuery() {
80          return left.getColumns();
81      }
82  
83      /**
84       * Get the columns definition for the results from the right component that is dependent upon the left.
85       * 
86       * @return the right-side columns; never null
87       */
88      protected final Columns colunnsOfDependentQuery() {
89          return right.getColumns();
90      }
91  
92      /**
93       * {@inheritDoc}
94       * 
95       * @see org.modeshape.graph.query.process.ProcessingComponent#execute()
96       */
97      @Override
98      public List<Object[]> execute() {
99          // First execute the left side ...
100         List<Object[]> leftResults = left.execute();
101         if (left.getColumns().getColumnCount() > 0) {
102             saveResultsToVariable(leftResults, leftVariableName);
103         }
104 
105         // Then execute the right side ...
106         List<Object[]> rightResults = right.execute();
107         if (right.getColumns().getColumnCount() > 0) {
108             saveResultsToVariable(rightResults, rightVariableName);
109         }
110         return rightResults;
111     }
112 
113     protected void saveResultsToVariable( List<Object[]> results,
114                                           String variableName ) {
115         if (results == null || results.isEmpty()) return;
116         if (variableName == null) return;
117 
118         // Grab the first value in each of the tuples, and set on the query context ...
119         List<Object> singleColumnResults = new ArrayList<Object>(results.size());
120         // Make sure there is at least one column (in the first record; remaining tuples should be the same) ...
121         Object[] firstTuple = results.get(0);
122         if (firstTuple.length != 0) {
123             for (Object[] tuple : results) {
124                 singleColumnResults.add(tuple[0]);
125             }
126         }
127         // Place the single column results into the variable ...
128         getContext().getVariables().put(variableName, singleColumnResults);
129     }
130 }