| /*- |
| * 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.resource.jcr.query; |
| |
| import java.util.ArrayList; |
| import java.util.List; |
| |
| import org.apache.commons.lang.StringUtils; |
| import org.apache.sling.query.resource.jcr.JcrOperator; |
| import org.apache.sling.query.resource.jcr.JcrTypeResolver; |
| import org.apache.sling.query.resource.jcr.query.Formula.Operator; |
| import org.apache.sling.query.selector.parser.Attribute; |
| import org.apache.sling.query.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<Term>(); |
| 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<Term>(); |
| 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); |
| } |
| } |