Index: extensions/modeshape-connector-filesystem/src/main/java/org/modeshape/connector/filesystem/FileSystemWorkspace.java =================================================================== --- extensions/modeshape-connector-filesystem/src/main/java/org/modeshape/connector/filesystem/FileSystemWorkspace.java (revision 2083) +++ extensions/modeshape-connector-filesystem/src/main/java/org/modeshape/connector/filesystem/FileSystemWorkspace.java (working copy) @@ -356,12 +356,14 @@ class FileSystemWorkspace extends PathWorkspace { properties.put(JcrLexicon.PRIMARY_TYPE, factory.create(JcrLexicon.PRIMARY_TYPE, ModeShapeLexicon.RESOURCE)); properties.put(JcrLexicon.LAST_MODIFIED, factory.create(JcrLexicon.LAST_MODIFIED, dateFactory.create(file.lastModified()))); - // Don't really know the encoding, either ... - // request.addProperty(factory.create(JcrLexicon.ENCODED, stringFactory.create("UTF-8"))); - // Now put the file's content into the "jcr:data" property ... BinaryFactory binaryFactory = context.getValueFactories().getBinaryFactory(); - properties.put(JcrLexicon.DATA, factory.create(JcrLexicon.DATA, binaryFactory.create(file))); + Binary binary = binaryFactory.create(file); + properties.put(JcrLexicon.DATA, factory.create(JcrLexicon.DATA, binary)); + + // Don't really know the encoding, either ... + // properties.put(JcrLexicon.ENCODED, factory.create(JcrLexicon.ENCODED, "UTF-8")); + // return new PathNode(path, null, properties, Collections.emptyList()); return new PathNode(null, path.getParent(), path.getLastSegment(), properties, Collections.emptyList()); } @@ -407,6 +409,7 @@ class FileSystemWorkspace extends PathWorkspace { return new PathNode(null, path.getParent(), path.getLastSegment(), properties, Collections.singletonList(pathFactory.createSegment(JcrLexicon.CONTENT))); } + /** * This utility files the existing {@link File} at the supplied path, and in the process will verify that the path is actually * valid. Index: modeshape-graph/src/main/java/org/modeshape/graph/query/parse/SqlQueryParser.java =================================================================== --- modeshape-graph/src/main/java/org/modeshape/graph/query/parse/SqlQueryParser.java (revision 2083) +++ modeshape-graph/src/main/java/org/modeshape/graph/query/parse/SqlQueryParser.java (working copy) @@ -706,7 +706,7 @@ public class SqlQueryParser implements QueryParser { throw new ParsingException(pos, msg); } selectorName = ((Selector)source).name(); - propertyName = first; + propertyName = removeBracketsAndQuotes(first); } tokens.consume(','); Index: modeshape-integration-tests/src/test/java/org/modeshape/test/integration/FileSystemRepositoryTckTest.java deleted file mode 100644 =================================================================== --- modeshape-integration-tests/src/test/java/org/modeshape/test/integration/FileSystemRepositoryTckTest.java (revision 2083) +++ /dev/null (working copy) @@ -1,33 +0,0 @@ -/* - * ModeShape (http://www.modeshape.org) - * See the COPYRIGHT.txt file distributed with this work for information - * regarding copyright ownership. Some portions may be licensed - * to Red Hat, Inc. under one or more contributor license agreements. - * See the AUTHORS.txt file in the distribution for a full listing of - * individual contributors. - * - * ModeShape is free software. Unless otherwise indicated, all code in ModeShape - * is licensed to you under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * ModeShape is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this software; if not, write to the Free - * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA, or see the FSF site: http://www.fsf.org. - */ -package org.modeshape.test.integration; - -import junit.framework.Test; - -public class FileSystemRepositoryTckTest { - - public static Test suite() { - return AbstractRepositoryTckTest.readOnlyRepositorySuite("filesystem"); - } -} Index: modeshape-integration-tests/src/test/java/org/modeshape/test/integration/filesystem/FileSystemRepositoryTckTest.java new file mode 100644 =================================================================== --- /dev/null (revision 2083) +++ modeshape-integration-tests/src/test/java/org/modeshape/test/integration/filesystem/FileSystemRepositoryTckTest.java (working copy) @@ -0,0 +1,34 @@ +/* + * ModeShape (http://www.modeshape.org) + * See the COPYRIGHT.txt file distributed with this work for information + * regarding copyright ownership. Some portions may be licensed + * to Red Hat, Inc. under one or more contributor license agreements. + * See the AUTHORS.txt file in the distribution for a full listing of + * individual contributors. + * + * ModeShape is free software. Unless otherwise indicated, all code in ModeShape + * is licensed to you under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * ModeShape is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.modeshape.test.integration.filesystem; + +import org.modeshape.test.integration.AbstractRepositoryTckTest; +import junit.framework.Test; + +public class FileSystemRepositoryTckTest { + + public static Test suite() { + return AbstractRepositoryTckTest.readOnlyRepositorySuite("filesystem"); + } +} Index: modeshape-integration-tests/src/test/java/org/modeshape/test/integration/filesystem/FileSystemRepositoryTest.java new file mode 100644 =================================================================== --- /dev/null (revision 2083) +++ modeshape-integration-tests/src/test/java/org/modeshape/test/integration/filesystem/FileSystemRepositoryTest.java (working copy) @@ -0,0 +1,187 @@ +/* + * ModeShape (http://www.modeshape.org) + * See the COPYRIGHT.txt file distributed with this work for information + * regarding copyright ownership. Some portions may be licensed + * to Red Hat, Inc. under one or more contributor license agreements. + * See the AUTHORS.txt file in the distribution for a full listing of + * individual contributors. + * + * ModeShape is free software. Unless otherwise indicated, all code in ModeShape + * is licensed to you under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * ModeShape is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.modeshape.test.integration.filesystem; + +import static org.hamcrest.core.Is.is; +import static org.hamcrest.core.IsNull.notNullValue; +import static org.junit.Assert.assertThat; +import java.util.ArrayList; +import java.util.List; +import javax.jcr.Node; +import javax.jcr.Repository; +import javax.jcr.RepositoryException; +import javax.jcr.Session; +import javax.jcr.query.Query; +import javax.jcr.query.QueryResult; +import javax.jcr.query.Row; +import javax.jcr.query.RowIterator; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.modeshape.common.collection.Problem; +import org.modeshape.graph.JcrLexicon; +import org.modeshape.graph.ModeShapeLexicon; +import org.modeshape.jcr.JcrConfiguration; +import org.modeshape.jcr.JcrEngine; + +public class FileSystemRepositoryTest { + + private static final String TEST_REPOSITORY = "Test Repository Source"; + private static final String TEST_WORKSPACE = "defaultWorkspace"; + + private static JcrConfiguration configuration; + private static JcrEngine engine; + private static List sessions = new ArrayList(); + private boolean print = false; + + @BeforeClass + public static void beforeAll() throws Exception { + configuration = new JcrConfiguration(); + configuration.loadFrom("src/test/resources/tck/filesystem/configRepository.xml"); + + // Create an engine and use it to populate the source ... + engine = configuration.build(); + try { + engine.start(); + } catch (RuntimeException e) { + // There was a problem starting the engine ... + System.err.println("There were problems starting the engine:"); + for (Problem problem : engine.getProblems()) { + System.err.println(problem); + } + throw e; + } + } + + @AfterClass + public static void afterAll() throws Exception { + // Close all of the sessions ... + for (Session session : sessions) { + if (session.isLive()) session.logout(); + } + sessions.clear(); + + // Shut down the engines ... + if (engine != null) { + try { + engine.shutdown(); + } finally { + engine = null; + } + } + } + + @Before + public void beforeEach() { + print = false; + } + + // ---------------------------------------------------------------------------------------------------------------- + // Tests + // ---------------------------------------------------------------------------------------------------------------- + + @Test + public void shouldHaveContentInWorkspace() throws Exception { + Session session = sessionFrom(engine); + Node node1 = session.getRootNode().getNode("testroot/node1"); + assertThat(node1, is(notNullValue())); + assertThat(node1.getPrimaryNodeType().getName(), is("nt:file")); + Node node1Content = node1.getNode(stringFrom(JcrLexicon.CONTENT)); + assertThat(node1Content, is(notNullValue())); + assertThat(node1Content.getPrimaryNodeType().getName(), is(stringFrom(ModeShapeLexicon.RESOURCE))); + } + + @Test + public void shouldFindAllModeResourceNodesUsingJcrSql2Query() throws Exception { + Session session = sessionFrom(engine); + String sql = "SELECT * FROM [mode:resource]"; + Query query = session.getWorkspace().getQueryManager().createQuery(sql, Query.JCR_SQL2); + QueryResult result = query.execute(); + if (print) System.out.println(result); + } + + @Test + public void shouldFindAllNtFileNodesUsingJcrSql2Query() throws Exception { + Session session = sessionFrom(engine); + String sql = "SELECT * FROM [nt:file]"; + Query query = session.getWorkspace().getQueryManager().createQuery(sql, Query.JCR_SQL2); + QueryResult result = query.execute(); + if (print) System.out.println(result); + } + + @Test + public void shouldFindModeResourceNodesWithAnyPropertyContainingStringUsingJcrSql2Query() throws Exception { + Session session = sessionFrom(engine); + String sql = "SELECT * FROM [mode:resource] WHERE CONTAINS(*,'food')"; + Query query = session.getWorkspace().getQueryManager().createQuery(sql, Query.JCR_SQL2); + QueryResult result = query.execute(); + if (print) System.out.println(result); + RowIterator rowIter = result.getRows(); + while (rowIter.hasNext()) { + Row row = rowIter.nextRow(); + double score = row.getScore(); + assertThat(score > 0.0f, is(true)); + } + } + + @Test + public void shouldFindModeResourceNodesContainingStringUsingJcrSql2Query() throws Exception { + Session session = sessionFrom(engine); + String sql = "SELECT * FROM [mode:resource] WHERE CONTAINS([jcr:data],'food')"; + Query query = session.getWorkspace().getQueryManager().createQuery(sql, Query.JCR_SQL2); + QueryResult result = query.execute(); + if (print) System.out.println(result); + RowIterator rowIter = result.getRows(); + while (rowIter.hasNext()) { + Row row = rowIter.nextRow(); + double score = row.getScore(); + assertThat(score > 0.0f, is(true)); + } + } + + // ---------------------------------------------------------------------------------------------------------------- + // Utility Methods + // ---------------------------------------------------------------------------------------------------------------- + + protected Session sessionFrom( JcrEngine engine ) throws RepositoryException { + Repository repository = engine.getRepository(TEST_REPOSITORY); + Session session = repository.login(TEST_WORKSPACE); + sessions.add(session); + return session; + } + + protected String stringFrom( Object object ) { + return engine.getExecutionContext().getValueFactories().getStringFactory().create(object); + } + + // protected static URL resourceUrl( String name ) { + // return FileSystemRepositoryTest.class.getClassLoader().getResource(name); + // } + // + // protected static InputStream resourceStream( String name ) { + // return FileSystemRepositoryTest.class.getClassLoader().getResourceAsStream(name); + // } + +} Index: modeshape-integration-tests/src/test/resources/log4j.properties =================================================================== --- modeshape-integration-tests/src/test/resources/log4j.properties (revision 2083) +++ modeshape-integration-tests/src/test/resources/log4j.properties (working copy) @@ -31,3 +31,6 @@ log4j.logger.org.hibernate.hql.ast=WARN log4j.logger.org.hibernate.engine.loading.CollectionLoadContext=WARN log4j.logger.org.modeshape.connector.store=DEBUG + +# Turn this on TRACE to see the ModeShape indexing changes +#log4j.logger.org.modeshape.search.lucene=TRACE Index: modeshape-integration-tests/src/test/resources/tck/filesystem/defaultWorkspace/testroot/node1 =================================================================== --- modeshape-integration-tests/src/test/resources/tck/filesystem/defaultWorkspace/testroot/node1 (revision 2083) +++ modeshape-integration-tests/src/test/resources/tck/filesystem/defaultWorkspace/testroot/node1 (working copy) @@ -1 +1 @@ -Test content +food Index: modeshape-integration-tests/src/test/resources/tck/filesystem/defaultWorkspace/testroot/yetAnotherNode =================================================================== --- modeshape-integration-tests/src/test/resources/tck/filesystem/defaultWorkspace/testroot/yetAnotherNode (revision 2083) +++ modeshape-integration-tests/src/test/resources/tck/filesystem/defaultWorkspace/testroot/yetAnotherNode (working copy) @@ -1 +1 @@ -Test content +clothes \ No newline at end of file Index: modeshape-integration-tests/src/test/resources/tck/filesystem/otherWorkspace/testroot/nodeInOtherWorkspace =================================================================== --- modeshape-integration-tests/src/test/resources/tck/filesystem/otherWorkspace/testroot/nodeInOtherWorkspace (revision 2083) +++ modeshape-integration-tests/src/test/resources/tck/filesystem/otherWorkspace/testroot/nodeInOtherWorkspace (working copy) @@ -0,0 +1 @@ +products \ No newline at end of file Index: modeshape-jcr/src/main/java/org/modeshape/jcr/JcrI18n.java =================================================================== --- modeshape-jcr/src/main/java/org/modeshape/jcr/JcrI18n.java (revision 2083) +++ modeshape-jcr/src/main/java/org/modeshape/jcr/JcrI18n.java (working copy) @@ -152,8 +152,11 @@ public final class JcrI18n { public static I18n queryCannotBeParsedUsingLanguage; public static I18n queryInLanguageIsNotValid; public static I18n queryIsDisabledInRepository; + public static I18n queryResultsDoNotIncludeScore; + public static I18n queryResultsDoNotIncludeColumn; public static I18n selectorNotUsedInQuery; public static I18n selectorUsedInEquiJoinCriteriaDoesNotExistInQuery; + public static I18n multipleSelectorsAppearInQueryRequireSpecifyingSelectorName; // Type registration messages public static I18n invalidNodeTypeName; Index: modeshape-jcr/src/main/java/org/modeshape/jcr/query/JcrQueryResult.java =================================================================== --- modeshape-jcr/src/main/java/org/modeshape/jcr/query/JcrQueryResult.java (revision 2083) +++ modeshape-jcr/src/main/java/org/modeshape/jcr/query/JcrQueryResult.java (working copy) @@ -34,7 +34,6 @@ import javax.jcr.ItemNotFoundException; import javax.jcr.Node; import javax.jcr.NodeIterator; import javax.jcr.RepositoryException; -import javax.jcr.UnsupportedRepositoryOperationException; import javax.jcr.Value; import javax.jcr.query.QueryResult; import javax.jcr.query.Row; @@ -489,7 +488,7 @@ public class JcrQueryResult implements QueryResult, org.modeshape.jcr.api.query. */ @Override public Node getNode( String selectorName ) throws RepositoryException { - if (iterator.hasSelector(selectorName)) { + if (!iterator.hasSelector(selectorName)) { throw new RepositoryException(JcrI18n.selectorNotUsedInQuery.text(selectorName, iterator.query)); } return node; @@ -521,28 +520,39 @@ public class JcrQueryResult implements QueryResult, org.modeshape.jcr.api.query. } @Override - public Node getNode() throws RepositoryException { - throw new UnsupportedRepositoryOperationException(); + public Node getNode() { + return node; } @Override public String getPath() throws RepositoryException { - throw new UnsupportedRepositoryOperationException(); + return node.getPath(); } @Override public String getPath( String selectorName ) throws RepositoryException { - throw new UnsupportedRepositoryOperationException(); + if (!iterator.hasSelector(selectorName)) { + throw new RepositoryException(JcrI18n.selectorNotUsedInQuery.text(selectorName, iterator.query)); + } + return node.getPath(); } @Override public double getScore() throws RepositoryException { - throw new UnsupportedRepositoryOperationException(); + int index = iterator.scoreIndex; + if (index == -1) { + throw new RepositoryException(JcrI18n.queryResultsDoNotIncludeScore.text(iterator.query)); + } + Object score = tuple[index]; + return score instanceof Float ? ((Float)score).doubleValue() : (Double)score; } @Override public double getScore( String selectorName ) throws RepositoryException { - throw new UnsupportedRepositoryOperationException(); + if (!iterator.hasSelector(selectorName)) { + throw new RepositoryException(JcrI18n.selectorNotUsedInQuery.text(selectorName, iterator.query)); + } + return getScore(); } } @@ -551,7 +561,6 @@ public class JcrQueryResult implements QueryResult, org.modeshape.jcr.api.query. protected final Object[] tuple; private Value[] values = null; private Node[] nodes; - private int[] locationIndexes; protected MultiSelectorQueryResultRow( QueryResultRowIterator iterator, Node[] nodes, @@ -560,7 +569,6 @@ public class JcrQueryResult implements QueryResult, org.modeshape.jcr.api.query. this.iterator = iterator; this.tuple = tuple; this.nodes = nodes; - this.locationIndexes = locationIndexes; assert this.iterator != null; assert this.tuple != null; } @@ -572,18 +580,11 @@ public class JcrQueryResult implements QueryResult, org.modeshape.jcr.api.query. */ @Override public Node getNode( String selectorName ) throws RepositoryException { - try { - int locationIndex = iterator.columns.getLocationIndex(selectorName); - for (int i = 0; i != this.locationIndexes.length; ++i) { - if (this.locationIndexes[i] == locationIndex) { - return nodes[i]; - } - } - } catch (NoSuchElementException e) { - throw new RepositoryException(e.getLocalizedMessage(), e); + int locationIndex = iterator.columns.getLocationIndex(selectorName); + if (locationIndex == -1) { + throw new RepositoryException(JcrI18n.selectorNotUsedInQuery.text(selectorName, iterator.query)); } - assert false; - return null; + return nodes[locationIndex]; } /** @@ -592,19 +593,12 @@ public class JcrQueryResult implements QueryResult, org.modeshape.jcr.api.query. * @see javax.jcr.query.Row#getValue(java.lang.String) */ public Value getValue( String columnName ) throws ItemNotFoundException, RepositoryException { - try { - int locationIndex = iterator.columns.getLocationIndexForColumn(columnName); - for (int i = 0; i != this.locationIndexes.length; ++i) { - if (this.locationIndexes[i] == locationIndex) { - Node node = nodes[i]; - return node != null ? node.getProperty(columnName).getValue() : null; - } - } - } catch (NoSuchElementException e) { - throw new RepositoryException(e.getLocalizedMessage(), e); + int locationIndex = iterator.columns.getLocationIndexForColumn(columnName); + if (locationIndex == -1) { + throw new RepositoryException(JcrI18n.queryResultsDoNotIncludeColumn.text(columnName, iterator.query)); } - assert false; - return null; + Node node = nodes[locationIndex]; + return node != null ? node.getProperty(columnName).getValue() : null; } /** @@ -625,27 +619,39 @@ public class JcrQueryResult implements QueryResult, org.modeshape.jcr.api.query. @Override public Node getNode() throws RepositoryException { - throw new UnsupportedRepositoryOperationException(); + throw new RepositoryException( + JcrI18n.multipleSelectorsAppearInQueryRequireSpecifyingSelectorName.text(iterator.query)); } @Override public String getPath() throws RepositoryException { - throw new UnsupportedRepositoryOperationException(); + throw new RepositoryException( + JcrI18n.multipleSelectorsAppearInQueryRequireSpecifyingSelectorName.text(iterator.query)); } @Override - public String getPath( String selectorName ) throws RepositoryException { - throw new UnsupportedRepositoryOperationException(); + public double getScore() throws RepositoryException { + throw new RepositoryException( + JcrI18n.multipleSelectorsAppearInQueryRequireSpecifyingSelectorName.text(iterator.query)); } @Override - public double getScore() throws RepositoryException { - throw new UnsupportedRepositoryOperationException(); + public String getPath( String selectorName ) throws RepositoryException { + return getNode(selectorName).getPath(); } @Override public double getScore( String selectorName ) throws RepositoryException { - throw new UnsupportedRepositoryOperationException(); + if (!iterator.hasSelector(selectorName)) { + throw new RepositoryException(JcrI18n.selectorNotUsedInQuery.text(selectorName, iterator.query)); + } + int scoreIndex = iterator.columns.getFullTextSearchScoreIndexFor(selectorName); + if (scoreIndex == -1) { + throw new RepositoryException(JcrI18n.queryResultsDoNotIncludeScore.text(iterator.query)); + } + Object score = tuple[scoreIndex]; + return score instanceof Float ? ((Float)score).doubleValue() : (Double)score; } + } } Index: modeshape-jcr/src/main/resources/org/modeshape/jcr/JcrI18n.properties =================================================================== --- modeshape-jcr/src/main/resources/org/modeshape/jcr/JcrI18n.properties (revision 2083) +++ modeshape-jcr/src/main/resources/org/modeshape/jcr/JcrI18n.properties (working copy) @@ -140,8 +140,11 @@ invalidQueryLanguage="{0}" is not a valid query langauge. Supported languages a queryCannotBeParsedUsingLanguage=The {0} query "{1}" is not well-formed: {2} queryInLanguageIsNotValid=The {0} query "{1}" has one or more errors: {2} queryIsDisabledInRepository = The {0} repository does not have queries enabled +queryResultsDoNotIncludeScore = The query does not include the score in the results: {0} +queryResultsDoNotIncludeColumn = The column '{0}' does not appear in the results for query: {1} selectorNotUsedInQuery = The selector '{0}' was not used in the query: {1} selectorUsedInEquiJoinCriteriaDoesNotExistInQuery = The selector '{0}' used in the equijoin criteria (at line {1} and column {2}) does not exist in the query +multipleSelectorsAppearInQueryRequireSpecifyingSelectorName = Selector name must be specified when the query contains multiple selectors: {0} invalidNodeTypeName=Node types cannot have a null or empty name badNodeTypeName={0} cannot have a null or invalid name Index: modeshape-jcr/src/main/resources/org/modeshape/jcr/modeshape_builtins.cnd =================================================================== --- modeshape-jcr/src/main/resources/org/modeshape/jcr/modeshape_builtins.cnd (revision 2083) +++ modeshape-jcr/src/main/resources/org/modeshape/jcr/modeshape_builtins.cnd (working copy) @@ -71,11 +71,9 @@ + jcr:system (mode:system) = mode:system autocreated mandatory protected ignore + * (nt:base) = nt:unstructured sns version -[mode:resource] > nt:base +// This is the same as 'nt:resource' but is not 'mix:referenceable'... +[mode:resource] > nt:base, mix:mimeType, mix:lastModified - jcr:data (binary) primary mandatory -- jcr:encoding (string) copy -- jcr:lastModified (date) mandatory ignore -- jcr:mimeType (string) copy mandatory [mode:share] > mix:referenceable // Used for non-original shared nodes, but never really exposed to JCR clients - mode:sharedUuid (reference) mandatory protected initialize