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 }