/******************************************************************************* * Copyright (c) 2014 Formal Mind GmbH. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Ingo Weigelt - initial API and implementation ******************************************************************************/ package org.eclipse.rmf.reqif10.search.filter; import java.math.BigInteger; import org.eclipse.rmf.reqif10.AttributeDefinition; import org.eclipse.rmf.reqif10.AttributeDefinitionInteger; import org.eclipse.rmf.reqif10.AttributeDefinitionReal; import org.eclipse.rmf.reqif10.AttributeValueInteger; import org.eclipse.rmf.reqif10.AttributeValueReal; import org.eclipse.rmf.reqif10.SpecElementWithAttributes; import org.eclipse.rmf.reqif10.common.util.ReqIF10Util; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Sets; public class NumberFilter extends AbstractAttributeFilter { public static final ImmutableSet<Operator> SUPPORTED_OPERATORS = Sets .immutableEnumSet(Operator.IS, Operator.IS_NOT, Operator.BETWEEN, Operator.GREATER, Operator.SMALLER, Operator.IS_SET, Operator.IS_NOT_SET); private AttributeDefinition attributeDefinition; private Operator operator; private Comparable<Number> value1; private Comparable<Number> value2; public NumberFilter(Operator operator, BigInteger value1, BigInteger value2, AttributeDefinitionInteger attributeDefinition) { init(operator, value1, value2, attributeDefinition); } public NumberFilter(Operator operator, Double value1, Double value2, AttributeDefinitionReal attributeDefinition) { init(operator, value1, value2, attributeDefinition); } /** * TODO (mj) How about abandoning the above two constructors in favor of * this one? Maybe after adding some sanity checks. */ public NumberFilter(Operator operator, Number value1, Number value2, AttributeDefinition attributeDefinition) { init(operator, (Comparable<? extends Number>) value1, (Comparable<? extends Number>) value2, attributeDefinition); } /** * * @param operator * @param value1 the value used for all operations. For the BETWEEN operation this is the lower value * @param value2 If operation is BETWEEN, this is the upper bound. Otherwise this parameter is ignored * @param attributeDefinition */ @SuppressWarnings("unchecked") private void init(Operator operator, Comparable<? extends Number> value1, Comparable<? extends Number> value2, AttributeDefinition attributeDefinition) { // ensure that operator is supported if (!SUPPORTED_OPERATORS.contains(operator)){ throw new IllegalArgumentException( "This filter does not support the " + operator.toString() + " operation"); }; // ensure that value1 is not null if (null == value1 && operator != Operator.IS_SET && operator != Operator.IS_NOT_SET ){ throw new IllegalArgumentException( "value1 can not be null"); } // ensure that value2 is not null for operations that need two parameters if (operator.equals(IFilter.Operator.BETWEEN)) { if (null == value2) { throw new IllegalArgumentException("value2 can not be null"); } } this.attributeDefinition = attributeDefinition; this.operator = operator; this.value1 = (Comparable<Number>) value1; this.value2 = (Comparable<Number>) value2; } @Override public boolean match(SpecElementWithAttributes element) { if (operator == Operator.IS_SET || operator == Operator.IS_NOT_SET){ return super.match(element); } Number theValue = getTheValue(element); if (theValue == null){ /* Check if there is any default value for this attribute */ theValue = getDefaultValue(element); } if (theValue == null){ if (operator.equals(Operator.IS_NOT)){ return true; } return false; } switch (operator) { case IS: return value1.compareTo(theValue) == 0; case IS_NOT: return value1.compareTo(theValue) != 0; case BETWEEN: return value1.compareTo(theValue) <= 0 && value2.compareTo(theValue) >= 0; case GREATER: return value1.compareTo(theValue) <= 0; case SMALLER: return value1.compareTo(theValue) >= 0; default: throw new IllegalArgumentException( "This filter does not support the " + this.operator + " operation"); } } private Number getDefaultValue(SpecElementWithAttributes element) { if (!AbstractAttributeFilter.isSetAttribute(element, attributeDefinition)){ return null; } if (attributeDefinition instanceof AttributeDefinitionInteger) { AttributeDefinitionInteger ad = (AttributeDefinitionInteger) attributeDefinition; if (!ad.isSetDefaultValue()){ return null; } if (!ad.getDefaultValue().isSetTheValue()){ return null; } return ad.getDefaultValue().getTheValue(); } if (attributeDefinition instanceof AttributeDefinitionReal) { AttributeDefinitionReal ad = (AttributeDefinitionReal) attributeDefinition; if (!ad.isSetDefaultValue()){ return null; } if (!ad.getDefaultValue().isSetTheValue()){ return null; } return ad.getDefaultValue().getTheValue(); } throw new IllegalStateException("Expected an AttributeDefinitionInteger or AttributeDefinitionReal as attribute but found " + attributeDefinition.getClass()); } private Number getTheValue(SpecElementWithAttributes element){ if (attributeDefinition instanceof AttributeDefinitionInteger){ AttributeValueInteger attributeValue = (AttributeValueInteger) ReqIF10Util.getAttributeValue(element, attributeDefinition); if (attributeValue == null || !attributeValue.isSetTheValue()){ return null; } return attributeValue.getTheValue(); } if (attributeDefinition instanceof AttributeDefinitionReal){ AttributeValueReal attributeValue = (AttributeValueReal) ReqIF10Util.getAttributeValue(element, attributeDefinition); if (attributeValue == null || !attributeValue.isSetTheValue()){ return null; } return attributeValue.getTheValue(); } else{ throw new IllegalArgumentException("SpecElementType is not supported"); } } @Override public AttributeDefinition getAttribute() { return attributeDefinition; } @Override public Operator getOperator() { return operator; } @Override public Number getFilterValue1() { return (Number) value1; } @Override public Number getFilterValue2() { return (Number) value2; } @Override public ImmutableSet<Operator> getSupportedOperators() { return SUPPORTED_OPERATORS; } }