blob: e178f2f942588463c9134822585d14213b9cd3b6 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.apache.sling.jcr.resource.internal.helper.jcr;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.NoSuchElementException;
import javax.jcr.RepositoryException;
import javax.jcr.Value;
import javax.jcr.query.Query;
import javax.jcr.query.QueryResult;
import javax.jcr.query.Row;
import javax.jcr.query.RowIterator;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.sling.api.SlingException;
import org.apache.sling.api.resource.QuerySyntaxException;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ValueMap;
import org.apache.sling.api.wrappers.ValueMapDecorator;
import org.apache.sling.jcr.resource.internal.helper.JcrResourceUtil;
import org.apache.sling.spi.resource.provider.ProviderContext;
import org.apache.sling.spi.resource.provider.QueryLanguageProvider;
import org.apache.sling.spi.resource.provider.ResolveContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class BasicQueryLanguageProvider implements QueryLanguageProvider<JcrProviderState> {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@SuppressWarnings("deprecation")
private static final String DEFAULT_QUERY_LANGUAGE = Query.XPATH;
/** column name for node path */
private static final String QUERY_COLUMN_PATH = "jcr:path";
/** column name for score value */
private static final String QUERY_COLUMN_SCORE = "jcr:score";
/** The provider context. */
private final ProviderContext providerContext;
public BasicQueryLanguageProvider(final ProviderContext ctx) {
this.providerContext = ctx;
}
@Override
public String[] getSupportedLanguages(final ResolveContext<JcrProviderState> ctx) {
try {
return ctx.getProviderState().getSession().getWorkspace().getQueryManager().getSupportedQueryLanguages();
} catch (final RepositoryException e) {
throw new SlingException("Unable to discover supported query languages", e);
}
}
@Override
public Iterator<Resource> findResources(final ResolveContext<JcrProviderState> ctx,
final String query,
final String language) {
try {
final QueryResult res = JcrResourceUtil.query(ctx.getProviderState().getSession(), query, language);
return new JcrNodeResourceIterator(ctx.getResourceResolver(),
null, null,
res.getNodes(),
ctx.getProviderState().getHelperData(),
this.providerContext.getExcludedPaths());
} catch (final javax.jcr.query.InvalidQueryException iqe) {
throw new QuerySyntaxException(iqe.getMessage(), query, language, iqe);
} catch (final RepositoryException re) {
throw new SlingException(re.getMessage(), re);
}
}
@Override
public Iterator<ValueMap> queryResources(final ResolveContext<JcrProviderState> ctx,
final String query,
final String language) {
final String queryLanguage = ArrayUtils.contains(getSupportedLanguages(ctx), language) ? language : DEFAULT_QUERY_LANGUAGE;
try {
final QueryResult result = JcrResourceUtil.query(ctx.getProviderState().getSession(), query, queryLanguage);
final String[] colNames = result.getColumnNames();
final RowIterator rows = result.getRows();
return new Iterator<ValueMap>() {
private ValueMap next;
{
next = seek();
}
@Override
public boolean hasNext() {
return next != null;
}
@Override
public ValueMap next() {
if (next == null) {
throw new NoSuchElementException();
}
final ValueMap result = next;
next = seek();
return result;
}
private ValueMap seek() {
ValueMap result = null;
while (result == null && rows.hasNext()) {
try {
final Row jcrRow = rows.nextRow();
final String resourcePath = jcrRow.getPath();
if (resourcePath != null && providerContext.getExcludedPaths().matches(resourcePath) == null) {
final Map<String, Object> row = new HashMap<>();
boolean didPath = false;
boolean didScore = false;
final Value[] values = jcrRow.getValues();
for (int i = 0; i < values.length; i++) {
Value v = values[i];
if (v != null) {
String colName = colNames[i];
row.put(colName,
JcrResourceUtil.toJavaObject(values[i]));
if (colName.equals(QUERY_COLUMN_PATH)) {
didPath = true;
row.put(colName, JcrResourceUtil.toJavaObject(values[i]).toString());
}
if (colName.equals(QUERY_COLUMN_SCORE)) {
didScore = true;
}
}
}
if (!didPath) {
row.put(QUERY_COLUMN_PATH, jcrRow.getPath());
}
if (!didScore) {
row.put(QUERY_COLUMN_SCORE, jcrRow.getScore());
}
result = new ValueMapDecorator(row);
}
} catch (final RepositoryException re) {
logger.error("queryResources$next: Problem accessing row values", re);
}
}
return result;
}
@Override
public void remove() {
throw new UnsupportedOperationException("remove");
}
};
} catch (final javax.jcr.query.InvalidQueryException iqe) {
throw new QuerySyntaxException(iqe.getMessage(), query, language, iqe);
} catch (final RepositoryException re) {
throw new SlingException(re.getMessage(), re);
}
}
}