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.request;
25  
26  import java.util.Collections;
27  import java.util.List;
28  import java.util.Map;
29  import org.modeshape.common.util.CheckArg;
30  import org.modeshape.common.util.HashCode;
31  import org.modeshape.graph.query.QueryResults.Columns;
32  import org.modeshape.graph.query.QueryResults.Statistics;
33  import org.modeshape.graph.query.model.Column;
34  import org.modeshape.graph.query.model.Constraint;
35  import org.modeshape.graph.query.model.Limit;
36  import org.modeshape.graph.query.model.SelectorName;
37  import org.modeshape.graph.query.model.Visitors;
38  import org.modeshape.graph.query.validate.Schemata;
39  
40  /**
41   * A {@link Request} to issue an access query a graph, where an access query is a low-level atomic query that is part of a large,
42   * planned query.
43   */
44  public class AccessQueryRequest extends SearchRequest {
45  
46      private static final Map<String, Object> EMPTY_VARIABLES = Collections.emptyMap();
47  
48      private static final long serialVersionUID = 1L;
49  
50      private final String workspaceName;
51      private final SelectorName tableName;
52      private final List<Constraint> andedConstraints;
53      private final Limit limit;
54      private final Map<String, Object> variables;
55      private final Schemata schemata;
56      private final int hc;
57  
58      /**
59       * Create a new request to execute the supplied query against the name workspace.
60       * 
61       * @param workspace the name of the workspace to be queried
62       * @param tableName the name of the selector (or table) being queried
63       * @param resultColumns the specification of the expected columns in the result tuples
64       * @param andedConstraints the list of AND-ed constraints; may be empty or null if there are no constraints
65       * @param limit the limit on the results; may be null if there is no limit
66       * @param schemata the schemata that defines the table and columns being queried; may not be null
67       * @param variables the variables that are available to be substituted upon execution; may be null if there are no variables
68       * @throws IllegalArgumentException if the query or workspace name is null
69       */
70      public AccessQueryRequest( String workspace,
71                                 SelectorName tableName,
72                                 Columns resultColumns,
73                                 List<Constraint> andedConstraints,
74                                 Limit limit,
75                                 Schemata schemata,
76                                 Map<String, Object> variables ) {
77          CheckArg.isNotNull(workspace, "workspace");
78          CheckArg.isNotNull(tableName, "tableName");
79          CheckArg.isNotNull(resultColumns, "resultColumns");
80          this.workspaceName = workspace;
81          this.tableName = tableName;
82          this.andedConstraints = andedConstraints != null ? andedConstraints : Collections.<Constraint>emptyList();
83          this.variables = variables != null ? variables : EMPTY_VARIABLES;
84          this.limit = limit != null ? limit : Limit.NONE;
85          this.schemata = schemata;
86          this.doSetResults(resultColumns, null, null);
87          this.hc = HashCode.compute(workspaceName, tableName, resultColumns);
88      }
89  
90      /**
91       * Get the name of the workspace in which the node exists.
92       * 
93       * @return the name of the workspace; never null
94       */
95      public String workspace() {
96          return workspaceName;
97      }
98  
99      /**
100      * Get the name of the selector (or table) that is being queried.
101      * 
102      * @return the selector name; never null
103      */
104     public SelectorName selectorName() {
105         return tableName;
106     }
107 
108     /**
109      * Get the specification of the columns for the {@link #getTuples() results}.
110      * 
111      * @return the column specifications; never null
112      */
113     public Columns resultColumns() {
114         return super.columns();
115     }
116 
117     /**
118      * Get the immutable list of constraints that are AND-ed together in this query. Every {@link #getTuples() tuple in the
119      * results} must satisfy <i>all</i> of these constraints.
120      * 
121      * @return the AND-ed constraints; never null but possibly empty if there are no constraints
122      */
123     public List<Constraint> andedConstraints() {
124         return andedConstraints;
125     }
126 
127     /**
128      * The variables that are available to be substituted upon execution.
129      * 
130      * @return the variables; never null but possibly empty
131      */
132     public Map<String, Object> variables() {
133         return variables;
134     }
135 
136     /**
137      * Get the schemata that defines the table structure and columns definitions available to this query.
138      * 
139      * @return the schemata; never null
140      */
141     public Schemata schemata() {
142         return schemata;
143     }
144 
145     /**
146      * Get the limit of the result tuples, which can specify a {@link Limit#getRowLimit() maximum number of rows} as well as an
147      * {@link Limit#getOffset() initial offset} for the first row.
148      * 
149      * @return the limit; never null but may be {@link Limit#isUnlimited() unlimited} if there is no effective limit
150      */
151     public Limit limit() {
152         return limit;
153     }
154 
155     /**
156      * Set the results for this request.
157      * 
158      * @param tuples the result values
159      * @param statistics the statistics, or null if there are none
160      */
161     public void setResults( List<Object[]> tuples,
162                             Statistics statistics ) {
163         super.doSetResults(columns(), tuples, statistics);
164     }
165 
166     /**
167      * {@inheritDoc}
168      * 
169      * @see java.lang.Object#hashCode()
170      */
171     @Override
172     public int hashCode() {
173         return hc;
174     }
175 
176     /**
177      * {@inheritDoc}
178      * 
179      * @see java.lang.Object#equals(java.lang.Object)
180      */
181     @Override
182     public boolean equals( Object obj ) {
183         if (obj == this) return true;
184         if (this.getClass().isInstance(obj)) {
185             AccessQueryRequest that = (AccessQueryRequest)obj;
186             if (this.hashCode() != that.hashCode()) return false;
187             if (!this.workspace().equals(that.workspace())) return false;
188             if (!this.selectorName().equals(that.selectorName())) return false;
189             if (!this.limit().equals(that.limit())) return false;
190             if (!this.andedConstraints().equals(that.andedConstraints())) return false;
191             if (!this.resultColumns().equals(that.resultColumns())) return false;
192             if (!this.variables().equals(that.variables())) return false;
193             return true;
194         }
195         return false;
196     }
197 
198     /**
199      * {@inheritDoc}
200      * 
201      * @see java.lang.Object#toString()
202      */
203     @Override
204     public String toString() {
205         StringBuilder sb = new StringBuilder("query the \"");
206         sb.append(workspaceName).append("\" workspace: SELECT ");
207         boolean first = true;
208         for (Column column : resultColumns().getColumns()) {
209             if (first) first = false;
210             else sb.append(", ");
211             sb.append(column);
212         }
213         sb.append(" FROM ").append(selectorName().getName());
214         if (!andedConstraints.isEmpty()) {
215             sb.append(" WHERE ");
216             first = true;
217             for (Constraint constraint : andedConstraints) {
218                 if (first) first = false;
219                 else sb.append(" AND ");
220                 sb.append(Visitors.readable(constraint));
221             }
222         }
223         if (!limit.isUnlimited()) {
224             sb.append(Visitors.readable(limit));
225         }
226         if (!variables.isEmpty()) {
227             sb.append(" USING <");
228             first = true;
229             for (Map.Entry<String, Object> entry : variables.entrySet()) {
230                 if (first) first = false;
231                 else sb.append(", ");
232                 sb.append(entry.getKey()).append('=');
233                 Object value = entry.getValue();
234                 if (value instanceof String) {
235                     sb.append('"').append(value).append('"');
236                 } else {
237                     sb.append(value);
238                 }
239             }
240             sb.append('>');
241         }
242         return sb.toString();
243     }
244 }