/**
* Copyright (c) Codice Foundation
*
* This is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser
* General Public License as published by the Free Software Foundation, either version 3 of the
* License, or any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. A copy of the GNU Lesser General Public License
* is distributed along with this program and can be found at
* <http://www.gnu.org/licenses/lgpl.html>.
*
**/
package org.codice.ddf.spatial.ogc.wfs.v2_0_0.catalog.source;
import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.greaterThan;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.text.pattern.PatternMatcher.matchesPattern;
import static org.hamcrest.text.pattern.Patterns.anyCharacterIn;
import static org.hamcrest.text.pattern.Patterns.oneOrMore;
import static org.hamcrest.text.pattern.Patterns.sequence;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.namespace.QName;
import org.apache.commons.lang.StringUtils;
import org.codice.ddf.spatial.ogc.wfs.catalog.common.FeatureAttributeDescriptor;
import org.codice.ddf.spatial.ogc.wfs.catalog.common.FeatureMetacardType;
import org.codice.ddf.spatial.ogc.wfs.catalog.common.WfsConstants;
import org.codice.ddf.spatial.ogc.wfs.catalog.mapper.MetacardMapper;
import org.codice.ddf.spatial.ogc.wfs.v2_0_0.catalog.common.Wfs20Constants;
import org.codice.ddf.spatial.ogc.wfs.v2_0_0.catalog.common.Wfs20Constants.COMPARISON_OPERATORS;
import org.codice.ddf.spatial.ogc.wfs.v2_0_0.catalog.common.Wfs20Constants.SPATIAL_OPERATORS;
import org.codice.ddf.spatial.ogc.wfs.v2_0_0.catalog.common.Wfs20Constants.TEMPORAL_OPERATORS;
import org.custommonkey.xmlunit.XMLUnit;
import org.hamcrest.text.pattern.PatternMatcher;
import org.joda.time.DateTime;
import org.joda.time.DateTimeUtils;
import org.joda.time.DateTimeZone;
import org.joda.time.format.ISODateTimeFormat;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.opengis.filter.sort.SortOrder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.SAXException;
import com.google.common.base.Function;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ObjectArrays;
import ddf.catalog.data.Metacard;
import ddf.catalog.data.impl.BasicTypes;
import net.opengis.filter.v_2_0_0.BBOXType;
import net.opengis.filter.v_2_0_0.BinaryLogicOpType;
import net.opengis.filter.v_2_0_0.BinarySpatialOpType;
import net.opengis.filter.v_2_0_0.BinaryTemporalOpType;
import net.opengis.filter.v_2_0_0.ComparisonOperatorType;
import net.opengis.filter.v_2_0_0.ComparisonOperatorsType;
import net.opengis.filter.v_2_0_0.ConformanceType;
import net.opengis.filter.v_2_0_0.DistanceBufferType;
import net.opengis.filter.v_2_0_0.FilterCapabilities;
import net.opengis.filter.v_2_0_0.FilterType;
import net.opengis.filter.v_2_0_0.GeometryOperandsType.GeometryOperand;
import net.opengis.filter.v_2_0_0.LiteralType;
import net.opengis.filter.v_2_0_0.PropertyIsLikeType;
import net.opengis.filter.v_2_0_0.ResourceIdType;
import net.opengis.filter.v_2_0_0.ScalarCapabilitiesType;
import net.opengis.filter.v_2_0_0.SpatialOperatorType;
import net.opengis.filter.v_2_0_0.TemporalCapabilitiesType;
import net.opengis.filter.v_2_0_0.TemporalOperandsType;
import net.opengis.filter.v_2_0_0.TemporalOperatorType;
import net.opengis.filter.v_2_0_0.TemporalOperatorsType;
import net.opengis.filter.v_2_0_0.UnaryLogicOpType;
import net.opengis.gml.v_3_2_1.TimeInstantType;
import net.opengis.gml.v_3_2_1.TimePeriodType;
import net.opengis.gml.v_3_2_1.TimePositionType;
import net.opengis.ows.v_1_1_0.AllowedValues;
import net.opengis.ows.v_1_1_0.DomainType;
import net.opengis.ows.v_1_1_0.ValueType;
public class TestWfsFilterDelegate {
private static final Logger LOGGER = LoggerFactory.getLogger(TestWfsFilterDelegate.class);
private static final String FILTER_QNAME_LOCAL_PART = "Filter";
private static final String LITERAL = "Literal";
private static final String VALUE_REFERENCE = "ValueReference";
private static final String LOGICAL_OR_NAME = "{http://www.opengis.net/fes/2.0}Or";
private static final String LOGICAL_AND_NAME = "{http://www.opengis.net/fes/2.0}And";
private static final String LOGICAL_NOT_NAME = "{http://www.opengis.net/fes/2.0}Not";
private static final String MOCK_GEOM = "geom";
private static final String MOCK_GEOM2 = "geom2";
private static final String POLYGON = "POLYGON ((30 -10, 30 30, 10 30, 10 -10, 30 -10))";
private static final String LINESTRING = "LINESTRING (30 -10, 30 30, 10 30, 10 -10)";
private static final String POINT = "POINT (30 -10)";
private static final double DISTANCE = 1000.0;
@Rule
public ExpectedException thrown = ExpectedException.none();
private String mockMetacardAttribute = "modified";
private String mockFeatureType = "mockFeatureType";
private String mockFeatureProperty = "mockFeatureProperty";
private MetacardMapper mockMapper;
private FeatureMetacardType mockFeatureMetacardType = mock(FeatureMetacardType.class);
@BeforeClass
public static void setUp() {
XMLUnit.setNormalizeWhitespace(true);
XMLUnit.setIgnoreWhitespace(true);
}
private static JAXBContext initJaxbContext() {
JAXBContext localJaxbContext = null;
String contextPath = StringUtils.join(new String[] {Wfs20Constants.OGC_FILTER_PACKAGE,
Wfs20Constants.OGC_GML_PACKAGE, Wfs20Constants.OGC_OWS_PACKAGE}, ":");
try {
LOGGER.debug("Creating JAXB context with context path: {}", contextPath);
localJaxbContext = JAXBContext.newInstance(contextPath);
} catch (JAXBException e) {
LOGGER.error("Unable to create JAXB context using contextPath: {}", contextPath, e);
}
return localJaxbContext;
}
@Test
public void testFullFilterCapabilities() {
WfsFilterDelegate delegate = new WfsFilterDelegate(mockFeatureMetacardType,
MockWfsServer.getFilterCapabilities(), Wfs20Constants.EPSG_4326_URN, null,
WfsConstants.LAT_LON_ORDER);
assertThat(delegate.isLogicalOps(), is(true));
assertThat(delegate.isEpsg4326(), is(true));
assertThat(delegate.isSortingSupported(), is(true));
assertThat(delegate.getSrsName(), is(Wfs20Constants.EPSG_4326_URN));
assertThat(delegate.getComparisonOps().size(), is(COMPARISON_OPERATORS.values().length));
assertThat(delegate.getGeometryOperands().size(), greaterThan(0));
assertThat(delegate.getSpatialOps().size(), is(SPATIAL_OPERATORS.values().length));
assertThat(delegate.getTemporalOps().size(), is(TEMPORAL_OPERATORS.values().length));
assertThat(delegate.getTemporalOperands().size(), greaterThan(0));
}
@Test
public void testNoConformance() {
FilterCapabilities capabilities = MockWfsServer.getFilterCapabilities();
capabilities.setConformance(null);
WfsFilterDelegate delegate = new WfsFilterDelegate(mockFeatureMetacardType, capabilities,
Wfs20Constants.EPSG_4326_URN, null, WfsConstants.LAT_LON_ORDER);
assertThat(delegate.isLogicalOps(), is(true));
assertThat(delegate.isEpsg4326(), is(true));
assertThat(delegate.isSortingSupported(), is(false));
assertThat(delegate.getSrsName(), is(Wfs20Constants.EPSG_4326_URN));
assertThat(delegate.getComparisonOps().size(), is(COMPARISON_OPERATORS.values().length));
assertThat(delegate.getGeometryOperands().size(), greaterThan(0));
assertThat(delegate.getSpatialOps().size(), is(SPATIAL_OPERATORS.values().length));
assertThat(delegate.getTemporalOps().size(), is(TEMPORAL_OPERATORS.values().length));
assertThat(delegate.getTemporalOperands().size(), greaterThan(0));
}
@Test
public void testNoComparisonOps() {
FilterCapabilities capabilities = MockWfsServer.getFilterCapabilities();
capabilities.setScalarCapabilities(null);
WfsFilterDelegate delegate = new WfsFilterDelegate(mockFeatureMetacardType, capabilities,
Wfs20Constants.EPSG_4326_URN, null, WfsConstants.LAT_LON_ORDER);
assertThat(delegate.isLogicalOps(), is(false));
assertThat(delegate.isEpsg4326(), is(true));
assertThat(delegate.isSortingSupported(), is(true));
assertThat(delegate.getSrsName(), is(Wfs20Constants.EPSG_4326_URN));
assertThat(delegate.getComparisonOps().size(), is(0));
assertThat(delegate.getGeometryOperands().size(), greaterThan(0));
assertThat(delegate.getSpatialOps().size(), is(SPATIAL_OPERATORS.values().length));
assertThat(delegate.getTemporalOps().size(), is(TEMPORAL_OPERATORS.values().length));
assertThat(delegate.getTemporalOperands().size(), greaterThan(0));
}
@Test
public void testNoSpatialOps() {
FilterCapabilities capabilities = MockWfsServer.getFilterCapabilities();
capabilities.setSpatialCapabilities(null);
WfsFilterDelegate delegate = new WfsFilterDelegate(mockFeatureMetacardType, capabilities,
Wfs20Constants.EPSG_4326_URN, null, WfsConstants.LAT_LON_ORDER);
assertThat(delegate.isLogicalOps(), is(true));
assertThat(delegate.isEpsg4326(), is(true));
assertThat(delegate.isSortingSupported(), is(true));
assertThat(delegate.getSrsName(), is(Wfs20Constants.EPSG_4326_URN));
assertThat(delegate.getComparisonOps().size(), is(COMPARISON_OPERATORS.values().length));
assertThat(delegate.getGeometryOperands().size(), is(0));
assertThat(delegate.getSpatialOps().size(), is(0));
assertThat(delegate.getTemporalOps().size(), is(TEMPORAL_OPERATORS.values().length));
assertThat(delegate.getTemporalOperands().size(), greaterThan(0));
}
@Test
public void testNoTemporalOps() {
FilterCapabilities capabilities = MockWfsServer.getFilterCapabilities();
capabilities.setTemporalCapabilities(null);
WfsFilterDelegate delegate = new WfsFilterDelegate(mockFeatureMetacardType, capabilities,
Wfs20Constants.EPSG_4326_URN, null, WfsConstants.LAT_LON_ORDER);
assertThat(delegate.isLogicalOps(), is(true));
assertThat(delegate.isEpsg4326(), is(true));
assertThat(delegate.isSortingSupported(), is(true));
assertThat(delegate.getSrsName(), is(Wfs20Constants.EPSG_4326_URN));
assertThat(delegate.getComparisonOps().size(), is(COMPARISON_OPERATORS.values().length));
assertThat(delegate.getGeometryOperands().size(), greaterThan(0));
assertThat(delegate.getSpatialOps().size(), is(SPATIAL_OPERATORS.values().length));
assertThat(delegate.getTemporalOps().size(), is(0));
assertThat(delegate.getTemporalOperands().size(), is(0));
}
@Test
public void testConformanceAllowedValues() {
// Setup
FilterCapabilities capabilities = MockWfsServer.getFilterCapabilities();
ConformanceType conformance = capabilities.getConformance();
List<DomainType> domainTypes = conformance.getConstraint();
for (DomainType domainType : domainTypes) {
if (StringUtils.equals(domainType.getName(), "ImplementsSorting")) {
domainType.setNoValues(null);
ValueType asc = new ValueType();
asc.setValue("ASC");
ValueType desc = new ValueType();
desc.setValue("DESC");
AllowedValues allowedValues = new AllowedValues();
List<Object> values = new ArrayList<Object>();
values.add(asc);
values.add(desc);
allowedValues.setValueOrRange(values);
domainType.setAllowedValues(allowedValues);
ValueType defaultValue = new ValueType();
defaultValue.setValue("ASC");
domainType.setDefaultValue(defaultValue);
break;
}
}
// Perform Test
WfsFilterDelegate delegate = new WfsFilterDelegate(mockFeatureMetacardType, capabilities,
Wfs20Constants.EPSG_4326_URN, null, WfsConstants.LAT_LON_ORDER);
// Verify
assertThat(delegate.isSortingSupported(), is(true));
assertThat(delegate.getAllowedSortOrders().size(), is(2));
assertThat(delegate.getAllowedSortOrders().contains(SortOrder.ASCENDING), is(true));
assertThat(delegate.getAllowedSortOrders().contains(SortOrder.DESCENDING), is(true));
}
@Test
/**
* Doing a Absolute query from the search UI creates a During filter with the selected Begin and End date/times.
*
* Example During filter:
*
* <Filter>
* <During>
* <ValueReference>myFeatureProperty</ValueReference>
* <ns4:TimePeriod ns4:id="myFeatureType.1406219647420">
* <ns4:beginPosition>1974-08-01T16:29:45.430-07:00</ns4:beginPosition>
* <ns4:endPosition>2014-07-22T16:29:45.430-07:00</ns4:endPosition>
* </ns4:TimePeriod>
* </During>
* </Filter>
*
**/ public void testDuringPropertyIsOfTemporalType() throws Exception {
SequentialTestMockHolder sequentialTestMockHolder = new SequentialTestMockHolder().invoke();
WfsFilterDelegate delegate = sequentialTestMockHolder.getDelegate();
String mockMetacardAttribute = sequentialTestMockHolder.getMockMetacardAttribute();
String mockFeatureProperty = sequentialTestMockHolder.getMockFeatureProperty();
String mockFeatureType = sequentialTestMockHolder.getMockFeatureType();
DateTime startDate = new DateTime(2014, 01, 01, 01, 01, 01, 123,
DateTimeZone.forID("-07:00"));
DateTime endDate = new DateTime(2014, 01, 02, 01, 01, 01, 123,
DateTimeZone.forID("-07:00"));
// Perform Test
FilterType filter = delegate
.during(mockMetacardAttribute, startDate.toDate(), endDate.toDate());
//Verify
assertThat(filter.getTemporalOps().getName().toString(),
is("{http://www.opengis.net/fes/2.0}During"));
BinaryTemporalOpType binaryTemporalOpType = (BinaryTemporalOpType) filter.getTemporalOps()
.getValue();
assertThat(binaryTemporalOpType.isSetValueReference(), is(true));
assertThat(binaryTemporalOpType.getValueReference(), is(mockFeatureProperty));
assertThat(binaryTemporalOpType.isSetExpression(), is(true));
TimePeriodType timePeriod = (TimePeriodType) binaryTemporalOpType.getExpression()
.getValue();
assertThat(timePeriod.getBeginPosition().getValue().get(0), is("2014-01-01T08:01:01Z"));
assertThat(timePeriod.getEndPosition().getValue().get(0), is("2014-01-02T08:01:01Z"));
assertThat(timePeriod.getId(), is(matchesPattern(new PatternMatcher(
sequence(mockFeatureType, ".", oneOrMore(anyCharacterIn("0-9")))))));
}
@Test(expected = IllegalArgumentException.class)
/**
* Verify that when Feature property "myFeatureProperty" is not defined in the Feature schema as a {http://www.opengis.net/gml/3.2}TimePeriodType
* an IllegalArgumentException is thrown.
*/ public void testDuringPropertyIsNotOfTemporalType() throws Throwable {
testSequentialPropertyIsNotOfTemporalType("during", new DateTime().minusDays(365).toDate(),
new DateTime().minusDays(10).toDate());
}
@Test
/**
* Doing a Relative query from the search UI creates a During filter with the selected End date/time and the
* Begin date/time calculated based on the duration.
*
* <Filter>
* <During>
* <ValueReference>myFeatureProperty</ValueReference>
* <ns4:TimePeriod ns4:id="myFeatureType.1406219647420">
* <ns4:beginPosition>1974-08-01T16:29:45.430-07:00</ns4:beginPosition>
* <ns4:endPosition>2014-07-22T16:29:45.430-07:00</ns4:endPosition>
* </ns4:TimePeriod>
* </During>
* </Filter>
*
**/ public void testRelativePropertyIsOfTemporalType() throws Exception {
// Setup
SequentialTestMockHolder sequentialTestMockHolder = new SequentialTestMockHolder().invoke();
WfsFilterDelegate delegate = sequentialTestMockHolder.getDelegate();
String mockMetacardAttribute = sequentialTestMockHolder.getMockMetacardAttribute();
String mockFeatureProperty = sequentialTestMockHolder.getMockFeatureProperty();
String mockFeatureType = sequentialTestMockHolder.getMockFeatureType();
long duration = 604800000;
DateTime now = new DateTime();
/**
* When delegate.relative(mockProperty, duration) is called, the current time (now) is calculated and used for the
* end date/time and the start date/time is calculated based on the end date/time and duration (now - duration). Once we
* get the current time (now) in the test, we want to hold the System time fixed so when the current time (now) is retrieved
* in delegate.relative(mockProperty, duration) there is no discrepancy. This allows us to easily assert the begin position and
* end position in the Verify step of this test.
*/
DateTimeUtils.setCurrentMillisFixed(now.getMillis());
String startDate = ISODateTimeFormat.dateTimeNoMillis().withZone(DateTimeZone.UTC)
.print(now.minus(duration));
// Perform Test
FilterType filter = delegate.relative(mockMetacardAttribute, duration);
//Verify
assertThat(filter.getTemporalOps().getName().toString(),
is("{http://www.opengis.net/fes/2.0}During"));
BinaryTemporalOpType binaryTemporalOpType = (BinaryTemporalOpType) filter.getTemporalOps()
.getValue();
assertThat(binaryTemporalOpType.isSetValueReference(), is(true));
assertThat(binaryTemporalOpType.getValueReference(), is(mockFeatureProperty));
assertThat(binaryTemporalOpType.isSetExpression(), is(true));
TimePeriodType timePeriod = (TimePeriodType) binaryTemporalOpType.getExpression()
.getValue();
assertThat(timePeriod.getBeginPosition().getValue().get(0), is(startDate.toString()));
assertThat(timePeriod.getEndPosition().getValue().get(0),
is(ISODateTimeFormat.dateTimeNoMillis().withZone(DateTimeZone.UTC).print(now)));
assertThat(timePeriod.getId(), is(matchesPattern(new PatternMatcher(
sequence(mockFeatureType, ".", oneOrMore(anyCharacterIn("0-9")))))));
// Reset the System time
DateTimeUtils.setCurrentMillisSystem();
}
/**
* Verify that when Feature property "myFeatureProperty" is not defined in the Feature schema as a {http://www.opengis.net/gml/3.2}TimePeriodType
* an IllegalArgumentException is thrown.
*/
@Test(expected = IllegalArgumentException.class)
public void testRelativePropertyIsNotOfTemporalType() throws Throwable {
testSequentialPropertyIsNotOfTemporalType("relative", 604800000L);
}
/**
* Example After filter:
*
* <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
* <ns5:Filter xmlns:ns2="http://www.opengis.net/ows/1.1" xmlns="http://www.opengis.net/fes/2.0" xmlns:ns4="http://www.opengis.net/gml" xmlns:ns3="http://www.w3.org/1999/xlink" xmlns:ns5="http://www.opengis.net/ogc">
* <After>
* <ValueReference>myFeatureProperty</ValueReference>
* <ns4:TimeInstant ns4:id="myFeatureType.1406219647420">
* <ns4:timePosition>2013-07-23T14:02:09.239-07:00</ns4:timePosition>
* </ns4:TimeInstant>
* </After>
* </ns5:Filter>
*/
@Test
public void testAfterPropertyIsOfTemporalType() throws Exception {
testSequentialPropertyIsOfTemporalType("after", "{http://www.opengis.net/fes/2.0}After");
}
/**
* Verify that when Feature property "myFeatureProperty" is not defined in the Feature schema as a {http://www.opengis.net/gml/3.2}TimeInstantType
* an IllegalArgumentException is thrown.
*/
@Test(expected = IllegalArgumentException.class)
public void testAfterPropertyIsNotOfTemporalType() throws Throwable {
testSequentialPropertyIsNotOfTemporalType("after", new DateTime().minusDays(365).toDate());
}
/**
* Example Before filter:
*
* <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
* <ns5:Filter xmlns:ns2="http://www.opengis.net/ows/1.1" xmlns="http://www.opengis.net/fes/2.0" xmlns:ns4="http://www.opengis.net/gml" xmlns:ns3="http://www.w3.org/1999/xlink" xmlns:ns5="http://www.opengis.net/ogc">
* <Before>
* <ValueReference>myFeatureProperty</ValueReference>
* <ns4:TimeInstant ns4:id="myFeatureType.1406219647420">
* <ns4:timePosition>2013-07-23T14:04:50.853-07:00</ns4:timePosition>
* </ns4:TimeInstant>
* </Before>
* </ns5:Filter>
*
*/
@Test
public void testBeforePropertyIsOfTemporalType() throws Exception {
testSequentialPropertyIsOfTemporalType("before", "{http://www.opengis.net/fes/2.0}Before");
}
private void testSequentialPropertyIsOfTemporalType(String methName,
String temporalOpName) throws Exception {
SequentialTestMockHolder sequentialTestMockHolder = new SequentialTestMockHolder().invoke();
WfsFilterDelegate delegate = sequentialTestMockHolder.getDelegate();
String mockMetacardAttribute = sequentialTestMockHolder.getMockMetacardAttribute();
String mockFeatureProperty = sequentialTestMockHolder.getMockFeatureProperty();
String mockFeatureType = sequentialTestMockHolder.getMockFeatureType();
DateTime date = new DateTime().minusDays(365);
// Perform Test
Method method = WfsFilterDelegate.class.getMethod(methName, String.class, Date.class);
FilterType filter = (FilterType) method
.invoke(delegate, mockMetacardAttribute, date.toDate());
//Verify
assertThat(filter.getTemporalOps().getName().toString(), is(temporalOpName));
BinaryTemporalOpType binaryTemporalOpType = (BinaryTemporalOpType) filter.getTemporalOps()
.getValue();
assertThat(binaryTemporalOpType.isSetValueReference(), is(true));
assertThat(binaryTemporalOpType.getValueReference(), is(mockFeatureProperty));
assertThat(binaryTemporalOpType.isSetExpression(), is(true));
TimeInstantType timeInstant = (TimeInstantType) binaryTemporalOpType.getExpression()
.getValue();
assertThat(timeInstant.getTimePosition().getValue().get(0),
is(ISODateTimeFormat.dateTimeNoMillis().withZone(DateTimeZone.UTC).print(date)));
assertThat(timeInstant.getId(), is(matchesPattern(new PatternMatcher(
sequence(mockFeatureType, ".", oneOrMore(anyCharacterIn("0-9")))))));
}
/**
* Verify that when Feature property "myFeatureProperty" is not defined in the Feature schema as a {http://www.opengis.net/gml/3.2}TimeInstantType
* an IllegalArgumentException is thrown.
*/
@Test(expected = IllegalArgumentException.class)
public void testBeforePropertyIsNotOfTemporalType() throws Throwable {
testSequentialPropertyIsNotOfTemporalType("before",
new DateTime().minusDays(365).toDate());
}
private void testSequentialPropertyIsNotOfTemporalType(String methName,
Object... inputParams) throws Throwable {
String mockMetacardAttribute = "myMetacardAttribute";
String mockFeatureType = "myFeatureType";
String mockFeatureProperty = "myFeatureProperty";
List<String> mockProperties = new ArrayList<String>(1);
mockProperties.add(mockFeatureProperty);
when(mockFeatureMetacardType.getProperties()).thenReturn(mockProperties);
when(mockFeatureMetacardType.getName()).thenReturn(mockFeatureType);
List<String> mockTemporalProperties = Collections.emptyList();
when(mockFeatureMetacardType.getTemporalProperties()).thenReturn(mockTemporalProperties);
FeatureAttributeDescriptor mockFeatureAttributeDescriptor = mock(
FeatureAttributeDescriptor.class);
when(mockFeatureAttributeDescriptor.isIndexed()).thenReturn(true);
when(mockFeatureAttributeDescriptor.getPropertyName()).thenReturn(mockFeatureProperty);
when(mockFeatureMetacardType.getAttributeDescriptor(mockFeatureProperty))
.thenReturn(mockFeatureAttributeDescriptor);
MetacardMapper mockMapper = mock(MetacardMapper.class);
when(mockMapper.getFeatureProperty(mockMetacardAttribute)).thenReturn(mockFeatureProperty);
WfsFilterDelegate delegate = new WfsFilterDelegate(mockFeatureMetacardType,
MockWfsServer.getFilterCapabilities(), Wfs20Constants.EPSG_4326_URN, mockMapper,
WfsConstants.LAT_LON_ORDER);
try {
// Inject the mockMetacardAttribute at the head of the array
Object[] methParams = ObjectArrays.concat(mockMetacardAttribute, inputParams);
// Generate the array of class types for the reflection call
Class<?>[] classTypes = FluentIterable.from(Arrays.asList(methParams))
.transform(new Function<Object, Class>() {
@Override
public Class<?> apply(Object o) {
// Autoboxing is a small problem with reflection when trying to be too clever
return (o instanceof Long) ? long.class : o.getClass();
}
}).toArray(Class.class);
Method method = WfsFilterDelegate.class.getMethod(methName, classTypes);
method.invoke(delegate, methParams);
} catch (InvocationTargetException e) {
throw e.getCause();
}
}
@Test
public void testLogicalNotOfComparison() throws Exception {
String mockProperty = "myPropertyName";
String mockType = "myType";
WfsFilterDelegate delegate = mockFeatureMetacardCreateDelegate(mockProperty, mockType);
FilterType filterToBeNoted = delegate.propertyIsLike(Metacard.ANY_TEXT, LITERAL, true);
//Perform Test
FilterType filter = delegate.not(filterToBeNoted);
//Verify
assertThat(filter.getLogicOps().getName().toString(), is(LOGICAL_NOT_NAME));
UnaryLogicOpType logicOpType = (UnaryLogicOpType) filter.getLogicOps().getValue();
PropertyIsLikeType compOpsType1 = (PropertyIsLikeType) logicOpType.getComparisonOps()
.getValue();
String valRef1 = fetchPropertyIsLikeExpression(compOpsType1, VALUE_REFERENCE);
assertThat(valRef1, is(mockProperty));
String literal1 = fetchPropertyIsLikeExpression(compOpsType1, LITERAL);
assertThat(literal1, is(LITERAL));
}
@Test
public void testLogicalOrOfComparisons() throws Exception {
testLogicalAndOrComparison("or", LOGICAL_OR_NAME);
}
@Test
public void testLogicalAndOfComparison() throws Exception {
testLogicalAndOrComparison("and", LOGICAL_AND_NAME);
}
private void testLogicalAndOrComparison(String methName, String compOpName) throws Exception {
String mockProperty = "myPropertyName";
String mockType = "myType";
WfsFilterDelegate delegate = mockFeatureMetacardCreateDelegate(mockProperty, mockType);
FilterType compFilter1 = delegate.propertyIsLike(Metacard.ANY_TEXT, LITERAL, true);
FilterType compFilter2 = delegate.propertyIsLike(Metacard.ANY_TEXT, LITERAL, true);
List<FilterType> filtersToCombine = new ArrayList<FilterType>();
filtersToCombine.add(compFilter1);
filtersToCombine.add(compFilter2);
//Perform Test
Method method = WfsFilterDelegate.class.getMethod(methName, List.class);
FilterType filter = (FilterType) method.invoke(delegate, filtersToCombine);
//Verify
assertThat(filter.getLogicOps().getName().toString(), is(compOpName));
BinaryLogicOpType logicOpType = (BinaryLogicOpType) filter.getLogicOps().getValue();
Assert.assertThat(logicOpType.getComparisonOpsOrSpatialOpsOrTemporalOps().size(), is(2));
for (JAXBElement<?> jaxbElement : logicOpType.getComparisonOpsOrSpatialOpsOrTemporalOps()) {
PropertyIsLikeType compOpsType = (PropertyIsLikeType) jaxbElement.getValue();
String valRef = fetchPropertyIsLikeExpression(compOpsType, VALUE_REFERENCE);
assertThat(valRef, is(mockProperty));
String literal = fetchPropertyIsLikeExpression(compOpsType, LITERAL);
assertThat(literal, is(LITERAL));
}
}
@Test
public void testLogicalNotOfSpatial() throws Exception {
String mockProperty = "myPropertyName";
String mockType = "myType";
WfsFilterDelegate delegate = mockFeatureMetacardCreateDelegate(mockProperty, mockType);
FilterType spatialFilter1 = delegate
.dwithin(Metacard.ANY_GEO, "POINT (30 10)", Double.valueOf(1000));
//Perform Test
FilterType filter = delegate.not(spatialFilter1);
//Verify
assertThat(filter.getLogicOps().getName().toString(), is(LOGICAL_NOT_NAME));
UnaryLogicOpType logicOpType = (UnaryLogicOpType) filter.getLogicOps().getValue();
DistanceBufferType spatialOpsType1 = (DistanceBufferType) logicOpType.getSpatialOps()
.getValue();
assertThat(Double.toString(spatialOpsType1.getDistance().getValue()),
is(Double.valueOf(1000).toString()));
}
@Test
public void testLogicalOrOfSpatial() throws Exception {
testLogicalAndOrSpatial("or", LOGICAL_OR_NAME);
}
@Test
public void testLogicalAndOfSpatial() throws Exception {
testLogicalAndOrSpatial("and", LOGICAL_AND_NAME);
}
private void testLogicalAndOrSpatial(String methName, String compOpName) throws Exception {
String mockProperty = "myPropertyName";
String mockType = "myType";
WfsFilterDelegate delegate = mockFeatureMetacardCreateDelegate(mockProperty, mockType);
FilterType spatialFilter1 = delegate
.dwithin(Metacard.ANY_GEO, "POINT (30 10)", Double.valueOf(1000));
FilterType spatialFilter2 = delegate
.dwithin(Metacard.ANY_GEO, "POINT (50 10)", Double.valueOf(1500));
List<FilterType> filtersToCombine = new ArrayList<FilterType>();
filtersToCombine.add(spatialFilter1);
filtersToCombine.add(spatialFilter2);
//Perform Test
Method method = WfsFilterDelegate.class.getMethod(methName, List.class);
FilterType filter = (FilterType) method.invoke(delegate, filtersToCombine);
//Verify
assertThat(filter.getLogicOps().getName().toString(), is(compOpName));
BinaryLogicOpType logicOpType = (BinaryLogicOpType) filter.getLogicOps().getValue();
DistanceBufferType spatialOpsType1 = (DistanceBufferType) logicOpType
.getComparisonOpsOrSpatialOpsOrTemporalOps().get(0).getValue();
assertThat(Double.toString(spatialOpsType1.getDistance().getValue()),
is(Double.valueOf(1000).toString()));
DistanceBufferType spatialOpsType2 = (DistanceBufferType) logicOpType
.getComparisonOpsOrSpatialOpsOrTemporalOps().get(1).getValue();
assertThat(Double.toString(spatialOpsType2.getDistance().getValue()),
is(Double.valueOf(1500).toString()));
}
/**
* Verifies that a temporal criteria can be AND'ed to other criteria.
*
* @throws Exception
*/
@Test
public void testLogicalAndOfSpatialTemporal() throws Exception {
String mockProperty = "myPropertyName";
String mockType = "myType";
WfsFilterDelegate delegate = mockFeatureMetacardCreateDelegate(mockProperty, mockType);
FilterType spatialFilter = delegate
.dwithin(Metacard.ANY_GEO, "POINT (30 10)", Double.valueOf(1000));
FilterType temporalFilter = delegate
.during(mockProperty, new DateTime().minusDays(365).toDate(),
new DateTime().minusDays(10).toDate());
List<FilterType> filtersToBeAnded = new ArrayList<FilterType>(
Arrays.asList(spatialFilter, temporalFilter));
//Perform Test
FilterType filter = delegate.and(filtersToBeAnded);
//Verify AND op used
if (filter.getLogicOps() == null) {
fail("No AND/OR element found in the generated FilterType.");
}
assertEquals(LOGICAL_AND_NAME, filter.getLogicOps().getName().toString());
BinaryLogicOpType logicOpType = (BinaryLogicOpType) filter.getLogicOps().getValue();
//Verify two items were AND'ed
assertEquals(2, logicOpType.getComparisonOpsOrSpatialOpsOrTemporalOps().size());
//Verify first is spatial, second is temporal
assertTrue(logicOpType.getComparisonOpsOrSpatialOpsOrTemporalOps().get(0)
.getValue() instanceof DistanceBufferType);
assertTrue(logicOpType.getComparisonOpsOrSpatialOpsOrTemporalOps().get(1)
.getValue() instanceof BinaryTemporalOpType);
}
@Test
public void testLogicalOrOfLogicals() throws Exception {
testLogicalCombinationOfLogicals("or", LOGICAL_OR_NAME);
}
@Test
public void testLogicalAndOfLogicals() throws Exception {
testLogicalCombinationOfLogicals("and", LOGICAL_AND_NAME);
}
private void testLogicalCombinationOfLogicals(String methName, String compOpName) throws
Exception {
String mockProperty = "myPropertyName";
String mockType = "myType";
WfsFilterDelegate delegate = mockFeatureMetacardCreateDelegate(mockProperty, mockType);
FilterType compFilter1 = delegate.propertyIsLike(Metacard.ANY_TEXT, LITERAL, true);
FilterType compFilter2 = delegate.propertyIsLike(Metacard.ANY_TEXT, LITERAL, true);
List<FilterType> subFiltersToBeOred = new ArrayList<>();
subFiltersToBeOred.add(compFilter1);
subFiltersToBeOred.add(compFilter2);
FilterType spatialFilter1 = delegate
.dwithin(Metacard.ANY_GEO, "POINT (30 10)", Double.valueOf(1000));
FilterType spatialFilter2 = delegate
.dwithin(Metacard.ANY_GEO, "POINT (50 10)", Double.valueOf(1500));
List<FilterType> subFiltersToBeAnded = new ArrayList<>();
subFiltersToBeAnded.add(spatialFilter1);
subFiltersToBeAnded.add(spatialFilter2);
List<FilterType> filtersToCombine = new ArrayList<>();
filtersToCombine.add(delegate.or(subFiltersToBeOred));
filtersToCombine.add(delegate.and(subFiltersToBeAnded));
Method method = WfsFilterDelegate.class.getMethod(methName, List.class);
FilterType filter = (FilterType) method.invoke(delegate, filtersToCombine);
//Verify
assertThat(filter.getLogicOps().getName().toString(), is(compOpName));
BinaryLogicOpType logicOpType = (BinaryLogicOpType) filter.getLogicOps().getValue();
BinaryLogicOpType logicOrType = (BinaryLogicOpType) logicOpType
.getComparisonOpsOrSpatialOpsOrTemporalOps().get(0).getValue();
assertThat(
logicOpType.getComparisonOpsOrSpatialOpsOrTemporalOps().get(0).getName().toString(),
is(LOGICAL_OR_NAME));
assertThat(logicOrType.getComparisonOpsOrSpatialOpsOrTemporalOps().size(), is(2));
for (JAXBElement<?> jaxbElement : logicOrType.getComparisonOpsOrSpatialOpsOrTemporalOps()) {
PropertyIsLikeType compOpsType = (PropertyIsLikeType) jaxbElement.getValue();
String valRef = fetchPropertyIsLikeExpression(compOpsType, VALUE_REFERENCE);
assertThat(valRef, is(mockProperty));
String literal = fetchPropertyIsLikeExpression(compOpsType, LITERAL);
assertThat(literal, is(LITERAL));
}
BinaryLogicOpType logicAndType = (BinaryLogicOpType) logicOpType
.getComparisonOpsOrSpatialOpsOrTemporalOps().get(1).getValue();
assertThat(
logicOpType.getComparisonOpsOrSpatialOpsOrTemporalOps().get(1).getName().toString(),
is(LOGICAL_AND_NAME));
DistanceBufferType spatialOpsType1 = (DistanceBufferType) logicAndType
.getComparisonOpsOrSpatialOpsOrTemporalOps().get(0).getValue();
assertThat(Double.toString(spatialOpsType1.getDistance().getValue()),
is(Double.valueOf(1000).toString()));
DistanceBufferType spatialOpsType2 = (DistanceBufferType) logicAndType
.getComparisonOpsOrSpatialOpsOrTemporalOps().get(1).getValue();
assertThat(Double.toString(spatialOpsType2.getDistance().getValue()),
is(Double.valueOf(1500).toString()));
}
@Test
public void testLogicalNotOfLogicals() throws Exception {
String mockProperty = "myPropertyName";
String mockType = "myType";
WfsFilterDelegate delegate = mockFeatureMetacardCreateDelegate(mockProperty, mockType);
FilterType compFilter1 = delegate.propertyIsLike(Metacard.ANY_TEXT, LITERAL, true);
FilterType compFilter2 = delegate.propertyIsLike(Metacard.ANY_TEXT, LITERAL, true);
List<FilterType> subFiltersToBeOred = new ArrayList<FilterType>();
subFiltersToBeOred.add(compFilter1);
subFiltersToBeOred.add(compFilter2);
//Perform Test
FilterType filter = delegate.not(delegate.or(subFiltersToBeOred));
//Verify
assertThat(filter.getLogicOps().getName().toString(), is(LOGICAL_NOT_NAME));
UnaryLogicOpType logicOpType = (UnaryLogicOpType) filter.getLogicOps().getValue();
BinaryLogicOpType logicOrType = (BinaryLogicOpType) logicOpType.getLogicOps().getValue();
assertThat(logicOpType.getLogicOps().getName().toString(), is(LOGICAL_OR_NAME));
PropertyIsLikeType compOpsType1 = (PropertyIsLikeType) logicOrType
.getComparisonOpsOrSpatialOpsOrTemporalOps().get(0).getValue();
String valRef1 = fetchPropertyIsLikeExpression(compOpsType1, VALUE_REFERENCE);
assertThat(valRef1, is(mockProperty));
String literal1 = fetchPropertyIsLikeExpression(compOpsType1, LITERAL);
assertThat(literal1, is(LITERAL));
PropertyIsLikeType compOpsType2 = (PropertyIsLikeType) logicOrType
.getComparisonOpsOrSpatialOpsOrTemporalOps().get(1).getValue();
String valRef2 = fetchPropertyIsLikeExpression(compOpsType2, VALUE_REFERENCE);
assertThat(valRef2, is(mockProperty));
String literal2 = fetchPropertyIsLikeExpression(compOpsType2, LITERAL);
assertThat(literal2, is(LITERAL));
}
@Test
public void testLogicalOrOneItem() throws Exception {
testLogicalCombinatorsOneItem("or");
}
@Test
public void testLogicalAndOneItem() throws Exception {
testLogicalCombinatorsOneItem("and");
}
private void testLogicalCombinatorsOneItem(String methName) throws Exception {
String mockProperty = "myPropertyName";
String mockType = "myType";
WfsFilterDelegate delegate = mockFeatureMetacardCreateDelegate(mockProperty, mockType);
FilterType compFilter1 = delegate.propertyIsLike(Metacard.ANY_TEXT, LITERAL, true);
List<FilterType> filtersToCombine = new ArrayList<FilterType>();
filtersToCombine.add(compFilter1);
Method method = WfsFilterDelegate.class.getMethod(methName, List.class);
FilterType filter = (FilterType) method.invoke(delegate, filtersToCombine);
// Only one filter was provided to combinator so only that filter is returned as not
// enough filters to combine together
assertNull(filter.getLogicOps());
PropertyIsLikeType compOpsType1 = (PropertyIsLikeType) filter.getComparisonOps().getValue();
String valRef1 = fetchPropertyIsLikeExpression(compOpsType1, VALUE_REFERENCE);
assertThat(valRef1, is(mockProperty));
String literal1 = fetchPropertyIsLikeExpression(compOpsType1, LITERAL);
assertThat(literal1, is(LITERAL));
}
@Test
public void testLogicalWithNullOrEmpty() throws Exception {
String mockProperty = "myPropertyName";
String mockType = "myType";
WfsFilterDelegate delegate = mockFeatureMetacardCreateDelegate(mockProperty, mockType);
// Test with null list/entry
FilterType filter = delegate.and(null);
assertNull(filter);
filter = delegate.not(null);
assertNull(filter);
// Test with empty list
List<FilterType> filtersToBeCombined = new ArrayList<>();
filter = delegate.and(filtersToBeCombined);
assertNull(filter);
filter = delegate.or(filtersToBeCombined);
assertNull(filter);
// Test with list with null entries
filtersToBeCombined.add(null);
filtersToBeCombined.add(null);
filter = delegate.and(filtersToBeCombined);
assertNull(filter);
filter = delegate.or(filtersToBeCombined);
assertNull(filter);
// Finally, test a null list with an or
thrown.expect(NullPointerException.class);
filter = delegate.or(null);
}
@Test(expected = UnsupportedOperationException.class)
public void testLogicalAndNoLogicalSupport() throws Exception {
WfsFilterDelegate delegate = makeDelegateForLogicalSupportTests();
FilterType compFilter1 = delegate.propertyIsLike(Metacard.ANY_TEXT, LITERAL, true);
FilterType compFilter2 = delegate.propertyIsLike(Metacard.ANY_TEXT, LITERAL, true);
List<FilterType> filtersToBeAnded = new ArrayList<FilterType>();
filtersToBeAnded.add(compFilter1);
filtersToBeAnded.add(compFilter2);
//Perform Test
FilterType filter = delegate.and(filtersToBeAnded);
}
@Test(expected = UnsupportedOperationException.class)
public void testLogicalOrNoLogicalSupport() throws Exception {
WfsFilterDelegate delegate = makeDelegateForLogicalSupportTests();
FilterType compFilter1 = delegate.propertyIsLike(Metacard.ANY_TEXT, LITERAL, true);
FilterType compFilter2 = delegate.propertyIsLike(Metacard.ANY_TEXT, LITERAL, true);
List<FilterType> filtersToBeOred = new ArrayList<FilterType>();
filtersToBeOred.add(compFilter1);
filtersToBeOred.add(compFilter2);
//Perform Test
FilterType filter = delegate.or(filtersToBeOred);
}
@Test(expected = UnsupportedOperationException.class)
public void testLogicalNotNoLogicalSupport() throws Exception {
WfsFilterDelegate delegate = makeDelegateForLogicalSupportTests();
FilterType filterToBeNoted = delegate.propertyIsLike(Metacard.ANY_TEXT, LITERAL, true);
//Perform Test
FilterType filter = delegate.not(filterToBeNoted);
}
private WfsFilterDelegate makeDelegateForLogicalSupportTests() throws Exception {
String mockProperty = "myPropertyName";
String mockType = "myType";
List<String> mockProperties = new ArrayList<String>(1);
mockProperties.add(mockProperty);
when(mockFeatureMetacardType.getProperties()).thenReturn(mockProperties);
when(mockFeatureMetacardType.getGmlProperties()).thenReturn(mockProperties);
when(mockFeatureMetacardType.getTextualProperties()).thenReturn(mockProperties);
when(mockFeatureMetacardType.getTemporalProperties()).thenReturn(mockProperties);
when(mockFeatureMetacardType.getName()).thenReturn(mockType);
FeatureAttributeDescriptor mockFeatureAttributeDescriptor = mock(
FeatureAttributeDescriptor.class);
when(mockFeatureAttributeDescriptor.isIndexed()).thenReturn(true);
when(mockFeatureAttributeDescriptor.getPropertyName()).thenReturn(mockProperty);
when(mockFeatureMetacardType.getAttributeDescriptor(mockProperty))
.thenReturn(mockFeatureAttributeDescriptor);
FilterCapabilities filterCap = MockWfsServer.getFilterCapabilities();
//Create new ScalarCapabiltiesType without Logical Operator support
ScalarCapabilitiesType scalar = new ScalarCapabilitiesType();
scalar.setComparisonOperators(new ComparisonOperatorsType());
for (COMPARISON_OPERATORS compOp : COMPARISON_OPERATORS.values()) {
ComparisonOperatorType operator = new ComparisonOperatorType();
operator.setName(compOp.toString());
scalar.getComparisonOperators().getComparisonOperator().add(operator);
}
filterCap.setScalarCapabilities(scalar);
return new WfsFilterDelegate(mockFeatureMetacardType, filterCap,
Wfs20Constants.EPSG_4326_URN, null, WfsConstants.LAT_LON_ORDER);
}
@Test
public void testFeatureID() throws Exception {
String mockProperty = "myPropertyName";
String mockType = "myType";
WfsFilterDelegate delegate = mockFeatureMetacardCreateDelegate(mockProperty, mockType);
String featureId = "1234567";
//Perform Test
FilterType matchIdFilter = delegate.propertyIsLike(Metacard.ID, featureId, true);
//Verify
assertThat(((ResourceIdType) matchIdFilter.getId().get(0).getValue()).getRid(),
is(featureId));
}
@Test
public void testFeatureTypeFeatureID() throws Exception {
String mockProperty = "myPropertyName";
String mockType = "myType";
WfsFilterDelegate delegate = mockFeatureMetacardCreateDelegate(mockProperty, mockType);
String featureId = "1234567";
String mockTypeFeatureId = mockType + "." + featureId;
//Perform Test
FilterType matchIdFilter = delegate.propertyIsEqualTo(Metacard.ID, mockTypeFeatureId, true);
//Verify
assertThat(((ResourceIdType) matchIdFilter.getId().get(0).getValue()).getRid(),
is(mockTypeFeatureId));
}
@Test
public void testInvalidFeatureTypeFeatureID() throws Exception {
String mockProperty = "myPropertyName";
String mockType = "myType";
WfsFilterDelegate delegate = mockFeatureMetacardCreateDelegate(mockProperty, mockType);
String nonExistentType = "myBadType";
String featureId = "1234567";
String mockTypeFeatureId = nonExistentType + "." + featureId;
//Perform Test
FilterType matchIdFilter = delegate.propertyIsEqualTo(Metacard.ID, mockTypeFeatureId, true);
assertNull(matchIdFilter);
}
private WfsFilterDelegate setupFilterDelegate(String spatialOpType) {
List<String> gmlProps = new ArrayList<String>();
gmlProps.add(MOCK_GEOM);
when(mockFeatureMetacardType.getGmlProperties()).thenReturn(gmlProps);
when(mockFeatureMetacardType.getAttributeDescriptor(MOCK_GEOM)).thenReturn(
new FeatureAttributeDescriptor(MOCK_GEOM, MOCK_GEOM, true, false, false, false,
BasicTypes.STRING_TYPE));
SpatialOperatorType operator = new SpatialOperatorType();
operator.setName(spatialOpType.toString());
FilterCapabilities capabilities = MockWfsServer.getFilterCapabilities();
capabilities.getSpatialCapabilities().getSpatialOperators().getSpatialOperator().clear();
capabilities.getSpatialCapabilities().getSpatialOperators().getSpatialOperator()
.add(operator);
return new WfsFilterDelegate(mockFeatureMetacardType, capabilities,
Wfs20Constants.EPSG_4326_URN, null, WfsConstants.LAT_LON_ORDER);
}
@Test
public void testBeyondFilter() throws JAXBException, SAXException, IOException {
WfsFilterDelegate delegate = setupFilterDelegate(SPATIAL_OPERATORS.Beyond.toString());
FilterType filter = delegate.beyond(Metacard.ANY_GEO, POLYGON, DISTANCE);
assertTrue(filter.isSetSpatialOps());
assertTrue(filter.getSpatialOps().getValue() instanceof DistanceBufferType);
assertXMLEqual(MockWfsServer.getBeyondXmlFilter(), getXmlFromMarshaller(filter));
}
@Test
public void testBeyondAsNotDwithin() {
WfsFilterDelegate delegate = setupFilterDelegate(SPATIAL_OPERATORS.DWithin.toString());
FilterType filter = delegate.beyond(Metacard.ANY_GEO, POLYGON, DISTANCE);
assertTrue(filter.getLogicOps().getValue() instanceof UnaryLogicOpType);
UnaryLogicOpType type = (UnaryLogicOpType) filter.getLogicOps().getValue();
assertTrue(type.getSpatialOps().getValue() instanceof DistanceBufferType);
}
@Test
public void testBeyondFilterUnsupported() throws Exception {
testUnsupportedFilterTypeWithDistance("beyond", SPATIAL_OPERATORS.Intersects, DISTANCE);
}
@Test
public void testContainsFilter() throws JAXBException, SAXException, IOException {
WfsFilterDelegate delegate = setupFilterDelegate(SPATIAL_OPERATORS.Contains.toString());
FilterType filter = delegate.contains(Metacard.ANY_GEO, POLYGON);
assertTrue(filter.getSpatialOps().getValue() instanceof BinarySpatialOpType);
assertFalse(filter.isSetLogicOps());
assertXMLEqual(MockWfsServer.getContainsXmlFilter(), getXmlFromMarshaller(filter));
}
@Test
public void testContainsUnsupported() throws Exception {
testUnsupportedFilterType("contains", SPATIAL_OPERATORS.Intersects);
}
@Test
public void testCrossesFilter() throws SAXException, IOException, JAXBException {
WfsFilterDelegate delegate = setupFilterDelegate(SPATIAL_OPERATORS.Crosses.toString());
FilterType filter = delegate.crosses(Metacard.ANY_GEO, LINESTRING);
assertTrue(filter.getSpatialOps().getValue() instanceof BinarySpatialOpType);
assertFalse(filter.isSetLogicOps());
assertXMLEqual(MockWfsServer.getCrossesXmlFilter(), getXmlFromMarshaller(filter));
}
@Test
public void testCrossesUnsupported() throws Exception {
testUnsupportedFilterType("crosses", SPATIAL_OPERATORS.Intersects);
}
@Test
public void testDisjointFilter() throws SAXException, IOException, JAXBException {
WfsFilterDelegate delegate = setupFilterDelegate(SPATIAL_OPERATORS.Disjoint.toString());
FilterType filter = delegate.disjoint(Metacard.ANY_GEO, POLYGON);
assertTrue(filter.getSpatialOps().getValue() instanceof BinarySpatialOpType);
assertXMLEqual(MockWfsServer.getDisjointXmlFilter(), getXmlFromMarshaller(filter));
}
@Test
public void testDisjointAsNotBBox() throws SAXException, IOException, JAXBException {
WfsFilterDelegate delegate = setupFilterDelegate(SPATIAL_OPERATORS.BBOX.toString());
FilterType filter = delegate.disjoint(Metacard.ANY_GEO, POLYGON);
assertTrue(filter.getLogicOps().getValue() instanceof UnaryLogicOpType);
UnaryLogicOpType type = (UnaryLogicOpType) filter.getLogicOps().getValue();
assertTrue(type.getSpatialOps().getValue() instanceof BBOXType);
assertXMLEqual(MockWfsServer.getNotBboxXmlFilter(), getXmlFromMarshaller(filter));
}
@Test
public void testDisjointAsNotIntersects() throws SAXException, IOException, JAXBException {
WfsFilterDelegate delegate = setupFilterDelegate(SPATIAL_OPERATORS.Intersects.toString());
FilterType filter = delegate.disjoint(Metacard.ANY_GEO, POLYGON);
assertTrue(filter.getLogicOps().getValue() instanceof UnaryLogicOpType);
UnaryLogicOpType type = (UnaryLogicOpType) filter.getLogicOps().getValue();
assertTrue(type.getSpatialOps().getValue() instanceof BinarySpatialOpType);
assertXMLEqual(MockWfsServer.getNotIntersectsXmlFilter(), getXmlFromMarshaller(filter));
}
@Test
public void testDWithinFilterPolygon() throws SAXException, IOException, JAXBException {
WfsFilterDelegate delegate = setupFilterDelegate(SPATIAL_OPERATORS.DWithin.toString());
FilterType filter = delegate.dwithin(Metacard.ANY_GEO, POLYGON, DISTANCE);
assertFalse(filter.isSetLogicOps());
assertTrue(filter.isSetSpatialOps());
assertTrue(filter.getSpatialOps().getValue() instanceof DistanceBufferType);
assertXMLEqual(MockWfsServer.getDWithinXmlFilter(), getXmlFromMarshaller(filter));
}
@Test
public void testDWithinFilterPoint() throws SAXException, IOException, JAXBException {
WfsFilterDelegate delegate = setupFilterDelegate(SPATIAL_OPERATORS.DWithin.toString());
FilterType filter = delegate.dwithin(Metacard.ANY_GEO, POINT, DISTANCE);
assertFalse(filter.isSetLogicOps());
assertTrue(filter.isSetSpatialOps());
assertTrue(filter.getSpatialOps().getValue() instanceof DistanceBufferType);
assertXMLEqual(MockWfsServer.getDWithinPointXmlFilter(), getXmlFromMarshaller(filter));
}
@Test
public void testDwithinAsNotBeyond() {
WfsFilterDelegate delegate = setupFilterDelegate(SPATIAL_OPERATORS.Beyond.toString());
FilterType filter = delegate.dwithin(Metacard.ANY_GEO, POLYGON, DISTANCE);
assertTrue(filter.getLogicOps().getValue() instanceof UnaryLogicOpType);
UnaryLogicOpType type = (UnaryLogicOpType) filter.getLogicOps().getValue();
assertTrue(type.getSpatialOps().getValue() instanceof DistanceBufferType);
}
/**
* From the Search UI, point-radius uses dwithin. We want dwithin to fallback to intersects as a
* last resort. We buffer the geometry (the point) by the radius and do an intersects.
*/
@Test
public void testDwithinAsIntersects() throws JAXBException, SAXException, IOException {
WfsFilterDelegate delegate = setupFilterDelegate(SPATIAL_OPERATORS.Intersects.toString());
/**
* Made distance a large value so if the original WKT and the buffered WKT are plotted at:
* http://openlayers.org/dev/examples/vector-formats.html one can easily see the buffer.
*/
double distance = 200000.0;
FilterType filter = delegate.dwithin(Metacard.ANY_GEO, POINT, distance);
String xml = getXmlFromMarshaller(filter);
assertXMLEqual(MockWfsServer.getDWithinAsIntersectsXml(), xml);
}
@Test
public void testDwithinUnsupported() throws Exception {
testUnsupportedFilterTypeWithDistance("dwithin", SPATIAL_OPERATORS.Contains, DISTANCE);
}
@Test
public void testIntersects() throws SAXException, IOException, JAXBException {
WfsFilterDelegate delegate = setupFilterDelegate(SPATIAL_OPERATORS.Intersects.toString());
FilterType filter = delegate.intersects(Metacard.ANY_GEO, POLYGON);
assertTrue(filter.getSpatialOps().getValue() instanceof BinarySpatialOpType);
assertFalse(filter.isSetLogicOps());
assertXMLEqual(MockWfsServer.getIntersectsXmlFilter(), getXmlFromMarshaller(filter));
}
@Test
public void testIntersectsWithEnvelope() throws SAXException, IOException, JAXBException {
List<String> gmlProps = new ArrayList<String>();
gmlProps.add(MOCK_GEOM);
when(mockFeatureMetacardType.getGmlProperties()).thenReturn(gmlProps);
when(mockFeatureMetacardType.getAttributeDescriptor(MOCK_GEOM)).thenReturn(
new FeatureAttributeDescriptor(MOCK_GEOM, MOCK_GEOM, true, false, false, false,
BasicTypes.STRING_TYPE));
SpatialOperatorType operator = new SpatialOperatorType();
operator.setName(SPATIAL_OPERATORS.Intersects.toString());
FilterCapabilities capabilities = MockWfsServer.getFilterCapabilities();
capabilities.getSpatialCapabilities().getSpatialOperators().getSpatialOperator().clear();
capabilities.getSpatialCapabilities().getSpatialOperators().getSpatialOperator()
.add(operator);
capabilities.getSpatialCapabilities().getGeometryOperands().getGeometryOperand().clear();
GeometryOperand geoOperand = new GeometryOperand();
geoOperand.setName(Wfs20Constants.ENVELOPE);
capabilities.getSpatialCapabilities().getGeometryOperands().getGeometryOperand()
.add(geoOperand);
WfsFilterDelegate delegate = new WfsFilterDelegate(mockFeatureMetacardType, capabilities,
Wfs20Constants.EPSG_4326_URN, null, WfsConstants.LAT_LON_ORDER);
FilterType filter = delegate.intersects(Metacard.ANY_GEO, POLYGON);
assertTrue(filter.getSpatialOps().getValue() instanceof BinarySpatialOpType);
assertFalse(filter.isSetLogicOps());
assertXMLEqual(MockWfsServer.getIntersectsWithEnvelopeXmlFilter(),
getXmlFromMarshaller(filter));
}
@Test
public void testIntersectsLonLat() throws SAXException, IOException, JAXBException {
List<String> gmlProps = new ArrayList<String>();
gmlProps.add(MOCK_GEOM);
when(mockFeatureMetacardType.getGmlProperties()).thenReturn(gmlProps);
when(mockFeatureMetacardType.getAttributeDescriptor(MOCK_GEOM)).thenReturn(
new FeatureAttributeDescriptor(MOCK_GEOM, MOCK_GEOM, true, false, false, false,
BasicTypes.STRING_TYPE));
SpatialOperatorType operator = new SpatialOperatorType();
operator.setName(SPATIAL_OPERATORS.Intersects.toString());
FilterCapabilities capabilities = MockWfsServer.getFilterCapabilities();
capabilities.getSpatialCapabilities().getSpatialOperators().getSpatialOperator().clear();
capabilities.getSpatialCapabilities().getSpatialOperators().getSpatialOperator()
.add(operator);
WfsFilterDelegate delegate = new WfsFilterDelegate(mockFeatureMetacardType, capabilities,
Wfs20Constants.EPSG_4326_URN, null, WfsConstants.LON_LAT_ORDER);
FilterType filter = delegate.intersects(Metacard.ANY_GEO, POLYGON);
assertTrue(filter.getSpatialOps().getValue() instanceof BinarySpatialOpType);
assertFalse(filter.isSetLogicOps());
assertXMLEqual(MockWfsServer.getIntersectsLonLatXmlFilter(), getXmlFromMarshaller(filter));
}
@Test
public void testIntersectsWithEnvelopeLonLat() throws SAXException, IOException, JAXBException {
List<String> gmlProps = new ArrayList<String>();
gmlProps.add(MOCK_GEOM);
when(mockFeatureMetacardType.getGmlProperties()).thenReturn(gmlProps);
when(mockFeatureMetacardType.getAttributeDescriptor(MOCK_GEOM)).thenReturn(
new FeatureAttributeDescriptor(MOCK_GEOM, MOCK_GEOM, true, false, false, false,
BasicTypes.STRING_TYPE));
SpatialOperatorType operator = new SpatialOperatorType();
operator.setName(SPATIAL_OPERATORS.Intersects.toString());
FilterCapabilities capabilities = MockWfsServer.getFilterCapabilities();
capabilities.getSpatialCapabilities().getSpatialOperators().getSpatialOperator().clear();
capabilities.getSpatialCapabilities().getSpatialOperators().getSpatialOperator()
.add(operator);
capabilities.getSpatialCapabilities().getGeometryOperands().getGeometryOperand().clear();
GeometryOperand geoOperand = new GeometryOperand();
geoOperand.setName(Wfs20Constants.ENVELOPE);
capabilities.getSpatialCapabilities().getGeometryOperands().getGeometryOperand()
.add(geoOperand);
WfsFilterDelegate delegate = new WfsFilterDelegate(mockFeatureMetacardType, capabilities,
Wfs20Constants.EPSG_4326_URN, null, WfsConstants.LON_LAT_ORDER);
FilterType filter = delegate.intersects(Metacard.ANY_GEO, POLYGON);
assertTrue(filter.getSpatialOps().getValue() instanceof BinarySpatialOpType);
assertFalse(filter.isSetLogicOps());
assertXMLEqual(MockWfsServer.getIntersectsWithEnvelopeLonLatXmlFilter(),
getXmlFromMarshaller(filter));
}
@Test
public void testIntersectsAsBoundingBox() throws SAXException, IOException, JAXBException {
WfsFilterDelegate delegate = setupFilterDelegate(SPATIAL_OPERATORS.BBOX.toString());
FilterType filter = delegate.intersects(Metacard.ANY_GEO, POLYGON);
assertNotNull(filter);
assertTrue(filter.getSpatialOps().getValue() instanceof BBOXType);
assertFalse(filter.isSetLogicOps());
assertXMLEqual(MockWfsServer.getBboxXmlFilter(), getXmlFromMarshaller(filter));
}
@Test
public void testIntersectsAsNotDisjoint() {
WfsFilterDelegate delegate = setupFilterDelegate(SPATIAL_OPERATORS.Disjoint.toString());
FilterType filter = delegate.intersects(Metacard.ANY_GEO, POLYGON);
assertTrue(filter.isSetLogicOps());
assertTrue(filter.getLogicOps().getValue() instanceof UnaryLogicOpType);
UnaryLogicOpType type = (UnaryLogicOpType) filter.getLogicOps().getValue();
assertTrue(type.isSetSpatialOps());
assertTrue(type.getSpatialOps().getValue() instanceof BinarySpatialOpType);
}
@Test
public void testIntersectsUnsupported() throws Exception {
testUnsupportedFilterType("intersects", SPATIAL_OPERATORS.Contains);
}
@Test
public void testOverlapsFilter() throws Exception {
ImmutableMap<SPATIAL_OPERATORS, String> acceptedSpatialTypes = ImmutableMap
.of(SPATIAL_OPERATORS.Overlaps, MockWfsServer.getOverlapsXmlFilter());
testBinarySpatialFilter(acceptedSpatialTypes, "overlaps");
}
@Test
public void testTouchesFilter() throws Exception {
ImmutableMap<SPATIAL_OPERATORS, String> acceptedSpatialTypes = ImmutableMap
.of(SPATIAL_OPERATORS.Touches, MockWfsServer.getTouchesXmlFilter());
testBinarySpatialFilter(acceptedSpatialTypes, "touches");
}
@Test
public void testWithinFilter() throws Exception {
ImmutableMap<SPATIAL_OPERATORS, String> acceptedSpatialTypes = ImmutableMap
.of(SPATIAL_OPERATORS.Within, MockWfsServer.getWithinXmlFilter(),
SPATIAL_OPERATORS.Contains, MockWfsServer.getContainsXmlFilter());
testBinarySpatialFilter(acceptedSpatialTypes, "within");
}
private void testBinarySpatialFilter(Map<SPATIAL_OPERATORS, String> acceptedSpatialTypes,
String delegateMethodName) throws Exception {
List<SPATIAL_OPERATORS> failTypes = new ArrayList<>(
Arrays.asList(SPATIAL_OPERATORS.values()));
failTypes.removeAll(acceptedSpatialTypes.keySet());
Method spatialOpMeth = WfsFilterDelegate.class
.getMethod(delegateMethodName, String.class, String.class);
for (Map.Entry<SPATIAL_OPERATORS, String> row : acceptedSpatialTypes.entrySet()) {
WfsFilterDelegate delegate = setupFilterDelegate(row.getKey().toString());
FilterType filter = (FilterType) spatialOpMeth
.invoke(delegate, Metacard.ANY_GEO, POLYGON);
assertThat(filter.getSpatialOps().getValue(), instanceOf(BinarySpatialOpType.class));
assertFalse(filter.isSetLogicOps());
assertXMLEqual(row.getValue(), getXmlFromMarshaller(filter));
}
for (SPATIAL_OPERATORS failType : failTypes) {
testUnsupportedFilterType(spatialOpMeth, failType);
}
}
private void testUnsupportedFilterType(String spatialOpMethName,
SPATIAL_OPERATORS failType) throws NoSuchMethodException, InvocationTargetException,
IllegalAccessException {
Method spatialOpMeth = WfsFilterDelegate.class
.getMethod(spatialOpMethName, String.class, String.class);
testUnsupportedFilterType(spatialOpMeth, failType);
}
private void testUnsupportedFilterType(Method spatialOpMeth, SPATIAL_OPERATORS failType) throws
InvocationTargetException, IllegalAccessException {
WfsFilterDelegate delegate = setupFilterDelegate(failType.toString());
FilterType filter = (FilterType) spatialOpMeth.invoke(delegate, Metacard.ANY_GEO, POLYGON);
assertNull(filter);
}
private void testUnsupportedFilterTypeWithDistance(String spatialOpMethName,
SPATIAL_OPERATORS failType, double distance) throws NoSuchMethodException,
InvocationTargetException, IllegalAccessException {
Method spatialOpMeth = WfsFilterDelegate.class
.getMethod(spatialOpMethName, String.class, String.class, double.class);
WfsFilterDelegate delegate = setupFilterDelegate(failType.toString());
FilterType filter = (FilterType) spatialOpMeth
.invoke(delegate, Metacard.ANY_GEO, POLYGON, distance);
assertNull(filter);
}
@Test(expected = IllegalArgumentException.class)
public void testSingleGmlPropertyBlacklisted() {
WfsFilterDelegate delegate = setupFilterDelegate(SPATIAL_OPERATORS.Contains.toString());
when(mockFeatureMetacardType.getAttributeDescriptor(MOCK_GEOM)).thenReturn(
new FeatureAttributeDescriptor(MOCK_GEOM, MOCK_GEOM, false, false, false, false,
BasicTypes.STRING_TYPE));
delegate.contains(MOCK_GEOM, POLYGON);
}
@Test
public void testIntersectsMultipleProperties() {
intersectsMultiple(true);
}
@Test
public void testAllGmlPropertiesBlacklisted() {
intersectsMultiple(false);
}
private void intersectsMultiple(boolean indexed) {
List<String> gmlProps = new ArrayList<String>();
gmlProps.add(MOCK_GEOM);
gmlProps.add(MOCK_GEOM2);
when(mockFeatureMetacardType.getGmlProperties()).thenReturn(gmlProps);
for (String gmlProp : gmlProps) {
when(mockFeatureMetacardType.
getAttributeDescriptor(gmlProp)).
thenReturn(
new FeatureAttributeDescriptor(gmlProp, gmlProp, indexed, false, false,
false, BasicTypes.STRING_TYPE));
}
SpatialOperatorType operator = new SpatialOperatorType();
operator.setName(SPATIAL_OPERATORS.Intersects.toString());
FilterCapabilities capabilities = MockWfsServer.getFilterCapabilities();
capabilities.getSpatialCapabilities().getSpatialOperators().getSpatialOperator().clear();
capabilities.getSpatialCapabilities().getSpatialOperators().getSpatialOperator()
.add(operator);
WfsFilterDelegate delegate = new WfsFilterDelegate(mockFeatureMetacardType, capabilities,
Wfs20Constants.EPSG_4326_URN, null, WfsConstants.LAT_LON_ORDER);
FilterType filter = delegate.intersects(Metacard.ANY_GEO, POLYGON);
if (indexed) {
assertNotNull(filter);
assertTrue(filter.isSetLogicOps());
assertNotNull(filter.getLogicOps());
} else {
assertNull(filter);
}
}
@Test(expected = UnsupportedOperationException.class)
public void testBadPolygonWkt() {
WfsFilterDelegate delegate = setupFilterDelegate(SPATIAL_OPERATORS.Intersects.toString());
delegate.intersects(Metacard.ANY_GEO, "junk");
}
@Test(expected = UnsupportedOperationException.class)
public void testBadPointWkt() {
WfsFilterDelegate delegate = setupFilterDelegate(SPATIAL_OPERATORS.DWithin.toString());
delegate.dwithin(Metacard.ANY_GEO, "junk", DISTANCE);
}
@Test
public void testNonEpsg4326Srs() {
List<String> gmlProps = new ArrayList<String>();
gmlProps.add(MOCK_GEOM);
when(mockFeatureMetacardType.getGmlProperties()).thenReturn(gmlProps);
WfsFilterDelegate delegate = new WfsFilterDelegate(mockFeatureMetacardType,
MockWfsServer.getFilterCapabilities(), "EPSG:42304", null,
WfsConstants.LAT_LON_ORDER);
FilterType filter = delegate.intersects(Metacard.ANY_GEO, POLYGON);
assertTrue(filter == null);
}
@Test(expected = IllegalArgumentException.class)
public void testGeoFilterNullMetacardType() {
WfsFilterDelegate delegate = new WfsFilterDelegate(null,
MockWfsServer.getFilterCapabilities(), Wfs20Constants.EPSG_4326_URN, null,
WfsConstants.LAT_LON_ORDER);
delegate.beyond(Metacard.ANY_GEO, POLYGON, DISTANCE);
}
private String fetchPropertyIsLikeExpression(PropertyIsLikeType compOpsType,
String expressionType) {
String result = null;
List<JAXBElement<?>> expressions = compOpsType.getExpression();
for (int i = 0; i < expressions.size(); ++i) {
String item = expressions.get(i).getName().getLocalPart();
if (item.equals(VALUE_REFERENCE) && item.equals(expressionType)) {
result = expressions.get(i).getValue().toString();
} else if (item.equals(LITERAL) && item.equals(expressionType)) {
LiteralType literal = (LiteralType) expressions.get(i).getValue();
result = literal.getContent().get(0).toString();
}
}
return result;
}
private WfsFilterDelegate mockFeatureMetacardCreateDelegate(String mockProperty,
String mockType) {
List<String> mockProperties = new ArrayList<String>(1);
mockProperties.add(mockProperty);
when(mockFeatureMetacardType.getProperties()).thenReturn(mockProperties);
when(mockFeatureMetacardType.getGmlProperties()).thenReturn(mockProperties);
when(mockFeatureMetacardType.getTextualProperties()).thenReturn(mockProperties);
when(mockFeatureMetacardType.getTemporalProperties()).thenReturn(mockProperties);
when(mockFeatureMetacardType.getName()).thenReturn(mockType);
FeatureAttributeDescriptor mockFeatureAttributeDescriptor = mock(
FeatureAttributeDescriptor.class);
when(mockFeatureAttributeDescriptor.isIndexed()).thenReturn(true);
when(mockFeatureAttributeDescriptor.getPropertyName()).thenReturn(mockProperty);
when(mockFeatureMetacardType.getAttributeDescriptor(mockProperty))
.thenReturn(mockFeatureAttributeDescriptor);
WfsFilterDelegate delegate = new WfsFilterDelegate(mockFeatureMetacardType,
MockWfsServer.getFilterCapabilities(), Wfs20Constants.EPSG_4326_URN, null,
WfsConstants.LAT_LON_ORDER);
return delegate;
}
private String getXmlFromMarshaller(FilterType filterType) throws JAXBException {
JAXBContext jaxbContext = initJaxbContext();
Marshaller marshaller = jaxbContext.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
Writer writer = new StringWriter();
marshaller.marshal(getFilterTypeJaxbElement(filterType), writer);
String xml = writer.toString();
LOGGER.debug("XML returned by Marshaller:\n{}", xml);
LOGGER.trace(Thread.currentThread().getStackTrace().toString());
return xml;
}
private JAXBElement<FilterType> getFilterTypeJaxbElement(FilterType filterType) {
JAXBElement<FilterType> filterTypeJaxbElement = new JAXBElement<FilterType>(
new QName("http://www.opengis.net/ogc", FILTER_QNAME_LOCAL_PART), FilterType.class,
filterType);
return filterTypeJaxbElement;
}
@Test
public void testDuringTemporalFallback() throws Exception {
setupMockMetacardType();
FilterType afterFilter = setupAfterFilterType();
FilterType beforeFilter = setupBeforeFilterType();
FilterCapabilities duringFilterCapabilities = setupFilterCapabilities();
WfsFilterDelegate duringDelegate = new WfsFilterDelegate(mockFeatureMetacardType,
duringFilterCapabilities, Wfs20Constants.EPSG_4326_URN, mockMapper,
WfsConstants.LAT_LON_ORDER);
WfsFilterDelegate spatialDelegate = mockFeatureMetacardCreateDelegate(mockFeatureProperty,
mockFeatureType);
FilterType spatialFilter = spatialDelegate
.dwithin(Metacard.ANY_GEO, "POINT (30 10)", Double.valueOf(1000));
List<List<FilterType>> testFilters = new ArrayList<>();
testFilters.add(Arrays.asList(afterFilter, beforeFilter));
testFilters.add(Arrays.asList(afterFilter, beforeFilter, spatialFilter));
for (List<FilterType> filtersToBeConverted : testFilters) {
List<FilterType> convertedFilters = duringDelegate
.applyTemporalFallbacks(filtersToBeConverted);
FilterType duringFilter = convertedFilters.get(0);
if (filtersToBeConverted.contains(spatialFilter)) {
// verify that results contains the spatial filter type
assertThat(convertedFilters.contains(spatialFilter), is(true));
assertThat(convertedFilters.size(), is(2));
if (duringFilter.isSetSpatialOps()) {
duringFilter = convertedFilters.get(1);
}
//Verify during Filter is correct
assertThat(duringFilter.isSetTemporalOps(), is(true));
}
assertThat(duringFilter.getTemporalOps().getName().toString(),
is("{http://www.opengis.net/fes/2.0}During"));
BinaryTemporalOpType binaryTemporalOpType = (BinaryTemporalOpType) duringFilter
.getTemporalOps().getValue();
assertThat(binaryTemporalOpType.isSetValueReference(), is(true));
assertThat(binaryTemporalOpType.isSetExpression(), is(true));
TimePeriodType timePeriod = (TimePeriodType) binaryTemporalOpType.getExpression()
.getValue();
TimePositionType beginPositionType = timePeriod.getBeginPosition();
Date beginDate = timePositionTypeToDate(beginPositionType);
TimePositionType endPositionType = timePeriod.getEndPosition();
Date endDate = timePositionTypeToDate(endPositionType);
// Verify Date range is created correctly
assertThat(endDate.after(beginDate), is(true));
}
}
@Test
public void testDuringFilterTypeDates() throws Exception {
setupMockMetacardType();
FilterType duringFilter = setupDuringFilterType();
BinaryTemporalOpType binaryTemporalOpType = (BinaryTemporalOpType) duringFilter
.getTemporalOps().getValue();
assertThat(binaryTemporalOpType.isSetValueReference(), is(true));
assertThat(binaryTemporalOpType.isSetExpression(), is(true));
TimePeriodType timePeriod = (TimePeriodType) binaryTemporalOpType.getExpression()
.getValue();
TimePositionType beginPositionType = timePeriod.getBeginPosition();
Date beginDate = timePositionTypeToDate(beginPositionType);
TimePositionType endPositionType = timePeriod.getEndPosition();
Date endDate = timePositionTypeToDate(endPositionType);
assertThat(endDate.after(beginDate), is(true));
}
@Test
public void testIsInFilterSequenceType() throws Exception {
setupMockMetacardType();
FilterType beforeFilter = setupBeforeFilterType();
FilterType afterFilter = setupAfterFilterType();
FilterType duringFilter = setupDuringFilterType();
WfsFilterDelegate afterDelegate = setupTemporalFilterDelegate();
WfsFilterDelegate beforeDelegate = setupTemporalFilterDelegate();
// Test is before filter type
assertThat(beforeDelegate.isBeforeFilter(beforeFilter), is(true));
assertThat(beforeDelegate.isBeforeFilter(afterFilter), is(false));
assertThat(beforeDelegate.isBeforeFilter(duringFilter), is(false));
// Test is during filter type
assertThat(afterDelegate.isDuringFilter(duringFilter), is(true));
assertThat(afterDelegate.isDuringFilter(beforeFilter), is(false));
assertThat(afterDelegate.isDuringFilter(afterFilter), is(false));
// Test is after filter type
assertThat(afterDelegate.isAfterFilter(afterFilter), is(true));
assertThat(afterDelegate.isAfterFilter(beforeFilter), is(false));
assertThat(afterDelegate.isBeforeFilter(duringFilter), is(false));
}
private WfsFilterDelegate setupTemporalFilterDelegate() {
MetacardMapper mockMapper = mock(MetacardMapper.class);
return new WfsFilterDelegate(mockFeatureMetacardType, MockWfsServer.getFilterCapabilities(),
Wfs20Constants.EPSG_4326_URN, mockMapper, WfsConstants.LAT_LON_ORDER);
}
private void setupMockMetacardType() {
mockMetacardAttribute = "modified";
mockFeatureType = "myFeatureType";
mockFeatureProperty = "localpart.EXACT_COLLECT_DATE";
List<String> mockProperties = new ArrayList<>(1);
mockProperties.add(mockFeatureProperty);
QName localName = new QName("EXACT_COLLECT_DATE", "localpart");
when(mockFeatureMetacardType.getFeatureType()).thenReturn(localName);
when(mockFeatureMetacardType.getProperties()).thenReturn(mockProperties);
when(mockFeatureMetacardType.getName()).thenReturn(mockFeatureType);
when(mockFeatureMetacardType.getTemporalProperties()).thenReturn(mockProperties);
FeatureAttributeDescriptor mockFeatureAttributeDescriptor = mock(
FeatureAttributeDescriptor.class);
when(mockFeatureAttributeDescriptor.isIndexed()).thenReturn(true);
when(mockFeatureAttributeDescriptor.getPropertyName()).thenReturn("EXACT_COLLECT_DATE");
when(mockFeatureMetacardType.getAttributeDescriptor(mockFeatureProperty))
.thenReturn(mockFeatureAttributeDescriptor);
mockMapper = mock(MetacardMapper.class);
when(mockMapper.getFeatureProperty(mockMetacardAttribute))
.thenReturn(mockFeatureProperty);
}
private FilterType setupBeforeFilterType() {
WfsFilterDelegate beforeDelegate = new WfsFilterDelegate(mockFeatureMetacardType,
MockWfsServer.getFilterCapabilities(), Wfs20Constants.EPSG_4326_URN, mockMapper,
WfsConstants.LAT_LON_ORDER);
DateTime beforeDate = new DateTime().minusDays(1);
return beforeDelegate.before(mockMetacardAttribute, beforeDate.toDate());
}
private FilterType setupAfterFilterType() {
WfsFilterDelegate delegate = new WfsFilterDelegate(mockFeatureMetacardType,
MockWfsServer.getFilterCapabilities(), Wfs20Constants.EPSG_4326_URN, mockMapper,
WfsConstants.LAT_LON_ORDER);
DateTime afterDate = new DateTime().minusDays(30);
return delegate.after(mockMetacardAttribute, afterDate.toDate());
}
private FilterType setupDuringFilterType() {
WfsFilterDelegate delegate = new WfsFilterDelegate(mockFeatureMetacardType,
MockWfsServer.getFilterCapabilities(), Wfs20Constants.EPSG_4326_URN, mockMapper,
WfsConstants.LAT_LON_ORDER);
DateTime startDate = new DateTime(2014, 01, 01, 01, 01, 01, 123,
DateTimeZone.forID("-07:00"));
DateTime endDate = new DateTime(2014, 01, 02, 01, 01, 01, 123,
DateTimeZone.forID("-07:00"));
return delegate.during(mockMetacardAttribute, startDate.toDate(), endDate.toDate());
}
private Date timePositionTypeToDate(TimePositionType timePositionType) {
Date date = new Date();
try {
List<String> timeList = timePositionType.getValue();
String dateTimeString = timeList.get(0);
DateFormat format = new SimpleDateFormat(
"yyyy-MM-dd'T'HH:mm:ss"); // 2014-12-14T17:14:43Z
date = format.parse(dateTimeString);
} catch (ParseException pe) {
LOGGER.debug("Parse Exception {}", pe);
}
return date;
}
private FilterCapabilities setupFilterCapabilities() {
FilterCapabilities filterCapabilities = new FilterCapabilities();
TemporalCapabilitiesType temporal = new TemporalCapabilitiesType();
temporal.setTemporalOperators(new TemporalOperatorsType());
TemporalOperatorType duringOperator = new TemporalOperatorType();
duringOperator.setName(TEMPORAL_OPERATORS.During.name());
temporal.getTemporalOperators().getTemporalOperator().add(duringOperator);
TemporalOperandsType temporalOperands = new TemporalOperandsType();
List<QName> timeQNames = Arrays
.asList(new QName(Wfs20Constants.GML_3_2_NAMESPACE, "TimePeriod"),
new QName(Wfs20Constants.GML_3_2_NAMESPACE, "TimeInstant"));
for (QName qName : timeQNames) {
TemporalOperandsType.TemporalOperand operand = new TemporalOperandsType.TemporalOperand();
operand.setName(qName);
temporalOperands.getTemporalOperand().add(operand);
}
temporal.setTemporalOperands(temporalOperands);
filterCapabilities.setTemporalCapabilities(temporal);
return filterCapabilities;
}
private class SequentialTestMockHolder {
private String mockMetacardAttribute;
private String mockFeatureType;
private String mockFeatureProperty;
private WfsFilterDelegate delegate;
public String getMockMetacardAttribute() {
return mockMetacardAttribute;
}
public String getMockFeatureType() {
return mockFeatureType;
}
public String getMockFeatureProperty() {
return mockFeatureProperty;
}
public WfsFilterDelegate getDelegate() {
return delegate;
}
public SequentialTestMockHolder invoke() {
mockMetacardAttribute = "myMetacardAttribute";
mockFeatureType = "myFeatureType";
mockFeatureProperty = "myFeatureProperty";
List<String> mockProperties = new ArrayList<String>(1);
mockProperties.add(mockFeatureProperty);
when(mockFeatureMetacardType.getProperties()).thenReturn(mockProperties);
when(mockFeatureMetacardType.getName()).thenReturn(mockFeatureType);
when(mockFeatureMetacardType.getTemporalProperties()).thenReturn(mockProperties);
FeatureAttributeDescriptor mockFeatureAttributeDescriptor = mock(
FeatureAttributeDescriptor.class);
when(mockFeatureAttributeDescriptor.isIndexed()).thenReturn(true);
when(mockFeatureAttributeDescriptor.getPropertyName()).thenReturn(mockFeatureProperty);
when(mockFeatureMetacardType.getAttributeDescriptor(mockFeatureProperty))
.thenReturn(mockFeatureAttributeDescriptor);
MetacardMapper mockMapper = mock(MetacardMapper.class);
when(mockMapper.getFeatureProperty(mockMetacardAttribute))
.thenReturn(mockFeatureProperty);
delegate = new WfsFilterDelegate(mockFeatureMetacardType,
MockWfsServer.getFilterCapabilities(), Wfs20Constants.EPSG_4326_URN, mockMapper,
WfsConstants.LAT_LON_ORDER);
return this;
}
}
}