// Copyright (C) 2006-2008 Google Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package com.google.enterprise.connector.mock.jcr; import com.google.enterprise.connector.mock.MockRepositoryDateTime; import com.google.enterprise.connector.mock.MockRepositoryDocumentStore; import com.google.enterprise.connector.spi.Value; import org.json.JSONException; import org.json.JSONObject; import java.text.MessageFormat; import java.text.ParseException; import java.text.ParsePosition; import java.util.Calendar; import javax.jcr.Node; import javax.jcr.RepositoryException; import javax.jcr.query.InvalidQueryException; import javax.jcr.query.Query; import javax.jcr.query.QueryManager; /** * MockJcrQuery implements the corresponding JCR interface. This implementation * temporarily violates the explicit semantics of JCR by changing the query * language semantics to specify only a date range. */ public class MockJcrQueryManager implements QueryManager { private static final String XPATH_QUERY_STRING_UNBOUNDED_DEFAULT = "//*[@jcr:primaryType='nt:resource'] order by @jcr:lastModified, @jcr:uuid"; private static final String XPATH_QUERY_STRING_BOUNDED_DEFAULT = "//*[@jcr:primaryType = 'nt:resource' and @jcr:lastModified >= " + "''{0}''] order by @jcr:lastModified, @jcr:uuid"; private String xpathUnboundedTraversalQuery; private String xpathBoundedTraversalQuery; /** * @param xpathBoundedTraversalQuery the xpathBoundedTraversalQuery to set */ void setXpathBoundedTraversalQuery(String xpathBoundedTraversalQuery) { this.xpathBoundedTraversalQuery = xpathBoundedTraversalQuery; } /** * @param xpathUnboundedTraversalQuery the xpathUnboundedTraversalQuery to set */ void setXpathUnboundedTraversalQuery(String xpathUnboundedTraversalQuery) { this.xpathUnboundedTraversalQuery = xpathUnboundedTraversalQuery; } MockRepositoryDocumentStore store; static final String[] SUPPORTED_LANGUAGES = new String[] { "mockQueryLanguage", Query.XPATH}; /** * Creates a MockJcrQueryManager from a MockRepositoryDocumentStore * * @param store */ public MockJcrQueryManager(MockRepositoryDocumentStore store) { this.store = store; this.xpathUnboundedTraversalQuery = XPATH_QUERY_STRING_UNBOUNDED_DEFAULT; this.xpathBoundedTraversalQuery = XPATH_QUERY_STRING_BOUNDED_DEFAULT; } /** * Creates a query object. This class does not fully support JCR, because only * the pseudo-query-language "mockQueryLanguage" is supported. * @param statement * @param language * @return MockJcrQuery * @throws InvalidQueryException * @throws RepositoryException */ public Query createQuery(String statement, String language) throws InvalidQueryException, RepositoryException { if (statement == null || statement.length() == 0) { throw new InvalidQueryException("Invalid query: " + statement); } if (language == null) { throw new IllegalArgumentException("Null language"); } if (language.equals("mockQueryLanguage")) { return createMockQueryLanguageQuery(statement); } if (language.equals(Query.XPATH)) { return createXpathQuery(statement); } throw new IllegalArgumentException("Unsupported language: " + language); } private Query createMockQueryLanguageQuery(String statement) { JSONObject jo; try { jo = new JSONObject(statement); } catch (JSONException e) { throw new IllegalArgumentException("query statement can not be parsed"); } int fromInt; int toInt; try { fromInt = jo.getInt("from"); toInt = jo.getInt("to"); } catch (JSONException e) { throw new IllegalArgumentException("test input can not be parsed"); } MockRepositoryDateTime from = new MockRepositoryDateTime(fromInt); MockRepositoryDateTime to = new MockRepositoryDateTime(toInt); return new MockJcrQuery(from, to, store); } private Query createXpathQuery(String statement) throws InvalidQueryException, RepositoryException { if (statement.equals(xpathUnboundedTraversalQuery)) { return createXpathQueryNoBound(); } MessageFormat mf = new MessageFormat(xpathBoundedTraversalQuery); Object[] objs = mf.parse(statement, new ParsePosition(0)); if (objs == null || objs.length < 1 || !(objs[0] instanceof String)) { throw new InvalidQueryException("Invalid query: \"" + statement + "\" " + "does not match format: \"" + xpathBoundedTraversalQuery + "\""); } String dateString = (String) objs[0]; return createXpathQueryWithBound(statement, dateString); } private Query createXpathQueryNoBound() { MockRepositoryDateTime from = new MockRepositoryDateTime(0); return new MockJcrQuery(from, store); } private Query createXpathQueryWithBound(String statement, String dateString) throws InvalidQueryException { Calendar c = null; try { c = Value.iso8601ToCalendar(dateString); } catch (ParseException e) { throw new InvalidQueryException("Invalid query: " + statement + ". " + "Can't parse date.", e); } long millis = c.getTimeInMillis(); int fromInt = (int) (millis / 1000); MockRepositoryDateTime from = new MockRepositoryDateTime(fromInt); return new MockJcrQuery(from, store); } /** * Returns the query languages supported - in this case, only the mock query * language "mockQueryLanguage". * * @return {"mockQueryLanguage"} */ public String[] getSupportedQueryLanguages() { return SUPPORTED_LANGUAGES; } // The following methods are JCR level 1 - but we do not anticipate using them /** * Throws UnsupportedOperationException * * @param arg0 * @return nothing */ public Query getQuery(Node arg0) { throw new UnsupportedOperationException(); } }