/*
* Copyright (C) 2012 Tirasa
*
* 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 net.tirasa.hct.repository;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.jcr.RepositoryException;
import net.tirasa.hct.cocoon.sax.Constants;
import net.tirasa.hct.cocoon.sax.Constants.Attribute;
import net.tirasa.hct.cocoon.sax.Constants.Element;
import net.tirasa.hct.cocoon.sax.Constants.State;
import org.apache.commons.lang3.StringUtils;
import org.xml.sax.Attributes;
public class HCTQueryFilter {
private final List<String> andConds = new ArrayList<String>();
private final List<String> orConds = new ArrayList<String>();
private final Map<HCTDocumentChildNode, ChildQueryFilter> childConds =
new HashMap<HCTDocumentChildNode, ChildQueryFilter>();
public void addCond(final State state, final Element element, final Attributes atts) throws RepositoryException {
if (state != State.INSIDE_FILTER_AND && state != State.INSIDE_FILTER_OR) {
throw new IllegalArgumentException(
"Only " + State.INSIDE_FILTER_AND + " and " + State.INSIDE_FILTER_OR + " are allowed");
}
if (!Constants.FILTER_ELEMENTS.contains(element)) {
throw new IllegalArgumentException(element + " not in " + Constants.FILTER_ELEMENTS);
}
final String childName = atts.getValue(Constants.Attribute.CHILD_NAME.getName());
final String childType = atts.getValue(Constants.Attribute.CHILD_TYPE.getName());
HCTDocumentChildNode child = null;
if (!StringUtils.isBlank(childName) && !StringUtils.isBlank(childType)) {
child = new HCTDocumentChildNode(childName, childType);
if (!childConds.containsKey(child)) {
childConds.put(child, new ChildQueryFilter());
}
}
final String selector = child == null ? Constants.QUERY_DEFAULT_SELECTOR : child.getSelector();
String condition = null;
switch (element) {
case EQUALTO:
condition = getEqualTo(atts, selector);
break;
case NOT_EQUALTO:
condition = getNotEqualTo(atts, selector);
break;
case CONTAINS:
condition = getContains(atts, selector);
break;
case NOT_CONTAINS:
condition = getNotContains(atts, selector);
break;
case LIKE:
condition = getLike(atts, selector);
break;
case NOT_LIKE:
condition = getNotLike(atts, selector);
break;
case ISNULL:
condition = getIsNull(atts, selector);
break;
case NOT_NULL:
condition = getNotNull(atts, selector);
break;
case GREATER_OR_EQUAL:
condition = getGreaterOrEqualThan(atts, selector);
break;
case GREATER:
condition = getGreaterThan(atts, selector);
break;
case LESS_OR_EQUAL:
condition = getLessOrEqualThan(atts, selector);
break;
case LESS:
condition = getLessThan(atts, selector);
break;
default:
}
if (condition == null) {
throw new IllegalArgumentException("Could not build condition from " + element);
}
if (state == State.INSIDE_FILTER_AND) {
if (child == null) {
andConds.add(condition);
} else {
childConds.get(child).getAndConds().add(condition);
}
}
if (state == State.INSIDE_FILTER_OR) {
if (child == null) {
orConds.add(condition);
} else {
childConds.get(child).getOrConds().add(condition);
}
}
}
private String buildComparableValue(final Attributes atts) throws RepositoryException {
String propTypeString = atts.getValue(Constants.Attribute.TYPE.getName());
if (StringUtils.isBlank(propTypeString)) {
propTypeString = Constants.PropertyType.STRING.name();
}
final Constants.PropertyType propType = Constants.PropertyType.valueOf(propTypeString);
final String value = atts.getValue(Attribute.VALUE.getName());
String result;
switch (propType) {
case BOOLEAN:
case DOUBLE:
case LONG:
result = "CAST('" + value + "' AS " + propType.name() + ")";
break;
case DATE:
result = "CAST('" + QueryFunction.call(value) + "' AS " + propType.name() + ")";
break;
case STRING:
default:
result = "'" + value + "'";
}
return result;
}
private String getEqualTo(final Attributes atts, final String selector) throws RepositoryException {
return new StringBuilder().append(selector).append('.').append('[').
append(atts.getValue(Attribute.FIELD.getName())).append(']').
append(" = ").append(buildComparableValue(atts)).toString();
}
private String getNotEqualTo(final Attributes atts, final String selector) throws RepositoryException {
return new StringBuilder().append(selector).append('.').append('[').
append(atts.getValue(Attribute.FIELD.getName())).append(']').
append(" <> ").append(buildComparableValue(atts)).toString();
}
private String getContains(final Attributes atts, final String selector) {
final StringBuilder result = new StringBuilder().append("CONTAINS(").append(selector).append('.');
final String field = atts.getValue(Attribute.FIELD.getName());
if (StringUtils.isBlank(field)) {
result.append('*');
} else {
result.append('[').append(atts.getValue(Attribute.FIELD.getName())).append(']');
}
result.append(", '").append(atts.getValue(Attribute.VALUE.getName())).append("')");
return result.toString();
}
private String getNotContains(final Attributes atts, final String selector) {
return new StringBuilder().append("NOT ").append(getContains(atts, selector)).toString();
}
private String getLike(final Attributes atts, final String selector) {
return new StringBuilder().append(selector).append('.').append('[').
append(atts.getValue(Attribute.FIELD.getName())).append(']').
append(" LIKE '%").append(atts.getValue(Attribute.VALUE.getName())).append("%'").toString();
}
private String getNotLike(final Attributes atts, final String selector) {
return new StringBuilder().append("NOT ").append(getLike(atts, selector)).toString();
}
private String getIsNull(final Attributes atts, final String selector) {
return new StringBuilder().append(selector).append('.').append('[').
append(atts.getValue(Attribute.FIELD.getName())).append(']').
append(" IS NULL").toString();
}
private String getNotNull(final Attributes atts, final String selector) {
return new StringBuilder().append("NOT ").append(getIsNull(atts, selector)).toString();
}
private String getGreaterOrEqualThan(final Attributes atts, final String selector) throws RepositoryException {
return new StringBuilder().append(selector).append('.').append('[').
append(atts.getValue(Attribute.FIELD.getName())).append(']').
append(" >= ").append(buildComparableValue(atts)).toString();
}
private String getGreaterThan(final Attributes atts, final String selector) throws RepositoryException {
return new StringBuilder().append(selector).append('.').append('[').
append(atts.getValue(Attribute.FIELD.getName())).append(']').
append(" > ").append(buildComparableValue(atts)).toString();
}
private String getLessOrEqualThan(final Attributes atts, final String selector) throws RepositoryException {
return new StringBuilder().append(selector).append('.').append('[').
append(atts.getValue(Attribute.FIELD.getName())).append(']').
append(" <= ").append(buildComparableValue(atts)).toString();
}
private String getLessThan(final Attributes atts, final String selector) throws RepositoryException {
return new StringBuilder().append(selector).append('.').append('[').
append(atts.getValue(Attribute.FIELD.getName())).append(']').
append(" < ").append(buildComparableValue(atts)).toString();
}
public List<String> getAndConds() {
return andConds;
}
public List<String> getOrConds() {
return orConds;
}
public Map<HCTDocumentChildNode, ChildQueryFilter> getChildConds() {
return childConds;
}
public class ChildQueryFilter {
private final List<String> andConds = new ArrayList<String>();
private final List<String> orConds = new ArrayList<String>();
public List<String> getAndConds() {
return andConds;
}
public List<String> getOrConds() {
return orConds;
}
}
}