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.jcr.query;
25
26 import java.util.HashMap;
27 import java.util.Map;
28 import java.util.Set;
29 import javax.jcr.RepositoryException;
30 import javax.jcr.Value;
31 import javax.jcr.query.Query;
32 import javax.jcr.query.QueryResult;
33 import net.jcip.annotations.NotThreadSafe;
34 import org.modeshape.common.util.CheckArg;
35 import org.modeshape.common.util.StringUtil;
36 import org.modeshape.graph.property.Path;
37 import org.modeshape.graph.query.QueryResults;
38 import org.modeshape.graph.query.model.QueryCommand;
39 import org.modeshape.graph.query.parse.QueryParser;
40 import org.modeshape.graph.query.plan.PlanHints;
41 import org.modeshape.graph.query.validate.Schemata;
42 import org.modeshape.jcr.query.qom.JcrAbstractQuery;
43 import org.modeshape.jcr.query.qom.JcrLiteral;
44
45 /**
46 * Implementation of {@link Query} that represents a {@link QueryCommand query command}.
47 */
48 @NotThreadSafe
49 public class JcrQuery extends JcrAbstractQuery {
50
51 private QueryCommand query;
52 private final PlanHints hints;
53 private final Map<String, Object> variables;
54
55 /**
56 * Creates a new JCR {@link Query} by specifying the query statement itself, the language in which the query is stated, the
57 * {@link QueryCommand} representation and, optionally, the node from which the query was loaded. The language must be a
58 * string from among those returned by {@code QueryManager#getSupportedQueryLanguages()}.
59 *
60 * @param context the context that was used to create this query and that will be used to execute this query; may not be null
61 * @param statement the original statement as supplied by the client; may not be null
62 * @param language the language obtained from the {@link QueryParser}; may not be null
63 * @param query the parsed query representation; may not be null
64 * @param hints any hints that are to be used; may be null if there are no hints
65 * @param storedAtPath the path at which this query was stored, or null if this is not a stored query
66 */
67 public JcrQuery( JcrQueryContext context,
68 String statement,
69 String language,
70 QueryCommand query,
71 PlanHints hints,
72 Path storedAtPath ) {
73 super(context, statement, language, storedAtPath);
74 assert query != null;
75 this.query = query;
76 this.hints = hints;
77 this.variables = new HashMap<String, Object>();
78 }
79
80 protected QueryCommand query() {
81 return query;
82 }
83
84 /**
85 * Get the underlying and immutable Abstract Query Model representation of this query.
86 *
87 * @return the AQM representation; never null
88 */
89 public QueryCommand getAbstractQueryModel() {
90 return query;
91 }
92
93 /**
94 * {@inheritDoc}
95 *
96 * @see javax.jcr.query.Query#execute()
97 */
98 @SuppressWarnings( "deprecation" )
99 public QueryResult execute() throws RepositoryException {
100 context.isLive();
101 // Submit immediately to the workspace graph ...
102 Schemata schemata = context.getSchemata();
103 QueryResults result = context.execute(query, hints, variables);
104 checkForProblems(result.getProblems());
105 if (Query.XPATH.equals(language)) {
106 return new XPathQueryResult(context, statement, result, schemata);
107 } else if (Query.SQL.equals(language)) {
108 return new JcrSqlQueryResult(context, statement, result, schemata);
109 }
110 return new JcrQueryResult(context, statement, result, schemata);
111 }
112
113 /**
114 * {@inheritDoc}
115 *
116 * @see java.lang.Object#toString()
117 */
118 @Override
119 public String toString() {
120 return language + " -> " + statement + "\n" + StringUtil.createString(' ', Math.min(language.length() - 3, 0))
121 + "AQM -> " + query;
122 }
123
124 /**
125 * {@inheritDoc}
126 *
127 * @see javax.jcr.query.Query#bindValue(java.lang.String, javax.jcr.Value)
128 */
129 @Override
130 public void bindValue( String varName,
131 Value value ) throws IllegalArgumentException, RepositoryException {
132 CheckArg.isNotNull(varName, "varName");
133 CheckArg.isNotNull(value, "value");
134 variables.put(varName, JcrLiteral.rawValue(value));
135 }
136
137 /**
138 * {@inheritDoc}
139 *
140 * @see javax.jcr.query.Query#getBindVariableNames()
141 */
142 @Override
143 public String[] getBindVariableNames() {
144 Set<String> keys = variables.keySet();
145 return keys.toArray(new String[keys.size()]);
146 }
147
148 /**
149 * {@inheritDoc}
150 *
151 * @see javax.jcr.query.Query#setLimit(long)
152 */
153 @Override
154 public void setLimit( long limit ) {
155 if (limit > Integer.MAX_VALUE) limit = Integer.MAX_VALUE;
156 query = query.withLimit((int)limit); // may not actually change if the limit matches the existing query
157 }
158
159 /**
160 * {@inheritDoc}
161 *
162 * @see javax.jcr.query.Query#setOffset(long)
163 */
164 @Override
165 public void setOffset( long offset ) {
166 if (offset > Integer.MAX_VALUE) offset = Integer.MAX_VALUE;
167 query = query.withOffset((int)offset); // may not actually change if the offset matches the existing query
168 }
169 }