/** * 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.csw.catalog.source; import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.nullValue; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.Matchers.any; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Dictionary; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import javax.xml.bind.JAXBException; import javax.xml.datatype.DatatypeConfigurationException; import javax.xml.namespace.QName; import org.codice.ddf.spatial.ogc.csw.catalog.common.CswConstants; import org.codice.ddf.spatial.ogc.csw.catalog.common.CswException; import org.codice.ddf.spatial.ogc.csw.catalog.common.CswRecordCollection; import org.codice.ddf.spatial.ogc.csw.catalog.common.CswRecordMetacardType; import org.codice.ddf.spatial.ogc.csw.catalog.common.CswSourceConfiguration; import org.codice.ddf.spatial.ogc.csw.catalog.common.GetCapabilitiesRequest; import org.codice.ddf.spatial.ogc.csw.catalog.converter.CswTransformProvider; import org.geotools.filter.FilterFactoryImpl; import org.joda.time.DateTime; import org.joda.time.format.DateTimeFormatter; import org.joda.time.format.ISODateTimeFormat; import org.junit.Assert; import org.junit.Test; import org.mockito.ArgumentCaptor; import org.mockito.Matchers; import org.opengis.filter.Filter; import org.opengis.filter.FilterFactory; import org.opengis.filter.sort.SortBy; import org.opengis.filter.sort.SortOrder; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceReference; import org.osgi.framework.ServiceRegistration; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.xml.sax.SAXException; import ddf.catalog.data.ContentType; import ddf.catalog.data.Metacard; import ddf.catalog.data.MetacardType; import ddf.catalog.data.Result; import ddf.catalog.filter.impl.SortByImpl; import ddf.catalog.filter.proxy.adapter.GeotoolsFilterAdapterImpl; import ddf.catalog.operation.SourceResponse; import ddf.catalog.operation.impl.QueryImpl; import ddf.catalog.operation.impl.QueryRequestImpl; import ddf.catalog.source.UnsupportedQueryException; import net.opengis.cat.csw.v_2_0_2.CapabilitiesType; import net.opengis.cat.csw.v_2_0_2.GetRecordsType; import net.opengis.cat.csw.v_2_0_2.QueryType; import net.opengis.filter.v_1_1_0.SortOrderType; public class TestCswSource extends TestCswSourceBase { private static final Logger LOGGER = LoggerFactory.getLogger(TestCswSource.class); private CswTransformProvider mockProvider = mock(CswTransformProvider.class); private static final String CSW_RECORD_QNAME = "{" + CswConstants.CSW_OUTPUT_SCHEMA + "}" + CswConstants.CSW_RECORD_LOCAL_NAME; @Test public void testParseCapabilities() throws CswException { CswSource source = getCswSource(createRemoteCsw(), mockContext, new ArrayList<String>()); assertTrue(source.isAvailable()); assertEquals(10, source.getContentTypes().size()); Set<ContentType> expected = generateContentType( Arrays.asList("a", "b", "c", "d", "e", "f", "g", "h", "i", "j")); assertThat(source.getContentTypes(), is(expected)); } @Test public void testInitialContentList() throws CswException { CswSource source = getCswSource(createRemoteCsw(), mockContext, Arrays.asList("x", "y")); assertTrue(source.isAvailable()); assertEquals(12, source.getContentTypes().size()); Set<ContentType> expected = generateContentType( Arrays.asList("a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "x", "y")); assertThat(source.getContentTypes(), is(expected)); } @Test public void testAddingContentTypesOnQueries() throws CswException, UnsupportedQueryException { RemoteCsw remote = createRemoteCsw(); List<String> expectedNames = new LinkedList<String>( Arrays.asList("a", "b", "c", "d", "e", "f", "g", "h", "i", "j")); ServiceRegistration<?> mockRegisteredMetacardType = (ServiceRegistration<?>) mock( ServiceRegistration.class); LOGGER.info("mockRegisteredMetacardType: {}", mockRegisteredMetacardType); doReturn(mockRegisteredMetacardType).when(mockContext) .registerService(eq(MetacardType.class.getName()), any(CswRecordMetacardType.class), Matchers.<Dictionary<String, ?>>any()); ServiceReference<?> mockServiceReference = (ServiceReference<?>) mock( ServiceReference.class); doReturn(mockServiceReference).when(mockRegisteredMetacardType).getReference(); when(mockServiceReference.getProperty(eq(Metacard.CONTENT_TYPE))).thenReturn(expectedNames); CswSource source = getCswSource(remote, mockContext, new ArrayList<String>()); assertEquals(10, source.getContentTypes().size()); Set<ContentType> expected = generateContentType(expectedNames); assertThat(source.getContentTypes(), is(expected)); CswRecordCollection collection = generateCswCollection("/getRecordsResponse.xml"); when(remote.getRecords(any(GetRecordsType.class))).thenReturn(collection); QueryImpl propertyIsLikeQuery = new QueryImpl( builder.attribute(Metacard.ANY_TEXT).is().like().text("*")); expectedNames.add("dataset"); expectedNames.add("dataset 2"); expected = generateContentType(expectedNames); source.query(new QueryRequestImpl(propertyIsLikeQuery)); assertEquals(12, source.getContentTypes().size()); assertThat(source.getContentTypes(), is(expected)); } @Test public void testPropertyIsLikeQuery() throws JAXBException, UnsupportedQueryException, DatatypeConfigurationException, SAXException, IOException { // Setup final String searchPhrase = "*th*e"; final int pageSize = 10; final int numRecordsReturned = 1; final long numRecordsMatched = 10; setupMockContextForMetacardTypeRegistrationAndUnregistration(getDefaultContentTypes()); try { configureMockRemoteCsw(numRecordsReturned, numRecordsMatched, CswConstants.VERSION_2_0_2); } catch (CswException e) { fail("Could not configure Mock Remote CSW: " + e.getMessage()); } QueryImpl propertyIsLikeQuery = new QueryImpl( builder.attribute(Metacard.ANY_TEXT).is().like().text(searchPhrase)); propertyIsLikeQuery.setPageSize(pageSize); CswSource cswSource = getCswSource(mockCsw, mockContext, new LinkedList<String>()); cswSource.setCswUrl(URL); cswSource.setId(ID); // Perform test SourceResponse response = cswSource.query(new QueryRequestImpl(propertyIsLikeQuery)); // Verify Assert.assertNotNull(response); assertThat(response.getResults().size(), is(numRecordsReturned)); assertThat(response.getHits(), is(numRecordsMatched)); ArgumentCaptor<GetRecordsType> captor = ArgumentCaptor.forClass(GetRecordsType.class); try { verify(mockCsw, atLeastOnce()).getRecords(captor.capture()); } catch (CswException e) { fail("Could not verify mock CSW record count: " + e.getMessage()); } GetRecordsType getRecordsType = captor.getValue(); String xml = getGetRecordsTypeAsXml(getRecordsType, CswConstants.VERSION_2_0_2); LOGGER.debug(xml); assertXMLEqual(xml, getRecordsControlXml202); } @Test public void testQueryWithSorting() throws JAXBException, UnsupportedQueryException, DatatypeConfigurationException, SAXException, IOException { final String TITLE = "title"; // Setup final String searchPhrase = "*"; final int pageSize = 1; final int numRecordsReturned = 1; final long numRecordsMatched = 1; setupMockContextForMetacardTypeRegistrationAndUnregistration(getDefaultContentTypes()); try { configureMockRemoteCsw(numRecordsReturned, numRecordsMatched, CswConstants.VERSION_2_0_2); } catch (CswException e) { fail("Could not configure Mock Remote CSW: " + e.getMessage()); } QueryImpl query = new QueryImpl( builder.attribute(Metacard.ANY_TEXT).is().like().text(searchPhrase)); query.setPageSize(pageSize); SortBy sortBy = new SortByImpl(TITLE, SortOrder.DESCENDING); query.setSortBy(sortBy); CswSource cswSource = getCswSource(mockCsw, mockContext, new LinkedList<String>()); cswSource.setCswUrl(URL); cswSource.setId(ID); // Perform test SourceResponse response = cswSource.query(new QueryRequestImpl(query)); // Verify Assert.assertNotNull(response); assertThat(response.getResults().size(), is(numRecordsReturned)); assertThat(response.getHits(), is(numRecordsMatched)); ArgumentCaptor<GetRecordsType> captor = ArgumentCaptor.forClass(GetRecordsType.class); try { verify(mockCsw, atLeastOnce()).getRecords(captor.capture()); } catch (CswException e) { fail("Could not verify mock CSW record count: " + e.getMessage()); } GetRecordsType getRecordsType = captor.getValue(); QueryType cswQuery = (QueryType) getRecordsType.getAbstractQuery().getValue(); assertThat(cswQuery.getSortBy().getSortProperty().size(), is(1)); assertThat( cswQuery.getSortBy().getSortProperty().get(0).getPropertyName().getContent().get(0) .toString(), equalTo(TITLE)); assertThat(cswQuery.getSortBy().getSortProperty().get(0).getSortOrder(), is(SortOrderType.DESC)); } @Test public void testQueryWithSortByDistance() throws JAXBException, UnsupportedQueryException, DatatypeConfigurationException, SAXException, IOException { // Setup final String searchPhrase = "*"; final int pageSize = 1; final int numRecordsReturned = 1; final long numRecordsMatched = 1; setupMockContextForMetacardTypeRegistrationAndUnregistration(getDefaultContentTypes()); try { configureMockRemoteCsw(numRecordsReturned, numRecordsMatched, CswConstants.VERSION_2_0_2); } catch (CswException e) { fail("Could not configure Mock Remote CSW: " + e.getMessage()); } QueryImpl query = new QueryImpl( builder.attribute(Metacard.ANY_TEXT).is().like().text(searchPhrase)); query.setPageSize(pageSize); SortBy sortBy = new SortByImpl(Result.DISTANCE, SortOrder.DESCENDING); query.setSortBy(sortBy); CswSource cswSource = getCswSource(mockCsw, mockContext, new LinkedList<String>()); cswSource.setCswUrl(URL); cswSource.setId(ID); // Perform test SourceResponse response = cswSource.query(new QueryRequestImpl(query)); // Verify Assert.assertNotNull(response); assertThat(response.getResults().size(), is(numRecordsReturned)); assertThat(response.getHits(), is(numRecordsMatched)); ArgumentCaptor<GetRecordsType> captor = ArgumentCaptor.forClass(GetRecordsType.class); try { verify(mockCsw, atLeastOnce()).getRecords(captor.capture()); } catch (CswException e) { fail("Could not verify mock CSW record count: " + e.getMessage()); } GetRecordsType getRecordsType = captor.getValue(); QueryType cswQuery = (QueryType) getRecordsType.getAbstractQuery().getValue(); assertThat(cswQuery.getSortBy(), nullValue()); } @Test public void testQueryWithSortByRelevance() throws JAXBException, UnsupportedQueryException, DatatypeConfigurationException, SAXException, IOException { // Setup final String searchPhrase = "*"; final int pageSize = 1; final int numRecordsReturned = 1; final long numRecordsMatched = 1; setupMockContextForMetacardTypeRegistrationAndUnregistration(getDefaultContentTypes()); try { configureMockRemoteCsw(numRecordsReturned, numRecordsMatched, CswConstants.VERSION_2_0_2); } catch (CswException e) { fail("Could not configure Mock Remote CSW: " + e.getMessage()); } QueryImpl query = new QueryImpl( builder.attribute(Metacard.ANY_TEXT).is().like().text(searchPhrase)); query.setPageSize(pageSize); SortBy sortBy = new SortByImpl(Result.RELEVANCE, SortOrder.DESCENDING); query.setSortBy(sortBy); CswSource cswSource = getCswSource(mockCsw, mockContext, new LinkedList<String>()); cswSource.setCswUrl(URL); cswSource.setId(ID); // Perform test SourceResponse response = cswSource.query(new QueryRequestImpl(query)); // Verify Assert.assertNotNull(response); assertThat(response.getResults().size(), is(numRecordsReturned)); assertThat(response.getHits(), is(numRecordsMatched)); ArgumentCaptor<GetRecordsType> captor = ArgumentCaptor.forClass(GetRecordsType.class); try { verify(mockCsw, atLeastOnce()).getRecords(captor.capture()); } catch (CswException e) { fail("Could not verify mock CSW record count: " + e.getMessage()); } GetRecordsType getRecordsType = captor.getValue(); QueryType cswQuery = (QueryType) getRecordsType.getAbstractQuery().getValue(); assertThat(cswQuery.getSortBy().getSortProperty().size(), is(1)); assertThat( cswQuery.getSortBy().getSortProperty().get(0).getPropertyName().getContent().get(0) .toString(), equalTo(Metacard.TITLE)); assertThat(cswQuery.getSortBy().getSortProperty().get(0).getSortOrder(), is(SortOrderType.DESC)); } @Test public void testQueryWithSortByTemporal() throws JAXBException, UnsupportedQueryException, DatatypeConfigurationException, SAXException, IOException { // Setup final String searchPhrase = "*"; final int pageSize = 1; final int numRecordsReturned = 1; final long numRecordsMatched = 1; setupMockContextForMetacardTypeRegistrationAndUnregistration(getDefaultContentTypes()); try { configureMockRemoteCsw(numRecordsReturned, numRecordsMatched, CswConstants.VERSION_2_0_2); } catch (CswException e) { fail("Could not configure Mock Remote CSW: " + e.getMessage()); } QueryImpl query = new QueryImpl( builder.attribute(Metacard.ANY_TEXT).is().like().text(searchPhrase)); query.setPageSize(pageSize); SortBy sortBy = new SortByImpl(Result.TEMPORAL, SortOrder.DESCENDING); query.setSortBy(sortBy); CswSource cswSource = getCswSource(mockCsw, mockContext, new LinkedList<String>()); cswSource.setCswUrl(URL); cswSource.setId(ID); // Perform test SourceResponse response = cswSource.query(new QueryRequestImpl(query)); // Verify Assert.assertNotNull(response); assertThat(response.getResults().size(), is(numRecordsReturned)); assertThat(response.getHits(), is(numRecordsMatched)); ArgumentCaptor<GetRecordsType> captor = ArgumentCaptor.forClass(GetRecordsType.class); try { verify(mockCsw, atLeastOnce()).getRecords(captor.capture()); } catch (CswException e) { fail("Could not verify mock CSW record count: " + e.getMessage()); } GetRecordsType getRecordsType = captor.getValue(); QueryType cswQuery = (QueryType) getRecordsType.getAbstractQuery().getValue(); assertThat(cswQuery.getSortBy().getSortProperty().size(), is(1)); assertThat( cswQuery.getSortBy().getSortProperty().get(0).getPropertyName().getContent().get(0) .toString(), equalTo(Metacard.MODIFIED)); assertThat(cswQuery.getSortBy().getSortProperty().get(0).getSortOrder(), is(SortOrderType.DESC)); } /** * Test to verify content type mapping is configurable. * The CSW Source should be able to map a csw:Record field to Content Type. */ @Test public void testPropertyIsEqualToQueryContentTypeIsMappedToFormat() throws JAXBException, UnsupportedQueryException, DatatypeConfigurationException, SAXException, IOException { // Setup int pageSize = 10; int numRecordsReturned = 1; long numRecordsMatched = 1; String format = "myContentType"; setupMockContextForMetacardTypeRegistrationAndUnregistration(getDefaultContentTypes()); try { configureMockRemoteCsw(numRecordsReturned, numRecordsMatched, CswConstants.VERSION_2_0_2); } catch (CswException e) { fail("Could not configure Mock Remote CSW: " + e.getMessage()); } QueryImpl propertyIsEqualToQuery = new QueryImpl( builder.attribute(Metacard.CONTENT_TYPE).is().text(format)); propertyIsEqualToQuery.setPageSize(pageSize); CswSource cswSource = getCswSource(mockCsw, mockContext, new LinkedList<String>(), CswRecordMetacardType.CSW_FORMAT); cswSource.setCswUrl(URL); cswSource.setId(ID); // Perform test cswSource.query(new QueryRequestImpl(propertyIsEqualToQuery)); // Verify ArgumentCaptor<GetRecordsType> captor = ArgumentCaptor.forClass(GetRecordsType.class); // getRecords() is called two times. Once for initial CSW source // configuration and // a second time for the actual content type query. try { verify(mockCsw, times(2)).getRecords(captor.capture()); } catch (CswException e) { fail("Could not verify Mock CSW record count " + e.getMessage()); } GetRecordsType getRecordsType = captor.getValue(); String xml = getGetRecordsTypeAsXml(getRecordsType, CswConstants.VERSION_2_0_2); LOGGER.debug(xml); assertXMLEqual(xml, getRecordsControlXml202ContentTypeMappedToFormat); } /** * Test to verify content type version mapping is correct. The CSW Source should be able to map * a csw:Record field to Content Type. */ @Test public void testPropertyIsLikeContentTypeVersion() throws JAXBException, UnsupportedQueryException, DatatypeConfigurationException, SAXException, IOException { // Setup int pageSize = 10; int numRecordsReturned = 1; long numRecordsMatched = 1; String format = "myContentType"; String version = "2.0"; setupMockContextForMetacardTypeRegistrationAndUnregistration(getDefaultContentTypes()); try { configureMockRemoteCsw(numRecordsReturned, numRecordsMatched, CswConstants.VERSION_2_0_2); } catch (CswException e) { fail("Could not configure Mock Remote CSW: " + e.getMessage()); } Filter ctfilter = builder.attribute(Metacard.CONTENT_TYPE).is().text(format); Filter versionFilter = builder.attribute(Metacard.CONTENT_TYPE_VERSION).is().like() .text(version); Filter filter = builder.allOf(ctfilter, versionFilter); QueryImpl propertyIsEqualToQuery = new QueryImpl(filter); propertyIsEqualToQuery.setPageSize(pageSize); CswSource cswSource = getCswSource(mockCsw, mockContext, new LinkedList<String>(), CswRecordMetacardType.CSW_FORMAT); cswSource.setCswUrl(URL); cswSource.setId(ID); // Perform test cswSource.query(new QueryRequestImpl(propertyIsEqualToQuery)); // Verify ArgumentCaptor<GetRecordsType> captor = ArgumentCaptor.forClass(GetRecordsType.class); // getRecords() is called two times. Once for initial CSW source // configuration and // a second time for the actual content type query. try { verify(mockCsw, times(2)).getRecords(captor.capture()); } catch (CswException e) { fail("Could not verify Mock CSW record count " + e.getMessage()); } GetRecordsType getRecordsType = captor.getValue(); String xml = getGetRecordsTypeAsXml(getRecordsType, CswConstants.VERSION_2_0_2); LOGGER.debug(xml); assertXMLEqual(xml, getRecordsControlXml202ContentTypeMappedToFormat); } @Test public void testAbsoluteTemporalSearchPropertyIsBetweenQuery() throws JAXBException, UnsupportedQueryException, DatatypeConfigurationException, SAXException, IOException { // Setup String expectedXml = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\r\n" + "<GetRecords resultType=\"results\" outputFormat=\"application/xml\" outputSchema=\"http://www.opengis.net/cat/csw/2.0.2\" startPosition=\"1\" maxRecords=\"10\" service=\"CSW\" version=\"2.0.2\" xmlns:ns2=\"http://www.opengis.net/ogc\" xmlns=\"http://www.opengis.net/cat/csw/2.0.2\" xmlns:ns4=\"http://www.w3.org/1999/xlink\" xmlns:ns3=\"http://www.opengis.net/gml\" xmlns:ns9=\"http://www.w3.org/2001/SMIL20/Language\" xmlns:ns5=\"http://www.opengis.net/ows\" xmlns:ns6=\"http://purl.org/dc/elements/1.1/\" xmlns:ns7=\"http://purl.org/dc/terms/\" xmlns:ns8=\"http://www.w3.org/2001/SMIL20/\">\r\n" + " <ns10:Query typeNames=\"Record\" xmlns=\"\" xmlns:ns10=\"http://www.opengis.net/cat/csw/2.0.2\">\r\n" + " <ns10:ElementSetName>full</ns10:ElementSetName>\r\n" + " <ns10:Constraint version=\"1.1.0\">\r\n" + " <ns2:Filter>\r\n" + " <ns2:PropertyIsBetween>\r\n" + " <ns2:PropertyName>effective</ns2:PropertyName>\r\n" + " <ns2:LowerBoundary>\r\n" + " <ns2:Literal>START_DATE_TIME</ns2:Literal>\r\n" + " </ns2:LowerBoundary>\r\n" + " <ns2:UpperBoundary>\r\n" + " <ns2:Literal>END_DATE_TIME</ns2:Literal>\r\n" + " </ns2:UpperBoundary>\r\n" + " </ns2:PropertyIsBetween>\r\n" + " </ns2:Filter>\r\n" + " </ns10:Constraint>\r\n" + " </ns10:Query>\r\n" + "</GetRecords>"; final int pageSize = 10; final int numRecordsReturned = 1; final long numRecordsMatched = 10; setupMockContextForMetacardTypeRegistrationAndUnregistration(getDefaultContentTypes()); try { configureMockRemoteCsw(numRecordsReturned, numRecordsMatched, CswConstants.VERSION_2_0_2); } catch (CswException e) { fail("Could not configure Mock Remote CSW: " + e.getMessage()); } // Create start and end date times that are before current time DateTime startDate = new DateTime(2013, 5, 1, 0, 0, 0, 0); DateTime endDate = new DateTime(2013, 12, 31, 0, 0, 0, 0); DateTimeFormatter fmt = ISODateTimeFormat.dateTime(); // Load the expected start and end date time into the excepted result // XML expectedXml = expectedXml.replace("START_DATE_TIME", fmt.print(startDate)); expectedXml = expectedXml.replace("END_DATE_TIME", fmt.print(endDate)); // Single absolute time range to search across Filter temporalFilter = builder.attribute(Metacard.EFFECTIVE).is().during() .dates(startDate.toDate(), endDate.toDate()); QueryImpl temporalQuery = new QueryImpl(temporalFilter); temporalQuery.setPageSize(pageSize); CswSource cswSource = getCswSource(mockCsw, mockContext, new LinkedList<String>()); cswSource.setCswUrl(URL); cswSource.setId(ID); cswSource.setEffectiveDateMapping(Metacard.EFFECTIVE); // Perform test cswSource.query(new QueryRequestImpl(temporalQuery)); // Verify ArgumentCaptor<GetRecordsType> captor = ArgumentCaptor.forClass(GetRecordsType.class); try { verify(mockCsw, atLeastOnce()).getRecords(captor.capture()); } catch (CswException e) { fail("Could not verify Mock CSW record count " + e.getMessage()); } GetRecordsType getRecordsType = captor.getValue(); String xml = getGetRecordsTypeAsXml(getRecordsType, CswConstants.VERSION_2_0_2); LOGGER.debug(xml); assertXMLEqual(expectedXml, xml); } @Test public void testAbsoluteTemporalSearchTwoRanges() throws JAXBException, UnsupportedQueryException, DatatypeConfigurationException, SAXException, IOException { // Setup String expectedXml = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\r\n" + "<ns4:GetRecords resultType=\"results\" outputFormat=\"application/xml\"\r\n" + " outputSchema=\"http://www.opengis.net/cat/csw/2.0.2\" startPosition=\"1\"\r\n" + " maxRecords=\"10\" service=\"CSW\" version=\"2.0.2\" xmlns:ns2=\"http://www.w3.org/1999/xlink\"\r\n" + " xmlns=\"http://www.opengis.net/ows\" xmlns:ns4=\"http://www.opengis.net/cat/csw/2.0.2\"\r\n" + " xmlns:ns3=\"http://www.opengis.net/ogc\" xmlns:ns9=\"http://www.w3.org/2001/SMIL20/Language\"\r\n" + " xmlns:ns5=\"http://www.opengis.net/gml\" xmlns:ns6=\"http://purl.org/dc/elements/1.1/\"\r\n" + " xmlns:ns7=\"http://purl.org/dc/terms/\" xmlns:ns8=\"http://www.w3.org/2001/SMIL20/\">\r\n" + " <ns4:Query typeNames=\"Record\" xmlns=\"\"\r\n" + " xmlns:ns10=\"http://www.opengis.net/ows\">\r\n" + " <ns4:ElementSetName>full</ns4:ElementSetName>\r\n" + " <ns4:Constraint version=\"1.1.0\">\r\n" + " <ns3:Filter>\r\n" + " <ns3:Or>\r\n" + " <ns3:PropertyIsBetween>\r\n" + " <ns3:PropertyName>effective</ns3:PropertyName>\r\n" + " <ns3:LowerBoundary>\r\n" + " <ns3:Literal>START1_DATE_TIME</ns3:Literal>\r\n" + " </ns3:LowerBoundary>\r\n" + " <ns3:UpperBoundary>\r\n" + " <ns3:Literal>END1_DATE_TIME</ns3:Literal>\r\n" + " </ns3:UpperBoundary>\r\n" + " </ns3:PropertyIsBetween>\r\n" + " <ns3:PropertyIsBetween>\r\n" + " <ns3:PropertyName>effective</ns3:PropertyName>\r\n" + " <ns3:LowerBoundary>\r\n" + " <ns3:Literal>START2_DATE_TIME</ns3:Literal>\r\n" + " </ns3:LowerBoundary>\r\n" + " <ns3:UpperBoundary>\r\n" + " <ns3:Literal>END2_DATE_TIME</ns3:Literal>\r\n" + " </ns3:UpperBoundary>\r\n" + " </ns3:PropertyIsBetween>\r\n" + " </ns3:Or>\r\n" + " </ns3:Filter>\r\n" + " </ns4:Constraint>\r\n" + " </ns4:Query>\r\n" + "</ns4:GetRecords>\r\n"; final int pageSize = 10; final int numRecordsReturned = 1; final long numRecordsMatched = 10; setupMockContextForMetacardTypeRegistrationAndUnregistration(getDefaultContentTypes()); try { configureMockRemoteCsw(numRecordsReturned, numRecordsMatched, CswConstants.VERSION_2_0_2); } catch (CswException e) { fail("Could not configure Mock Remote CSW: " + e.getMessage()); } DateTime startDate = new DateTime(2012, 5, 1, 0, 0, 0, 0); DateTime endDate = new DateTime(2012, 12, 31, 0, 0, 0, 0); DateTime startDate2 = new DateTime(2013, 5, 1, 0, 0, 0, 0); DateTime endDate2 = new DateTime(2013, 12, 31, 0, 0, 0, 0); DateTimeFormatter fmt = ISODateTimeFormat.dateTime(); // Load the expected start and end date time into the excepted result // XML expectedXml = expectedXml.replace("START1_DATE_TIME", fmt.print(startDate)); expectedXml = expectedXml.replace("END1_DATE_TIME", fmt.print(endDate)); expectedXml = expectedXml.replace("START2_DATE_TIME", fmt.print(startDate2)); expectedXml = expectedXml.replace("END2_DATE_TIME", fmt.print(endDate2)); // Single absolute time range to search across FilterFactory filterFactory = new FilterFactoryImpl(); Filter temporalFilter1 = builder.attribute(Metacard.EFFECTIVE).is().during() .dates(startDate.toDate(), endDate.toDate()); Filter temporalFilter2 = builder.attribute(Metacard.EFFECTIVE).is().during() .dates(startDate2.toDate(), endDate2.toDate()); Filter temporalFilter = filterFactory.or(temporalFilter1, temporalFilter2); QueryImpl temporalQuery = new QueryImpl(temporalFilter); temporalQuery.setPageSize(pageSize); CswSource cswSource = getCswSource(mockCsw, mockContext, new LinkedList<String>()); cswSource.setCswUrl(URL); cswSource.setId(ID); cswSource.setEffectiveDateMapping(Metacard.EFFECTIVE); // Perform test cswSource.query(new QueryRequestImpl(temporalQuery)); // Verify ArgumentCaptor<GetRecordsType> captor = ArgumentCaptor.forClass(GetRecordsType.class); try { verify(mockCsw, atLeastOnce()).getRecords(captor.capture()); } catch (CswException e) { fail("Could not verify Mock CSW record count " + e.getMessage()); } GetRecordsType getRecordsType = captor.getValue(); String xml = getGetRecordsTypeAsXml(getRecordsType, CswConstants.VERSION_2_0_2); LOGGER.debug(xml); assertXMLEqual(expectedXml, xml); } @Test(expected = UnsupportedQueryException.class) public void testCswSourceNoFilterCapabilities() throws CswException, UnsupportedQueryException { // Setup CapabilitiesType mockCapabilitiesType = mock(CapabilitiesType.class); when(mockCsw.getCapabilities(any(GetCapabilitiesRequest.class))) .thenReturn(mockCapabilitiesType); CswSource cswSource = getCswSource(mockCsw, mockContext, new ArrayList<String>()); cswSource.setCswUrl(URL); cswSource.setId(ID); QueryImpl propertyIsLikeQuery = new QueryImpl( builder.attribute(Metacard.ANY_TEXT).is().like().text("junk")); propertyIsLikeQuery.setPageSize(10); cswSource.query(new QueryRequestImpl(propertyIsLikeQuery)); } @Test public void testTimeoutConfiguration() { final String TITLE = "title"; // Setup final String searchPhrase = "*"; final int pageSize = 1; final int numRecordsReturned = 1; final long numRecordsMatched = 1; setupMockContextForMetacardTypeRegistrationAndUnregistration(getDefaultContentTypes()); try { configureMockRemoteCsw(numRecordsReturned, numRecordsMatched, CswConstants.VERSION_2_0_2); } catch (CswException e) { fail("Could not configure Mock Remote CSW: " + e.getMessage()); } CswSource cswSource = getCswSource(mockCsw, mockContext, new LinkedList<String>()); cswSource.setCswUrl(URL); cswSource.setId(ID); cswSource.setConnectionTimeout(10000); cswSource.setReceiveTimeout(10000); // Perform test cswSource.updateTimeouts(); verify(mockCsw, atLeastOnce()).setTimeouts(any(Integer.class), any(Integer.class)); } @Test public void testRefresh() { CswSource cswSource = getCswSource(null, null, Collections.<String>emptyList()); cswSource.refresh(null); Map<String, Object> configuration = new HashMap<String, Object>(); cswSource.refresh(configuration); } @Test public void testQueryWithAlternateQueryType() throws JAXBException, UnsupportedQueryException, DatatypeConfigurationException, SAXException, IOException { // Setup final QName expectedQname = new QName("http://example.com", "example", "abc"); final String searchPhrase = "*"; final int pageSize = 1; final int numRecordsReturned = 1; final long numRecordsMatched = 1; setupMockContextForMetacardTypeRegistrationAndUnregistration(getDefaultContentTypes()); try { configureMockRemoteCsw(numRecordsReturned, numRecordsMatched, CswConstants.VERSION_2_0_2); } catch (CswException e) { fail("Could not configure Mock Remote CSW: " + e.getMessage()); } QueryImpl query = new QueryImpl( builder.attribute(Metacard.ANY_TEXT).is().like().text(searchPhrase)); query.setPageSize(pageSize); CswSource cswSource = getCswSource(mockCsw, mockContext, new LinkedList<String>(), null, expectedQname.toString(), expectedQname.getPrefix()); cswSource.setCswUrl(URL); cswSource.setId(ID); // Perform test cswSource.query(new QueryRequestImpl(query)); ArgumentCaptor<GetRecordsType> captor = ArgumentCaptor.forClass(GetRecordsType.class); try { verify(mockCsw, atLeastOnce()).getRecords(captor.capture()); } catch (CswException e) { fail("Could not verify mock CSW record count: " + e.getMessage()); } GetRecordsType getRecordsType = captor.getValue(); QueryType cswQuery = (QueryType) getRecordsType.getAbstractQuery().getValue(); assertThat(cswQuery.getTypeNames().size(), is(1)); assertThat(cswQuery.getTypeNames().get(0), is(expectedQname)); } @Test public void testQueryWithDefaultQueryType() throws JAXBException, UnsupportedQueryException, DatatypeConfigurationException, SAXException, IOException { // Setup final String searchPhrase = "*"; final int pageSize = 1; final int numRecordsReturned = 1; final long numRecordsMatched = 1; setupMockContextForMetacardTypeRegistrationAndUnregistration(getDefaultContentTypes()); try { configureMockRemoteCsw(numRecordsReturned, numRecordsMatched, CswConstants.VERSION_2_0_2); } catch (CswException e) { fail("Could not configure Mock Remote CSW: " + e.getMessage()); } QueryImpl query = new QueryImpl( builder.attribute(Metacard.ANY_TEXT).is().like().text(searchPhrase)); query.setPageSize(pageSize); // Verify passing a null config for qname/prefix falls back to CSW Record CswSource cswSource = getCswSource(mockCsw, mockContext, new LinkedList<String>(), null, null, null); cswSource.setCswUrl(URL); cswSource.setId(ID); // Perform test cswSource.query(new QueryRequestImpl(query)); ArgumentCaptor<GetRecordsType> captor = ArgumentCaptor.forClass(GetRecordsType.class); try { verify(mockCsw, atLeastOnce()).getRecords(captor.capture()); } catch (CswException e) { fail("Could not verify mock CSW record count: " + e.getMessage()); } GetRecordsType getRecordsType = captor.getValue(); QueryType cswQuery = (QueryType) getRecordsType.getAbstractQuery().getValue(); assertThat(cswQuery.getTypeNames().size(), is(1)); assertThat(cswQuery.getTypeNames().get(0).toString(), is(CSW_RECORD_QNAME)); } private CswSourceConfiguration getStandardCswSourceConfiguration(String contentTypeMapping, String queryTypeQName, String queryTypePrefix) { CswSourceConfiguration cswSourceConfiguration = new CswSourceConfiguration(); if (contentTypeMapping == null) { cswSourceConfiguration.setContentTypeMapping(CswRecordMetacardType.CSW_TYPE); } else { cswSourceConfiguration.setContentTypeMapping(contentTypeMapping); } cswSourceConfiguration.setQueryTypePrefix(queryTypePrefix); cswSourceConfiguration.setQueryTypeQName(queryTypeQName); cswSourceConfiguration.setId(ID); cswSourceConfiguration.setCswUrl(URL); cswSourceConfiguration.setModifiedDateMapping(Metacard.MODIFIED); cswSourceConfiguration.setIdentifierMapping(CswRecordMetacardType.CSW_IDENTIFIER); return cswSourceConfiguration; } private CswSource getCswSource(RemoteCsw remoteCsw, BundleContext context, List<String> contentTypes) { return getCswSource(remoteCsw, context, contentTypes, null); } private CswSource getCswSource(RemoteCsw remoteCsw, BundleContext context, List<String> contentTypes, String contentMapping, String queryTypeQName, String queryTypePrefix) { CswSourceConfiguration cswSourceConfiguration = getStandardCswSourceConfiguration( contentMapping, queryTypeQName, queryTypePrefix); cswSourceConfiguration.setContentTypeMapping(contentMapping); CswSource cswSource = new CswSource(remoteCsw, mockContext, cswSourceConfiguration, mockProvider); cswSource.setFilterAdapter(new GeotoolsFilterAdapterImpl()); cswSource.setFilterBuilder(builder); cswSource.setContext(context); cswSource.setContentTypeNames(contentTypes); cswSource.setOutputSchema(CswConstants.CSW_OUTPUT_SCHEMA); cswSource.setAvailabilityTask(mockAvailabilityTask); cswSource.configureCswSource(); return cswSource; } private CswSource getCswSource(RemoteCsw remoteCsw, BundleContext context, List<String> contentTypes, String contentMapping) { return getCswSource(remoteCsw, context, contentTypes, contentMapping, CSW_RECORD_QNAME, CswConstants.CSW_NAMESPACE_PREFIX); } }