/*- * 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); } }