blob: e0b296c7e311034498aec5c96574c242cd20d4c3 [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.query.impl.resource.jcr.query;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.lang.StringUtils;
import org.apache.sling.query.impl.resource.jcr.JcrOperator;
import org.apache.sling.query.impl.resource.jcr.JcrTypeResolver;
import org.apache.sling.query.impl.resource.jcr.query.Formula.Operator;
import org.apache.sling.query.impl.selector.parser.Attribute;
import org.apache.sling.query.impl.selector.parser.SelectorSegment;
public class JcrQueryBuilder {
private final JcrTypeResolver typeResolver;
public JcrQueryBuilder(JcrTypeResolver typeResolver) {
this.typeResolver = typeResolver;
}
public String buildQuery(List<SelectorSegment> segments, String rootPath) {
StringBuilder query = new StringBuilder();
query.append("SELECT * FROM [");
query.append(findPrimaryType(segments));
query.append("]");
query.append(" AS s");
String conditionString = getConditionString(segments, rootPath);
if (StringUtils.isNotBlank(conditionString)) {
query.append(" WHERE ").append(conditionString);
}
return query.toString();
}
private String getConditionString(List<SelectorSegment> segments, String rootPath) {
Formula formula = prepareAlternativeConditions(segments);
if (StringUtils.isNotBlank(rootPath) && !"/".equals(rootPath)) {
List<Term> conditions = new ArrayList<Term>();
conditions.add(new Atomic(String.format("ISDESCENDANTNODE('%s')", rootPath)));
if (formula != null) {
conditions.add(formula);
}
formula = new Formula(Operator.AND, conditions);
}
if (formula == null) {
return null;
} else {
return formula.buildString();
}
}
private String findPrimaryType(List<SelectorSegment> segments) {
String result = null;
for (SelectorSegment s : segments) {
String type = s.getType();
if (!typeResolver.isJcrType(type)) {
continue;
}
if (result == null) {
result = type;
} else if (typeResolver.isSubtype(type, result)) {
result = type;
} else if (!typeResolver.isSubtype(result, type)) {
result = "nt:base";
}
}
if (result == null) {
result = "nt:base";
}
return result;
}
private static Formula prepareAlternativeConditions(List<SelectorSegment> segments) {
List<Term> list = new ArrayList<>();
for (SelectorSegment segment : segments) {
Formula conditions = prepareSegmentConditions(segment.getType(), segment.getName(),
segment.getAttributes());
if (conditions != null) {
list.add(conditions);
}
}
if (list.isEmpty()) {
return null;
} else {
return new Formula(Operator.OR, list);
}
}
private static Formula prepareSegmentConditions(String resourceType, String resourceName,
List<Attribute> attributes) {
List<Term> conditions = new ArrayList<>();
if (StringUtils.isNotBlank(resourceType) && !StringUtils.contains(resourceType, ':')) {
conditions.add(new Atomic(String.format("s.[sling:resourceType] = '%s'", resourceType)));
}
if (StringUtils.isNotBlank(resourceName)) {
conditions.add(new Atomic(String.format("NAME(s) = '%s'", resourceName)));
}
if (attributes != null) {
for (Attribute a : attributes) {
String attributeCondition = getAttributeCondition(a);
if (StringUtils.isNotBlank(attributeCondition)) {
conditions.add(new Atomic(attributeCondition));
}
}
}
if (conditions.isEmpty()) {
return null;
} else {
return new Formula(Operator.AND, conditions);
}
}
private static String getAttributeCondition(Attribute attribute) {
if (attribute.getKey().contains("/")) {
return null;
}
JcrOperator operator = JcrOperator.getSelectorOperator(attribute.getOperator());
String value = StringUtils.replace(attribute.getValue(), "'", "''");
return operator.getJcrQueryFragment(attribute.getKey(), value);
}
}