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.jcr;
25  
26  import java.math.BigDecimal;
27  import java.util.Comparator;
28  import java.util.Map;
29  import java.util.Set;
30  import javax.jcr.AccessDeniedException;
31  import javax.jcr.Node;
32  import javax.jcr.NodeIterator;
33  import javax.jcr.PropertyType;
34  import javax.jcr.RepositoryException;
35  import javax.jcr.Value;
36  import javax.jcr.ValueFactory;
37  import javax.jcr.query.InvalidQueryException;
38  import javax.jcr.query.Query;
39  import javax.jcr.query.QueryManager;
40  import javax.jcr.version.VersionException;
41  import net.jcip.annotations.Immutable;
42  import org.modeshape.common.text.ParsingException;
43  import org.modeshape.common.util.CheckArg;
44  import org.modeshape.graph.ExecutionContext;
45  import org.modeshape.graph.Location;
46  import org.modeshape.graph.property.Name;
47  import org.modeshape.graph.property.NamespaceRegistry;
48  import org.modeshape.graph.property.Path;
49  import org.modeshape.graph.property.ValueFactories;
50  import org.modeshape.graph.query.QueryResults;
51  import org.modeshape.graph.query.model.QueryCommand;
52  import org.modeshape.graph.query.model.TypeSystem;
53  import org.modeshape.graph.query.model.Visitors;
54  import org.modeshape.graph.query.parse.QueryParser;
55  import org.modeshape.graph.query.plan.PlanHints;
56  import org.modeshape.graph.query.validate.Schemata;
57  import org.modeshape.jcr.JcrRepository.QueryLanguage;
58  import org.modeshape.jcr.api.query.qom.QueryObjectModelFactory;
59  import org.modeshape.jcr.query.JcrQuery;
60  import org.modeshape.jcr.query.JcrQueryContext;
61  import org.modeshape.jcr.query.JcrSearch;
62  import org.modeshape.jcr.query.JcrTypeSystem;
63  import org.modeshape.jcr.query.qom.JcrQueryObjectModel;
64  import org.modeshape.jcr.query.qom.JcrQueryObjectModelFactory;
65  import org.modeshape.jcr.query.qom.JcrSelectQuery;
66  import org.modeshape.jcr.query.qom.JcrSetQuery;
67  import org.modeshape.jcr.query.qom.JcrSetQueryObjectModel;
68  
69  /**
70   * Place-holder implementation of {@link QueryManager} interface.
71   */
72  @Immutable
73  class JcrQueryManager implements QueryManager {
74  
75      public static final int MAXIMUM_RESULTS_FOR_FULL_TEXT_SEARCH_QUERIES = Integer.MAX_VALUE;
76  
77      private final JcrSession session;
78      private final JcrQueryContext context;
79      private final JcrTypeSystem typeSystem;
80      private final QueryObjectModelFactory factory;
81  
82      JcrQueryManager( JcrSession session ) {
83          this.session = session;
84          this.context = new SessionQueryContext(this.session);
85          this.typeSystem = new SessionTypeSystem(this.session);
86          this.factory = new JcrQueryObjectModelFactory(this.context);
87      }
88  
89      /**
90       * {@inheritDoc}
91       * 
92       * @see javax.jcr.query.QueryManager#getQOMFactory()
93       */
94      @Override
95      public javax.jcr.query.qom.QueryObjectModelFactory getQOMFactory() {
96          return factory;
97      }
98  
99      /**
100      * {@inheritDoc}
101      * 
102      * @see javax.jcr.query.QueryManager#createQuery(java.lang.String, java.lang.String)
103      */
104     public Query createQuery( String statement,
105                               String language ) throws InvalidQueryException, RepositoryException {
106         CheckArg.isNotNull(statement, "statement");
107         CheckArg.isNotNull(language, "language");
108         return createQuery(statement, language, null);
109     }
110 
111     /**
112      * Creates a new JCR {@link Query} by specifying the query expression itself, the language in which the query is stated, the
113      * {@link QueryCommand} representation and, optionally, the node from which the query was loaded. The language must be a
114      * string from among those returned by {@code QueryManager#getSupportedQueryLanguages()}.
115      * 
116      * @param expression the original query expression as supplied by the client; may not be null
117      * @param language the language in which the expression is represented; may not be null
118      * @param storedAtPath the path at which this query was stored, or null if this is not a stored query
119      * @return query the JCR query object; never null
120      * @throws InvalidQueryException if expression is invalid or language is unsupported
121      * @throws RepositoryException if the session is no longer live
122      */
123     @SuppressWarnings( "deprecation" )
124     public Query createQuery( String expression,
125                               String language,
126                               Path storedAtPath ) throws InvalidQueryException, RepositoryException {
127         session.checkLive();
128         // Look for a parser for the specified language ...
129         QueryParser parser = session.repository().queryParsers().getParserFor(language);
130         if (parser == null) {
131             Set<String> languages = session.repository().queryParsers().getLanguages();
132             throw new InvalidQueryException(JcrI18n.invalidQueryLanguage.text(language, languages));
133         }
134         if (parser.getLanguage().equals(FullTextSearchParser.LANGUAGE)) {
135             // This is a full-text search ...
136             return new JcrSearch(this.context, expression, parser.getLanguage(), storedAtPath);
137         }
138         try {
139             // Parsing must be done now ...
140             QueryCommand command = parser.parseQuery(expression, typeSystem);
141             if (command == null) {
142                 // The query is not well-formed and cannot be parsed ...
143                 throw new InvalidQueryException(JcrI18n.queryCannotBeParsedUsingLanguage.text(language, expression));
144             }
145             PlanHints hints = new PlanHints();
146             hints.showPlan = true;
147             if (Query.SQL.equals(language)) {
148                 hints.hasFullTextSearch = true; // requires 'jcr:score' to exist
149             }
150             if (Query.XPATH.equals(language)) {
151                 hints.hasFullTextSearch = true; // requires 'jcr:score' to exist
152                 hints.validateColumnExistance = false;
153             }
154             return resultWith(expression, parser.getLanguage(), command, hints, storedAtPath);
155         } catch (ParsingException e) {
156             // The query is not well-formed and cannot be parsed ...
157             String reason = e.getMessage();
158             throw new InvalidQueryException(JcrI18n.queryCannotBeParsedUsingLanguage.text(language, expression, reason));
159         } catch (org.modeshape.graph.query.parse.InvalidQueryException e) {
160             // The query was parsed, but there is an error in the query
161             String reason = e.getMessage();
162             throw new InvalidQueryException(JcrI18n.queryInLanguageIsNotValid.text(language, expression, reason));
163         }
164     }
165 
166     /**
167      * Creates a new JCR {@link Query} by specifying the query expression itself, the language in which the query is stated, the
168      * {@link QueryCommand} representation. This method is more efficient than {@link #createQuery(String, String, Path)} if the
169      * QueryCommand is created directly.
170      * 
171      * @param command the query command; may not be null
172      * @return query the JCR query object; never null
173      * @throws InvalidQueryException if expression is invalid or language is unsupported
174      * @throws RepositoryException if the session is no longer live
175      */
176     public Query createQuery( QueryCommand command ) throws InvalidQueryException, RepositoryException {
177         session.checkLive();
178         if (command == null) {
179             // The query is not well-formed and cannot be parsed ...
180             throw new InvalidQueryException(JcrI18n.queryInLanguageIsNotValid.text(QueryLanguage.JCR_SQL2, command));
181         }
182         // Produce the expression string ...
183         String expression = Visitors.readable(command);
184         try {
185             // Parsing must be done now ...
186             PlanHints hints = new PlanHints();
187             hints.showPlan = true;
188             return resultWith(expression, QueryLanguage.JCR_SQL2, command, hints, null);
189         } catch (org.modeshape.graph.query.parse.InvalidQueryException e) {
190             // The query was parsed, but there is an error in the query
191             String reason = e.getMessage();
192             throw new InvalidQueryException(JcrI18n.queryInLanguageIsNotValid.text(QueryLanguage.JCR_SQL2, expression, reason));
193         }
194     }
195 
196     /**
197      * {@inheritDoc}
198      * 
199      * @see javax.jcr.query.QueryManager#getQuery(javax.jcr.Node)
200      */
201     public Query getQuery( Node node ) throws InvalidQueryException, RepositoryException {
202         AbstractJcrNode jcrNode = CheckArg.getInstanceOf(node, AbstractJcrNode.class, "node");
203 
204         // Check the type of the node ...
205         JcrNodeType nodeType = jcrNode.getPrimaryNodeType();
206         if (!nodeType.getInternalName().equals(JcrNtLexicon.QUERY)) {
207             NamespaceRegistry registry = session.getExecutionContext().getNamespaceRegistry();
208             throw new InvalidQueryException(JcrI18n.notStoredQuery.text(jcrNode.path().getString(registry)));
209         }
210 
211         // These are both mandatory properties for nodes of nt:query
212         String statement = jcrNode.getProperty(JcrLexicon.STATEMENT).getString();
213         String language = jcrNode.getProperty(JcrLexicon.LANGUAGE).getString();
214 
215         return createQuery(statement, language, jcrNode.path());
216     }
217 
218     /**
219      * {@inheritDoc}
220      * 
221      * @see javax.jcr.query.QueryManager#getSupportedQueryLanguages()
222      */
223     public String[] getSupportedQueryLanguages() {
224         // Make a defensive copy ...
225         Set<String> languages = session.repository().queryParsers().getLanguages();
226         return languages.toArray(new String[languages.size()]);
227     }
228 
229     protected Query resultWith( String expression,
230                                 String language,
231                                 QueryCommand command,
232                                 PlanHints hints,
233                                 Path storedAtPath ) {
234         if (command instanceof JcrSelectQuery) {
235             JcrSelectQuery query = (JcrSelectQuery)command;
236             return new JcrQueryObjectModel(context, expression, language, query, hints, storedAtPath);
237         }
238         if (command instanceof JcrSetQuery) {
239             JcrSetQuery query = (JcrSetQuery)command;
240             return new JcrSetQueryObjectModel(this.context, expression, language, query, hints, storedAtPath);
241         }
242         return new JcrQuery(context, expression, language, command, hints, storedAtPath);
243     }
244 
245     // protected void checkForProblems( Problems problems ) throws RepositoryException {
246     // if (problems.hasErrors()) {
247     // // Build a message with the problems ...
248     // StringBuilder msg = new StringBuilder();
249     // for (Problem problem : problems) {
250     // if (problem.getStatus() != Status.ERROR) continue;
251     // msg.append(problem.getMessageString()).append("\n");
252     // }
253     // throw new RepositoryException(msg.toString());
254     // }
255     // }
256     //
257     // @NotThreadSafe
258     // protected static abstract class AbstractQuery implements Query {
259     // protected final JcrSession session;
260     // protected final String language;
261     // protected final String statement;
262     // private Path storedAtPath;
263     //
264     // /**
265     // * Creates a new JCR {@link Query} by specifying the query statement itself, the language in which the query is stated,
266     // * the {@link QueryCommand} representation and, optionally, the node from which the query was loaded. The language must be
267     // * a string from among those returned by {@code QueryManager#getSupportedQueryLanguages()}.
268     // *
269     // * @param session the session that was used to create this query and that will be used to execute this query; may not be
270     // * null
271     // * @param statement the original statement as supplied by the client; may not be null
272     // * @param language the language obtained from the {@link QueryParser}; may not be null
273     // * @param storedAtPath the path at which this query was stored, or null if this is not a stored query
274     // */
275     // protected AbstractQuery( JcrSession session,
276     // String statement,
277     // String language,
278     // Path storedAtPath ) {
279     // assert session != null;
280     // assert statement != null;
281     // assert language != null;
282     // this.session = session;
283     // this.language = language;
284     // this.statement = statement;
285     // this.storedAtPath = storedAtPath;
286     // }
287     //
288     // protected final JcrSession session() {
289     // return this.session;
290     // }
291     //
292     // /**
293     // * {@inheritDoc}
294     // *
295     // * @see javax.jcr.query.Query#getLanguage()
296     // */
297     // public String getLanguage() {
298     // return language;
299     // }
300     //
301     // /**
302     // * {@inheritDoc}
303     // *
304     // * @see javax.jcr.query.Query#getStatement()
305     // */
306     // public String getStatement() {
307     // return statement;
308     // }
309     //
310     // /**
311     // * {@inheritDoc}
312     // *
313     // * @see javax.jcr.query.Query#getStoredQueryPath()
314     // */
315     // public String getStoredQueryPath() throws ItemNotFoundException {
316     // if (storedAtPath == null) {
317     // throw new ItemNotFoundException(JcrI18n.notStoredQuery.text());
318     // }
319     // return storedAtPath.getString(session.getExecutionContext().getNamespaceRegistry());
320     // }
321     //
322     // /**
323     // * {@inheritDoc}
324     // *
325     // * @see javax.jcr.query.Query#storeAsNode(java.lang.String)
326     // */
327     // public Node storeAsNode( String absPath ) throws PathNotFoundException, ConstraintViolationException, RepositoryException {
328     // session.checkLive();
329     // NamespaceRegistry namespaces = this.session.namespaces();
330     //
331     // Path path;
332     // try {
333     // path = session.getExecutionContext().getValueFactories().getPathFactory().create(absPath);
334     // } catch (IllegalArgumentException iae) {
335     // throw new RepositoryException(JcrI18n.invalidPathParameter.text("absPath", absPath));
336     // }
337     // Path parentPath = path.getParent();
338     //
339     // Node parentNode = session.getNode(parentPath);
340     //
341     // if (!parentNode.isCheckedOut()) {
342     // throw new VersionException(JcrI18n.nodeIsCheckedIn.text(parentNode.getPath()));
343     // }
344     //
345     // Node queryNode = parentNode.addNode(path.relativeTo(parentPath).getString(namespaces),
346     // JcrNtLexicon.QUERY.getString(namespaces));
347     //
348     // queryNode.setProperty(JcrLexicon.LANGUAGE.getString(namespaces), this.language);
349     // queryNode.setProperty(JcrLexicon.STATEMENT.getString(namespaces), this.statement);
350     //
351     // this.storedAtPath = path;
352     //
353     // return queryNode;
354     // }
355     //
356     // protected void checkForProblems( Problems problems ) throws RepositoryException {
357     // if (problems.hasErrors()) {
358     // // Build a message with the problems ...
359     // StringBuilder msg = new StringBuilder();
360     // for (Problem problem : problems) {
361     // if (problem.getStatus() != Status.ERROR) continue;
362     // msg.append(problem.getMessageString()).append("\n");
363     // }
364     // throw new RepositoryException(msg.toString());
365     // }
366     // }
367     // }
368     //
369     // /**
370     // * Implementation of {@link Query} that represents a {@link QueryCommand} query.
371     // */
372     // @NotThreadSafe
373     // protected static class JcrQuery extends AbstractQuery {
374     // private final QueryCommand query;
375     // private final PlanHints hints;
376     // private final Map<String, Object> variables;
377     //
378     // /**
379     // * Creates a new JCR {@link Query} by specifying the query statement itself, the language in which the query is stated,
380     // * the {@link QueryCommand} representation and, optionally, the node from which the query was loaded. The language must be
381     // * a string from among those returned by {@code QueryManager#getSupportedQueryLanguages()}.
382     // *
383     // * @param session the session that was used to create this query and that will be used to execute this query; may not be
384     // * null
385     // * @param statement the original statement as supplied by the client; may not be null
386     // * @param language the language obtained from the {@link QueryParser}; may not be null
387     // * @param query the parsed query representation; may not be null
388     // * @param hints any hints that are to be used; may be null if there are no hints
389     // * @param storedAtPath the path at which this query was stored, or null if this is not a stored query
390     // */
391     // protected JcrQuery( JcrSession session,
392     // String statement,
393     // String language,
394     // QueryCommand query,
395     // PlanHints hints,
396     // Path storedAtPath ) {
397     // super(session, statement, language, storedAtPath);
398     // assert query != null;
399     // this.query = query;
400     // this.hints = hints;
401     // this.variables = null;
402     // }
403     //
404     // /**
405     // * Get the underlying and immutable Abstract Query Model representation of this query.
406     // *
407     // * @return the AQM representation; never null
408     // */
409     // public QueryCommand getAbstractQueryModel() {
410     // return query;
411     // }
412     //
413     // /**
414     // * {@inheritDoc}
415     // *
416     // * @see javax.jcr.query.Query#execute()
417     // */
418     // public QueryResult execute() throws RepositoryException {
419     // session.checkLive();
420     // // Submit immediately to the workspace graph ...
421     // Schemata schemata = session.workspace().nodeTypeManager().schemata();
422     // QueryResults result = session.repository().queryManager().query(session.workspace().getName(),
423     // query,
424     // schemata,
425     // hints,
426     // variables);
427     // checkForProblems(result.getProblems());
428     // if (Query.XPATH.equals(language)) {
429     // return new XPathQueryResult(session, statement, result, schemata);
430     // } else if (Query.SQL.equals(language)) {
431     // return new JcrSqlQueryResult(session, statement, result, schemata);
432     // }
433     // return new JcrQueryResult(session, statement, result, schemata);
434     // }
435     //
436     // /**
437     // * {@inheritDoc}
438     // *
439     // * @see java.lang.Object#toString()
440     // */
441     // @Override
442     // public String toString() {
443     // return language + " -> " + statement + "\n" + StringUtil.createString(' ', Math.min(language.length() - 3, 0))
444     // + "AQM -> " + query;
445     // }
446     //
447     // @Override
448     // public void bindValue( String varName,
449     // Value value ) throws IllegalArgumentException, RepositoryException {
450     // throw new UnsupportedRepositoryOperationException();
451     // }
452     //
453     // @Override
454     // public String[] getBindVariableNames() throws RepositoryException {
455     // throw new UnsupportedRepositoryOperationException();
456     // }
457     //
458     // @Override
459     // public void setLimit( long limit ) {
460     // throw new IllegalStateException();
461     // }
462     //
463     // @Override
464     // public void setOffset( long offset ) {
465     // throw new IllegalStateException();
466     // }
467     // }
468     //
469     // @NotThreadSafe
470     // protected static class JcrSearch extends AbstractQuery {
471     //
472     // /**
473     // * Creates a new JCR {@link Query} by specifying the query statement itself, the language in which the query is stated,
474     // * the {@link QueryCommand} representation and, optionally, the node from which the query was loaded. The language must be
475     // * a string from among those returned by {@code QueryManager#getSupportedQueryLanguages()}.
476     // *
477     // * @param session the session that was used to create this query and that will be used to execute this query; may not be
478     // * null
479     // * @param statement the original statement as supplied by the client; may not be null
480     // * @param language the language obtained from the {@link QueryParser}; may not be null
481     // * @param storedAtPath the path at which this query was stored, or null if this is not a stored query
482     // */
483     // protected JcrSearch( JcrSession session,
484     // String statement,
485     // String language,
486     // Path storedAtPath ) {
487     // super(session, statement, language, storedAtPath);
488     // }
489     //
490     // /**
491     // * {@inheritDoc}
492     // *
493     // * @see javax.jcr.query.Query#execute()
494     // */
495     // public QueryResult execute() throws RepositoryException {
496     // // Submit immediately to the workspace graph ...
497     // Schemata schemata = session.workspace().nodeTypeManager().schemata();
498     // QueryResults result = session.repository().queryManager().search(session.workspace().getName(),
499     // statement,
500     // MAXIMUM_RESULTS_FOR_FULL_TEXT_SEARCH_QUERIES,
501     // 0);
502     // checkForProblems(result.getProblems());
503     // return new JcrQueryResult(session, statement, result, schemata);
504     // }
505     //
506     // /**
507     // * {@inheritDoc}
508     // *
509     // * @see java.lang.Object#toString()
510     // */
511     // @Override
512     // public String toString() {
513     // return language + " -> " + statement;
514     // }
515     //
516     // @Override
517     // public void bindValue( String varName,
518     // Value value ) throws IllegalArgumentException, RepositoryException {
519     // throw new UnsupportedRepositoryOperationException();
520     // }
521     //
522     // @Override
523     // public String[] getBindVariableNames() throws RepositoryException {
524     // throw new UnsupportedRepositoryOperationException();
525     // }
526     //
527     // @Override
528     // public void setLimit( long limit ) {
529     // throw new IllegalStateException();
530     // }
531     //
532     // @Override
533     // public void setOffset( long offset ) {
534     // throw new IllegalStateException();
535     // }
536     // }
537     //
538     // protected static final String JCR_SCORE_COLUMN_NAME = "jcr:score";
539     // protected static final String JCR_PATH_COLUMN_NAME = "jcr:path";
540     //
541     // /**
542     // * The results of a query. This is not thread-safe because it relies upon JcrSession, which is not thread-safe. Also,
543     // although
544     // * the results of a query never change, the objects returned by the iterators may vary if the session information changes.
545     // */
546     // @NotThreadSafe
547     // public static class JcrQueryResult implements QueryResult, org.modeshape.jcr.api.query.QueryResult {
548     // protected final JcrSession session;
549     // protected final QueryResults results;
550     // protected final Schemata schemata;
551     // protected final String queryStatement;
552     // private List<String> columnTypes;
553     // private List<String> columnTables;
554     //
555     // protected JcrQueryResult( JcrSession session,
556     // String query,
557     // QueryResults graphResults,
558     // Schemata schemata ) {
559     // this.session = session;
560     // this.results = graphResults;
561     // this.schemata = schemata;
562     // this.queryStatement = query;
563     // assert this.session != null;
564     // assert this.results != null;
565     // assert this.schemata != null;
566     // assert this.queryStatement != null;
567     // }
568     //
569     // protected QueryResults results() {
570     // return results;
571     // }
572     //
573     // public List<String> getColumnNameList() {
574     // return results.getColumns().getColumnNames();
575     // }
576     //
577     // /**
578     // * {@inheritDoc}
579     // *
580     // * @see javax.jcr.query.QueryResult#getColumnNames()
581     // */
582     // public String[] getColumnNames() /*throws RepositoryException*/{
583     // List<String> names = getColumnNameList();
584     // return names.toArray(new String[names.size()]); // make a defensive copy ...
585     // }
586     //
587     // /**
588     // * {@inheritDoc}
589     // *
590     // * @see org.modeshape.jcr.api.query.QueryResult#getColumnTypes()
591     // */
592     // @Override
593     // public String[] getColumnTypes() {
594     // if (columnTypes == null) {
595     // // Discover the types ...
596     // columnTypes = loadColumnTypes(results.getColumns());
597     // }
598     // return columnTypes.toArray(new String[columnTypes.size()]);
599     // }
600     //
601     // protected List<String> loadColumnTypes( Columns columns ) {
602     // List<String> types = new ArrayList<String>(columns.getColumnCount());
603     // for (Column column : columns) {
604     // String typeName = null;
605     // Table table = schemata.getTable(column.selectorName());
606     // if (table != null) {
607     // Schemata.Column typedColumn = table.getColumn(column.propertyName());
608     // typeName = typedColumn.getPropertyType();
609     // }
610     // if (typeName == null) {
611     // // Might be fabricated column, so just assume string ...
612     // typeName = PropertyType.nameFromValue(PropertyType.STRING);
613     // }
614     // types.add(typeName);
615     // }
616     //
617     // return types;
618     // }
619     //
620     // /**
621     // * {@inheritDoc}
622     // *
623     // * @see org.modeshape.jcr.api.query.QueryResult#getSelectorNames()
624     // */
625     // @Override
626     // public String[] getSelectorNames() {
627     // if (columnTables == null) {
628     // // Discover the types ...
629     // Columns columns = results.getColumns();
630     // List<String> tables = new ArrayList<String>(columns.getColumnCount());
631     // for (Column column : columns) {
632     // String tableName = "";
633     // Table table = schemata.getTable(column.selectorName());
634     // if (table != null) tableName = table.getName().name();
635     // tables.add(tableName);
636     // }
637     // columnTables = tables;
638     // }
639     // return columnTables.toArray(new String[columnTables.size()]);
640     // }
641     //
642     // /**
643     // * {@inheritDoc}
644     // *
645     // * @see javax.jcr.query.QueryResult#getNodes()
646     // */
647     // public NodeIterator getNodes() throws RepositoryException {
648     // // Find all of the nodes in the results. We have to do this pre-emptively, since this
649     // // is the only method to throw RepositoryException ...
650     // final int numRows = results.getRowCount();
651     // if (numRows == 0) return new JcrEmptyNodeIterator();
652     //
653     // final List<AbstractJcrNode> nodes = new ArrayList<AbstractJcrNode>(numRows);
654     // final String selectorName = results.getColumns().getSelectorNames().get(0);
655     // final int locationIndex = results.getColumns().getLocationIndex(selectorName);
656     // for (Object[] tuple : results.getTuples()) {
657     // Location location = (Location)tuple[locationIndex];
658     // if (!session.wasRemovedInSession(location)) {
659     // nodes.add(session.getNode(location.getPath()));
660     // }
661     // }
662     // return new QueryResultNodeIterator(nodes);
663     // }
664     //
665     // /**
666     // * {@inheritDoc}
667     // *
668     // * @see javax.jcr.query.QueryResult#getRows()
669     // */
670     // public RowIterator getRows() /*throws RepositoryException*/{
671     // // We can actually delay the loading of the nodes until the rows are accessed ...
672     // final int numRows = results.getRowCount();
673     // final List<Object[]> tuples = results.getTuples();
674     // if (results.getColumns().getLocationCount() == 1) {
675     // return new SingleSelectorQueryResultRowIterator(session, queryStatement, results, tuples.iterator(), numRows);
676     // }
677     // return new QueryResultRowIterator(session, queryStatement, results, tuples.iterator(), numRows);
678     // }
679     //
680     // /**
681     // * Get a description of the query plan, if requested.
682     // *
683     // * @return the query plan, or null if the plan was not requested
684     // */
685     // public String getPlan() {
686     // return results.getPlan();
687     // }
688     //
689     // /**
690     // * {@inheritDoc}
691     // *
692     // * @see java.lang.Object#toString()
693     // */
694     // @Override
695     // public String toString() {
696     // return results.toString();
697     // }
698     // }
699     //
700     // /**
701     // * The {@link NodeIterator} implementation returned by the {@link JcrQueryResult}.
702     // *
703     // * @see JcrQueryResult#getNodes()
704     // */
705     // @NotThreadSafe
706     // protected static class QueryResultNodeIterator implements NodeIterator {
707     // private final Iterator<? extends Node> nodes;
708     // private final int size;
709     // private long position = 0L;
710     //
711     // protected QueryResultNodeIterator( List<? extends Node> nodes ) {
712     // this.nodes = nodes.iterator();
713     // this.size = nodes.size();
714     // }
715     //
716     // /**
717     // * {@inheritDoc}
718     // *
719     // * @see javax.jcr.NodeIterator#nextNode()
720     // */
721     // public Node nextNode() {
722     // Node node = nodes.next();
723     // ++position;
724     // return node;
725     // }
726     //
727     // /**
728     // * {@inheritDoc}
729     // *
730     // * @see javax.jcr.RangeIterator#getPosition()
731     // */
732     // public long getPosition() {
733     // return position;
734     // }
735     //
736     // /**
737     // * {@inheritDoc}
738     // *
739     // * @see javax.jcr.RangeIterator#getSize()
740     // */
741     // public long getSize() {
742     // return size;
743     // }
744     //
745     // /**
746     // * {@inheritDoc}
747     // *
748     // * @see javax.jcr.RangeIterator#skip(long)
749     // */
750     // public void skip( long skipNum ) {
751     // for (long i = 0L; i != skipNum; ++i)
752     // nextNode();
753     // }
754     //
755     // /**
756     // * {@inheritDoc}
757     // *
758     // * @see java.util.Iterator#hasNext()
759     // */
760     // public boolean hasNext() {
761     // return nodes.hasNext();
762     // }
763     //
764     // /**
765     // * {@inheritDoc}
766     // *
767     // * @see java.util.Iterator#next()
768     // */
769     // public Object next() {
770     // return nextNode();
771     // }
772     //
773     // /**
774     // * {@inheritDoc}
775     // *
776     // * @see java.util.Iterator#remove()
777     // */
778     // public void remove() {
779     // throw new UnsupportedOperationException();
780     // }
781     // }
782     //
783     // /**
784     // * The {@link RowIterator} implementation returned by the {@link JcrQueryResult}.
785     // *
786     // * @see JcrQueryResult#getRows()
787     // */
788     // @NotThreadSafe
789     // protected static class QueryResultRowIterator implements RowIterator {
790     // protected final List<String> columnNames;
791     // private final Iterator<Object[]> tuples;
792     // private final Set<String> selectorNames;
793     // protected final JcrSession session;
794     // protected final Columns columns;
795     // protected final String query;
796     // private int[] locationIndexes;
797     // private long position = 0L;
798     // private long numRows;
799     // private Row nextRow;
800     //
801     // protected QueryResultRowIterator( JcrSession session,
802     // String query,
803     // QueryResults results,
804     // Iterator<Object[]> tuples,
805     // long numRows ) {
806     // this.tuples = tuples;
807     // this.query = query;
808     // this.columns = results.getColumns();
809     // this.columnNames = this.columns.getColumnNames();
810     // this.session = session;
811     // this.numRows = numRows;
812     // this.selectorNames = new HashSet<String>(columns.getSelectorNames());
813     // int i = 0;
814     // locationIndexes = new int[selectorNames.size()];
815     // for (String selectorName : selectorNames) {
816     // locationIndexes[i++] = columns.getLocationIndex(selectorName);
817     // }
818     // }
819     //
820     // public boolean hasSelector( String selectorName ) {
821     // return this.selectorNames.contains(selectorName);
822     // }
823     //
824     // /**
825     // * {@inheritDoc}
826     // *
827     // * @see javax.jcr.query.RowIterator#nextRow()
828     // */
829     // public Row nextRow() {
830     // if (nextRow == null) {
831     // // Didn't call 'hasNext()' ...
832     // if (!hasNext()) {
833     // throw new NoSuchElementException();
834     // }
835     // }
836     // assert nextRow != null;
837     // Row result = nextRow;
838     // nextRow = null;
839     // return result;
840     // }
841     //
842     // /**
843     // * {@inheritDoc}
844     // *
845     // * @see javax.jcr.RangeIterator#getPosition()
846     // */
847     // public long getPosition() {
848     // return position;
849     // }
850     //
851     // /**
852     // * {@inheritDoc}
853     // *
854     // * @see javax.jcr.RangeIterator#getSize()
855     // */
856     // public long getSize() {
857     // return numRows;
858     // }
859     //
860     // /**
861     // * {@inheritDoc}
862     // *
863     // * @see javax.jcr.RangeIterator#skip(long)
864     // */
865     // public void skip( long skipNum ) {
866     // for (long i = 0L; i != skipNum; ++i) {
867     // tuples.next();
868     // }
869     // position += skipNum;
870     // }
871     //
872     // /**
873     // * {@inheritDoc}
874     // *
875     // * @see java.util.Iterator#hasNext()
876     // */
877     // public boolean hasNext() {
878     // if (nextRow != null) {
879     // return true;
880     // }
881     // while (tuples.hasNext()) {
882     // final Object[] tuple = tuples.next();
883     // ++position;
884     // try {
885     // // Get the next row ...
886     // nextRow = getNextRow(tuple);
887     // if (nextRow != null) return true;
888     // } catch (RepositoryException e) {
889     // // The node could not be found in this session, so skip it ...
890     // }
891     // --numRows;
892     // }
893     // return false;
894     // }
895     //
896     // protected Row getNextRow( Object[] tuple ) throws RepositoryException {
897     // // Make sure that each node referenced by the tuple exists and is accessible ...
898     // Node[] nodes = new Node[locationIndexes.length];
899     // int index = 0;
900     // for (int locationIndex : locationIndexes) {
901     // Location location = (Location)tuple[locationIndex];
902     // if (session.wasRemovedInSession(location)) {
903     // // Skip this record because one of the nodes no longer exists ...
904     // return null;
905     // }
906     // try {
907     // nodes[index++] = session.getNode(location.getPath());
908     // } catch (AccessDeniedException e) {
909     // // No access to this node, so skip the record ...
910     // return null;
911     // }
912     // }
913     // return new MultiSelectorQueryResultRow(this, nodes, locationIndexes, tuple);
914     // }
915     //
916     // /**
917     // * {@inheritDoc}
918     // *
919     // * @see java.util.Iterator#next()
920     // */
921     // public Object next() {
922     // return nextRow();
923     // }
924     //
925     // /**
926     // * {@inheritDoc}
927     // *
928     // * @see java.util.Iterator#remove()
929     // */
930     // public void remove() {
931     // throw new UnsupportedOperationException();
932     // }
933     // }
934     //
935     // /**
936     // * The {@link RowIterator} implementation returned by the {@link JcrQueryResult}.
937     // *
938     // * @see JcrQueryResult#getRows()
939     // */
940     // @NotThreadSafe
941     // protected static class SingleSelectorQueryResultRowIterator extends QueryResultRowIterator {
942     // protected final int locationIndex;
943     // protected final int scoreIndex;
944     //
945     // protected SingleSelectorQueryResultRowIterator( JcrSession session,
946     // String query,
947     // QueryResults results,
948     // Iterator<Object[]> tuples,
949     // long numRows ) {
950     // super(session, query, results, tuples, numRows);
951     // String selectorName = columns.getSelectorNames().get(0);
952     // locationIndex = columns.getLocationIndex(selectorName);
953     // scoreIndex = columns.getFullTextSearchScoreIndexFor(selectorName);
954     // }
955     //
956     // /**
957     // * {@inheritDoc}
958     // *
959     // * @see org.modeshape.jcr.JcrQueryManager.QueryResultRowIterator#getNextRow(java.lang.Object[])
960     // */
961     // @Override
962     // protected Row getNextRow( Object[] tuple ) throws RepositoryException {
963     // Location location = (Location)tuple[locationIndex];
964     // if (!session.wasRemovedInSession(location)) {
965     // Node node = session.getNode(location.getPath());
966     // return createRow(node, tuple);
967     // }
968     // return null;
969     // }
970     //
971     // protected Row createRow( Node node,
972     // Object[] tuple ) {
973     // return new SingleSelectorQueryResultRow(this, node, tuple);
974     // }
975     // }
976     //
977     // protected static class SingleSelectorQueryResultRow implements Row, org.modeshape.jcr.api.query.Row {
978     // protected final SingleSelectorQueryResultRowIterator iterator;
979     // protected final Node node;
980     // protected final Object[] tuple;
981     // private Value[] values = null;
982     //
983     // protected SingleSelectorQueryResultRow( SingleSelectorQueryResultRowIterator iterator,
984     // Node node,
985     // Object[] tuple ) {
986     // this.iterator = iterator;
987     // this.node = node;
988     // this.tuple = tuple;
989     // assert this.iterator != null;
990     // assert this.node != null;
991     // assert this.tuple != null;
992     // }
993     //
994     // /**
995     // * {@inheritDoc}
996     // *
997     // * @see org.modeshape.jcr.api.query.Row#getNode(java.lang.String)
998     // */
999     // @Override
1000     // public Node getNode( String selectorName ) throws RepositoryException {
1001     // if (iterator.hasSelector(selectorName)) {
1002     // throw new RepositoryException(JcrI18n.selectorNotUsedInQuery.text(selectorName, iterator.query));
1003     // }
1004     // return node;
1005     // }
1006     //
1007     // /**
1008     // * {@inheritDoc}
1009     // *
1010     // * @see javax.jcr.query.Row#getValue(java.lang.String)
1011     // */
1012     // public Value getValue( String columnName ) throws ItemNotFoundException, RepositoryException {
1013     // return node.getProperty(columnName).getValue();
1014     // }
1015     //
1016     // /**
1017     // * {@inheritDoc}
1018     // *
1019     // * @see javax.jcr.query.Row#getValues()
1020     // */
1021     // public Value[] getValues() throws RepositoryException {
1022     // if (values == null) {
1023     // int i = 0;
1024     // values = new Value[iterator.columnNames.size()];
1025     // for (String columnName : iterator.columnNames) {
1026     // values[i++] = getValue(columnName);
1027     // }
1028     // }
1029     // return values;
1030     // }
1031     //
1032     // @Override
1033     // public Node getNode() throws RepositoryException {
1034     // throw new UnsupportedRepositoryOperationException();
1035     // }
1036     //
1037     // @Override
1038     // public String getPath() throws RepositoryException {
1039     // throw new UnsupportedRepositoryOperationException();
1040     // }
1041     //
1042     // @Override
1043     // public String getPath( String selectorName ) throws RepositoryException {
1044     // throw new UnsupportedRepositoryOperationException();
1045     // }
1046     //
1047     // @Override
1048     // public double getScore() throws RepositoryException {
1049     // throw new UnsupportedRepositoryOperationException();
1050     // }
1051     //
1052     // @Override
1053     // public double getScore( String selectorName ) throws RepositoryException {
1054     // throw new UnsupportedRepositoryOperationException();
1055     // }
1056     // }
1057     //
1058     // protected static class MultiSelectorQueryResultRow implements Row, org.modeshape.jcr.api.query.Row {
1059     // protected final QueryResultRowIterator iterator;
1060     // protected final Object[] tuple;
1061     // private Value[] values = null;
1062     // private Node[] nodes;
1063     // private int[] locationIndexes;
1064     //
1065     // protected MultiSelectorQueryResultRow( QueryResultRowIterator iterator,
1066     // Node[] nodes,
1067     // int[] locationIndexes,
1068     // Object[] tuple ) {
1069     // this.iterator = iterator;
1070     // this.tuple = tuple;
1071     // this.nodes = nodes;
1072     // this.locationIndexes = locationIndexes;
1073     // assert this.iterator != null;
1074     // assert this.tuple != null;
1075     // }
1076     //
1077     // /**
1078     // * {@inheritDoc}
1079     // *
1080     // * @see org.modeshape.jcr.api.query.Row#getNode(java.lang.String)
1081     // */
1082     // @Override
1083     // public Node getNode( String selectorName ) throws RepositoryException {
1084     // try {
1085     // int locationIndex = iterator.columns.getLocationIndex(selectorName);
1086     // for (int i = 0; i != this.locationIndexes.length; ++i) {
1087     // if (this.locationIndexes[i] == locationIndex) {
1088     // return nodes[i];
1089     // }
1090     // }
1091     // } catch (NoSuchElementException e) {
1092     // throw new RepositoryException(e.getLocalizedMessage(), e);
1093     // }
1094     // assert false;
1095     // return null;
1096     // }
1097     //
1098     // /**
1099     // * {@inheritDoc}
1100     // *
1101     // * @see javax.jcr.query.Row#getValue(java.lang.String)
1102     // */
1103     // public Value getValue( String columnName ) throws ItemNotFoundException, RepositoryException {
1104     // try {
1105     // int locationIndex = iterator.columns.getLocationIndexForColumn(columnName);
1106     // for (int i = 0; i != this.locationIndexes.length; ++i) {
1107     // if (this.locationIndexes[i] == locationIndex) {
1108     // Node node = nodes[i];
1109     // return node != null ? node.getProperty(columnName).getValue() : null;
1110     // }
1111     // }
1112     // } catch (NoSuchElementException e) {
1113     // throw new RepositoryException(e.getLocalizedMessage(), e);
1114     // }
1115     // assert false;
1116     // return null;
1117     // }
1118     //
1119     // /**
1120     // * {@inheritDoc}
1121     // *
1122     // * @see javax.jcr.query.Row#getValues()
1123     // */
1124     // public Value[] getValues() throws RepositoryException {
1125     // if (values == null) {
1126     // int i = 0;
1127     // values = new Value[iterator.columnNames.size()];
1128     // for (String columnName : iterator.columnNames) {
1129     // values[i++] = getValue(columnName);
1130     // }
1131     // }
1132     // return values;
1133     // }
1134     //
1135     // @Override
1136     // public Node getNode() throws RepositoryException {
1137     // throw new UnsupportedRepositoryOperationException();
1138     // }
1139     //
1140     // @Override
1141     // public String getPath() throws RepositoryException {
1142     // throw new UnsupportedRepositoryOperationException();
1143     // }
1144     //
1145     // @Override
1146     // public String getPath( String selectorName ) throws RepositoryException {
1147     // throw new UnsupportedRepositoryOperationException();
1148     // }
1149     //
1150     // @Override
1151     // public double getScore() throws RepositoryException {
1152     // throw new UnsupportedRepositoryOperationException();
1153     // }
1154     //
1155     // @Override
1156     // public double getScore( String selectorName ) throws RepositoryException {
1157     // throw new UnsupportedRepositoryOperationException();
1158     // }
1159     // }
1160     //
1161     // protected static class XPathQueryResult extends JcrQueryResult {
1162     // private final List<String> columnNames;
1163     //
1164     // protected XPathQueryResult( JcrSession session,
1165     // String query,
1166     // QueryResults graphResults,
1167     // Schemata schemata ) {
1168     // super(session, query, graphResults, schemata);
1169     // List<String> columnNames = new LinkedList<String>(graphResults.getColumns().getColumnNames());
1170     // if (graphResults.getColumns().hasFullTextSearchScores() && !columnNames.contains(JCR_SCORE_COLUMN_NAME)) {
1171     // columnNames.add(0, JCR_SCORE_COLUMN_NAME);
1172     // }
1173     // columnNames.add(0, JCR_PATH_COLUMN_NAME);
1174     // this.columnNames = Collections.unmodifiableList(columnNames);
1175     // }
1176     //
1177     // /**
1178     // * {@inheritDoc}
1179     // *
1180     // * @see org.modeshape.jcr.JcrQueryManager.JcrQueryResult#getColumnNameList()
1181     // */
1182     // @Override
1183     // public List<String> getColumnNameList() {
1184     // return columnNames;
1185     // }
1186     //
1187     // /**
1188     // * {@inheritDoc}
1189     // *
1190     // * @see org.modeshape.jcr.JcrQueryManager.JcrQueryResult#getRows()
1191     // */
1192     // @Override
1193     // public RowIterator getRows() {
1194     // final int numRows = results.getRowCount();
1195     // final List<Object[]> tuples = results.getTuples();
1196     // return new XPathQueryResultRowIterator(session, queryStatement, results, tuples.iterator(), numRows);
1197     // }
1198     // }
1199     //
1200     // protected static class XPathQueryResultRowIterator extends SingleSelectorQueryResultRowIterator {
1201     // private final ValueFactories factories;
1202     // private final SessionCache cache;
1203     //
1204     // protected XPathQueryResultRowIterator( JcrSession session,
1205     // String query,
1206     // QueryResults results,
1207     // Iterator<Object[]> tuples,
1208     // long numRows ) {
1209     // super(session, query, results, tuples, numRows);
1210     // factories = session.executionContext.getValueFactories();
1211     // cache = session.cache();
1212     // }
1213     //
1214     // @Override
1215     // protected Row createRow( Node node,
1216     // Object[] tuple ) {
1217     // return new XPathQueryResultRow(this, node, tuple);
1218     // }
1219     //
1220     // protected Value jcrPath( Path path ) {
1221     // return new JcrValue(factories, cache, PropertyType.PATH, path);
1222     // }
1223     //
1224     // protected Value jcrScore( Float score ) {
1225     // return new JcrValue(factories, cache, PropertyType.DOUBLE, score);
1226     // }
1227     // }
1228     //
1229     // protected static class XPathQueryResultRow extends SingleSelectorQueryResultRow {
1230     // protected XPathQueryResultRow( SingleSelectorQueryResultRowIterator iterator,
1231     // Node node,
1232     // Object[] tuple ) {
1233     // super(iterator, node, tuple);
1234     // }
1235     //
1236     // /**
1237     // * {@inheritDoc}
1238     // *
1239     // * @see javax.jcr.query.Row#getValue(java.lang.String)
1240     // */
1241     // @Override
1242     // public Value getValue( String columnName ) throws ItemNotFoundException, RepositoryException {
1243     // if (JCR_PATH_COLUMN_NAME.equals(columnName)) {
1244     // Location location = (Location)tuple[iterator.locationIndex];
1245     // return ((XPathQueryResultRowIterator)iterator).jcrPath(location.getPath());
1246     // }
1247     // if (JCR_SCORE_COLUMN_NAME.equals(columnName)) {
1248     // Float score = (Float)tuple[iterator.scoreIndex];
1249     // return ((XPathQueryResultRowIterator)iterator).jcrScore(score);
1250     // }
1251     // return super.getValue(columnName);
1252     // }
1253     // }
1254     //
1255     // protected static class JcrSqlQueryResult extends JcrQueryResult {
1256     //
1257     // private final List<String> columnNames;
1258     // private boolean addedScoreColumn;
1259     // private boolean addedPathColumn;
1260     //
1261     // protected JcrSqlQueryResult( JcrSession session,
1262     // String query,
1263     // QueryResults graphResults,
1264     // Schemata schemata ) {
1265     // super(session, query, graphResults, schemata);
1266     // List<String> columnNames = new LinkedList<String>(graphResults.getColumns().getColumnNames());
1267     // if (!columnNames.contains(JCR_SCORE_COLUMN_NAME)) {
1268     // columnNames.add(0, JCR_SCORE_COLUMN_NAME);
1269     // addedScoreColumn = true;
1270     // }
1271     // if (!columnNames.contains(JCR_PATH_COLUMN_NAME)) {
1272     // columnNames.add(0, JCR_PATH_COLUMN_NAME);
1273     // addedPathColumn = true;
1274     // }
1275     // this.columnNames = Collections.unmodifiableList(columnNames);
1276     // }
1277     //
1278     // /**
1279     // * {@inheritDoc}
1280     // *
1281     // * @see org.modeshape.jcr.JcrQueryManager.JcrQueryResult#getColumnNameList()
1282     // */
1283     // @Override
1284     // public List<String> getColumnNameList() {
1285     // return columnNames;
1286     // }
1287     //
1288     // @Override
1289     // protected List<String> loadColumnTypes( Columns columns ) {
1290     // List<String> types = new ArrayList<String>(columns.getColumnCount() + (addedScoreColumn ? 1 : 0)
1291     // + (addedPathColumn ? 1 : 0));
1292     // String stringtype = PropertyType.nameFromValue(PropertyType.STRING);
1293     // if (addedScoreColumn) types.add(0, stringtype);
1294     // if (addedPathColumn) types.add(0, stringtype);
1295     //
1296     // for (Column column : columns) {
1297     // String typeName = null;
1298     // Table table = schemata.getTable(column.selectorName());
1299     // if (table != null) {
1300     // Schemata.Column typedColumn = table.getColumn(column.propertyName());
1301     // typeName = typedColumn.getPropertyType();
1302     // }
1303     // if (typeName == null) {
1304     // // Might be fabricated column, so just assume string ...
1305     // typeName = stringtype;
1306     // }
1307     // types.add(typeName);
1308     // }
1309     //
1310     // return types;
1311     // }
1312     //
1313     // /**
1314     // * {@inheritDoc}
1315     // *
1316     // * @see org.modeshape.jcr.JcrQueryManager.JcrQueryResult#getRows()
1317     // */
1318     // @Override
1319     // public RowIterator getRows() {
1320     // final int numRows = results.getRowCount();
1321     // final List<Object[]> tuples = results.getTuples();
1322     // return new JcrSqlQueryResultRowIterator(session, queryStatement, results, tuples.iterator(), numRows);
1323     // }
1324     // }
1325     //
1326     // protected static class JcrSqlQueryResultRowIterator extends SingleSelectorQueryResultRowIterator {
1327     // private final ValueFactories factories;
1328     // private final SessionCache cache;
1329     //
1330     // protected JcrSqlQueryResultRowIterator( JcrSession session,
1331     // String query,
1332     // QueryResults results,
1333     // Iterator<Object[]> tuples,
1334     // long numRows ) {
1335     // super(session, query, results, tuples, numRows);
1336     // factories = session.executionContext.getValueFactories();
1337     // cache = session.cache();
1338     // }
1339     //
1340     // @Override
1341     // protected Row createRow( Node node,
1342     // Object[] tuple ) {
1343     // return new JcrSqlQueryResultRow(this, node, tuple);
1344     // }
1345     //
1346     // protected Value jcrPath( Path path ) {
1347     // return new JcrValue(factories, cache, PropertyType.PATH, path);
1348     // }
1349     //
1350     // protected Value jcrScore( Float score ) {
1351     // return new JcrValue(factories, cache, PropertyType.DOUBLE, score);
1352     // }
1353     // }
1354     //
1355     // protected static class JcrSqlQueryResultRow extends SingleSelectorQueryResultRow {
1356     // protected JcrSqlQueryResultRow( SingleSelectorQueryResultRowIterator iterator,
1357     // Node node,
1358     // Object[] tuple ) {
1359     // super(iterator, node, tuple);
1360     // }
1361     //
1362     // /**
1363     // * {@inheritDoc}
1364     // *
1365     // * @see javax.jcr.query.Row#getValue(java.lang.String)
1366     // */
1367     // @Override
1368     // public Value getValue( String columnName ) throws ItemNotFoundException, RepositoryException {
1369     // if (JCR_PATH_COLUMN_NAME.equals(columnName)) {
1370     // Location location = (Location)tuple[iterator.locationIndex];
1371     // return ((JcrSqlQueryResultRowIterator)iterator).jcrPath(location.getPath());
1372     // }
1373     // if (JCR_SCORE_COLUMN_NAME.equals(columnName)) {
1374     // Float score = (Float)tuple[iterator.scoreIndex];
1375     // return ((JcrSqlQueryResultRowIterator)iterator).jcrScore(score);
1376     // }
1377     // return super.getValue(columnName);
1378     // }
1379     // }
1380     //
1381     // @Override
1382     // public QueryObjectModelFactory getQOMFactory() {
1383     // throw new IllegalStateException();
1384     // }
1385 
1386     protected static class SessionQueryContext implements JcrQueryContext {
1387         private final JcrSession session;
1388         private final ValueFactories factories;
1389         private final SessionCache cache;
1390 
1391         protected SessionQueryContext( JcrSession session ) {
1392             this.session = session;
1393             this.factories = session.getExecutionContext().getValueFactories();
1394             this.cache = session.cache();
1395         }
1396 
1397         /**
1398          * {@inheritDoc}
1399          * 
1400          * @see org.modeshape.jcr.query.JcrQueryContext#createValue(int, java.lang.Object)
1401          */
1402         @Override
1403         public Value createValue( int propertyType,
1404                                   Object value ) {
1405             return new JcrValue(factories, cache, PropertyType.PATH, value);
1406         }
1407 
1408         /**
1409          * {@inheritDoc}
1410          * 
1411          * @see org.modeshape.jcr.query.JcrQueryContext#emptyNodeIterator()
1412          */
1413         @Override
1414         public NodeIterator emptyNodeIterator() {
1415             return new JcrEmptyNodeIterator();
1416         }
1417 
1418         /**
1419          * {@inheritDoc}
1420          * 
1421          * @see org.modeshape.jcr.query.JcrQueryContext#execute(org.modeshape.graph.query.model.QueryCommand,
1422          *      org.modeshape.graph.query.plan.PlanHints, java.util.Map)
1423          */
1424         @Override
1425         public QueryResults execute( QueryCommand query,
1426                                      PlanHints hints,
1427                                      Map<String, Object> variables ) throws RepositoryException {
1428             session.checkLive();
1429             // Submit immediately to the workspace graph ...
1430             Schemata schemata = session.workspace().nodeTypeManager().schemata();
1431             return session.repository().queryManager().query(session.workspace().getName(), query, schemata, hints, variables);
1432         }
1433 
1434         /**
1435          * {@inheritDoc}
1436          * 
1437          * @see org.modeshape.jcr.query.JcrQueryContext#getExecutionContext()
1438          */
1439         @Override
1440         public ExecutionContext getExecutionContext() {
1441             return session.getExecutionContext();
1442         }
1443 
1444         /**
1445          * {@inheritDoc}
1446          * 
1447          * @see org.modeshape.jcr.query.JcrQueryContext#getNode(Location)
1448          */
1449         @Override
1450         public Node getNode( Location location ) throws AccessDeniedException, RepositoryException {
1451             if (!session.wasRemovedInSession(location)) {
1452                 return session.getNode(location.getPath());
1453             }
1454             return null;
1455         }
1456 
1457         /**
1458          * {@inheritDoc}
1459          * 
1460          * @see org.modeshape.jcr.query.JcrQueryContext#getSchemata()
1461          */
1462         @Override
1463         public Schemata getSchemata() {
1464             return session.nodeTypeManager().schemata();
1465         }
1466 
1467         /**
1468          * {@inheritDoc}
1469          * 
1470          * @see org.modeshape.jcr.query.JcrQueryContext#isLive()
1471          */
1472         @Override
1473         public boolean isLive() {
1474             return session.isLive();
1475         }
1476 
1477         /**
1478          * {@inheritDoc}
1479          * 
1480          * @see org.modeshape.jcr.query.JcrQueryContext#search(java.lang.String, int, int)
1481          */
1482         @Override
1483         public QueryResults search( String searchExpression,
1484                                     int maxRowCount,
1485                                     int offset ) throws RepositoryException {
1486             return session.repository().queryManager().search(session.workspace().getName(),
1487                                                               searchExpression,
1488                                                               maxRowCount,
1489                                                               offset);
1490         }
1491 
1492         /**
1493          * {@inheritDoc}
1494          * 
1495          * @see org.modeshape.jcr.query.JcrQueryContext#store(java.lang.String, org.modeshape.graph.property.Name,
1496          *      java.lang.String, java.lang.String)
1497          */
1498         @Override
1499         public Node store( String absolutePath,
1500                            Name nodeType,
1501                            String language,
1502                            String statement ) throws RepositoryException {
1503             session.checkLive();
1504             NamespaceRegistry namespaces = session.namespaces();
1505 
1506             Path path;
1507             try {
1508                 path = session.getExecutionContext().getValueFactories().getPathFactory().create(absolutePath);
1509             } catch (IllegalArgumentException iae) {
1510                 throw new RepositoryException(JcrI18n.invalidPathParameter.text("absolutePath", absolutePath));
1511             }
1512             Path parentPath = path.getParent();
1513 
1514             Node parentNode = session.getNode(parentPath);
1515 
1516             if (!parentNode.isCheckedOut()) {
1517                 throw new VersionException(JcrI18n.nodeIsCheckedIn.text(parentNode.getPath()));
1518             }
1519 
1520             Node queryNode = parentNode.addNode(path.relativeTo(parentPath).getString(namespaces),
1521                                                 JcrNtLexicon.QUERY.getString(namespaces));
1522 
1523             queryNode.setProperty(JcrLexicon.LANGUAGE.getString(namespaces), language);
1524             queryNode.setProperty(JcrLexicon.STATEMENT.getString(namespaces), statement);
1525 
1526             return queryNode;
1527         }
1528 
1529     }
1530 
1531     protected static class SessionTypeSystem implements JcrTypeSystem {
1532         protected final JcrSession session;
1533         protected final TypeSystem delegate;
1534 
1535         protected SessionTypeSystem( JcrSession session ) {
1536             this.session = session;
1537             this.delegate = session.getExecutionContext().getValueFactories().getTypeSystem();
1538         }
1539 
1540         @Override
1541         public Set<String> getTypeNames() {
1542             return delegate.getTypeNames();
1543         }
1544 
1545         @Override
1546         public TypeFactory<?> getTypeFactory( Object prototype ) {
1547             return delegate.getTypeFactory(prototype);
1548         }
1549 
1550         @Override
1551         public TypeFactory<?> getTypeFactory( String typeName ) {
1552             return delegate.getTypeFactory(typeName);
1553         }
1554 
1555         @Override
1556         public TypeFactory<String> getStringFactory() {
1557             return delegate.getStringFactory();
1558         }
1559 
1560         @Override
1561         public TypeFactory<?> getReferenceFactory() {
1562             return delegate.getReferenceFactory();
1563         }
1564 
1565         @Override
1566         public TypeFactory<?> getPathFactory() {
1567             return delegate.getPathFactory();
1568         }
1569 
1570         @Override
1571         public TypeFactory<Long> getLongFactory() {
1572             return delegate.getLongFactory();
1573         }
1574 
1575         @Override
1576         public TypeFactory<Double> getDoubleFactory() {
1577             return delegate.getDoubleFactory();
1578         }
1579 
1580         @Override
1581         public String getDefaultType() {
1582             return delegate.getDefaultType();
1583         }
1584 
1585         @Override
1586         public Comparator<Object> getDefaultComparator() {
1587             return delegate.getDefaultComparator();
1588         }
1589 
1590         @Override
1591         public TypeFactory<BigDecimal> getDecimalFactory() {
1592             return delegate.getDecimalFactory();
1593         }
1594 
1595         @Override
1596         public TypeFactory<?> getDateTimeFactory() {
1597             return delegate.getDateTimeFactory();
1598         }
1599 
1600         @Override
1601         public String getCompatibleType( String type1,
1602                                          String type2 ) {
1603             return delegate.getCompatibleType(type1, type2);
1604         }
1605 
1606         @Override
1607         public TypeFactory<Boolean> getBooleanFactory() {
1608             return delegate.getBooleanFactory();
1609         }
1610 
1611         @Override
1612         public TypeFactory<?> getBinaryFactory() {
1613             return delegate.getBinaryFactory();
1614         }
1615 
1616         @Override
1617         public String asString( Object value ) {
1618             return delegate.asString(value);
1619         }
1620 
1621         @Override
1622         public ValueFactory getValueFactory() {
1623             return session.getValueFactory();
1624         }
1625     }
1626 }