/** * 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.common; import java.io.Reader; import java.io.StringReader; import java.math.BigInteger; import java.util.Arrays; import java.util.LinkedList; 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.Unmarshaller; import javax.xml.namespace.QName; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import net.opengis.cat.csw.v_2_0_2.DistributedSearchType; import net.opengis.cat.csw.v_2_0_2.ElementSetNameType; import net.opengis.cat.csw.v_2_0_2.ElementSetType; import net.opengis.cat.csw.v_2_0_2.GetRecordsType; import net.opengis.cat.csw.v_2_0_2.QueryConstraintType; import net.opengis.cat.csw.v_2_0_2.QueryType; import net.opengis.cat.csw.v_2_0_2.ResultType; import net.opengis.filter.v_1_1_0.FilterType; import net.opengis.filter.v_1_1_0.PropertyNameType; import net.opengis.filter.v_1_1_0.SortByType; import net.opengis.filter.v_1_1_0.SortOrderType; import net.opengis.filter.v_1_1_0.SortPropertyType; /** * JAX-RS Parameter Bean Class for the GetRecords request. The member variables will be * automatically injected by the JAX-RS annotations. * */ public class GetRecordsRequest extends CswRequest { private static final Logger LOGGER = LoggerFactory.getLogger(GetRecordsRequest.class); private static final JAXBContext JAX_BCONTEXT; static { JAXBContext context = null; String contextPath = StringUtils .join(new String[] {CswConstants.OGC_FILTER_PACKAGE, CswConstants.OGC_GML_PACKAGE, CswConstants.OGC_OWS_PACKAGE}, ":"); try { LOGGER.debug("Creating JAXB context with context path: {}", contextPath); context = JAXBContext .newInstance(contextPath, CswJAXBElementProvider.class.getClassLoader()); } catch (JAXBException e) { LOGGER.error("Unable to create JAXB context using contextPath: {}", contextPath, e); } JAX_BCONTEXT = context; } /** * Should not set default values for these fields. Otherwise those values will be used * by the endpoint GET requests, when the caller fails to specify a parameter. */ private String version; private String requestId; private String namespace; private String resultType; private String outputFormat; private String outputSchema; private BigInteger startPosition; private BigInteger maxRecords; private String typeNames; private String elementName; private String elementSetName; private String constraintLanguage; private String constraint; private String sortBy; private Boolean distributedSearch; private BigInteger hopCount; private String responseHandler; public GetRecordsRequest() { super(CswConstants.GET_RECORDS); } public GetRecordsRequest(String service, String version) { this(); setService(service); setVersion(version); } public String getVersion() { return version; } public void setVersion(String version) { this.version = version; } public String getRequestId() { return requestId; } public void setRequestId(String requestId) { this.requestId = requestId; } public String getNamespace() { return namespace; } public void setNamespace(String namespace) { this.namespace = namespace; } public String getResultType() { return resultType; } public void setResultType(String resultType) { this.resultType = resultType; } public String getOutputFormat() { return outputFormat; } public void setOutputFormat(String outputFormat) { this.outputFormat = outputFormat; } public String getOutputSchema() { return outputSchema; } public void setOutputSchema(String outputSchema) { this.outputSchema = outputSchema; } public BigInteger getStartPosition() { return startPosition; } public void setStartPosition(BigInteger startPosition) { this.startPosition = startPosition; } public BigInteger getMaxRecords() { return maxRecords; } public void setMaxRecords(BigInteger maxRecords) { this.maxRecords = maxRecords; } public String getTypeNames() { return typeNames; } public void setTypeNames(String typeNames) { this.typeNames = typeNames; } public String getElementName() { return elementName; } public void setElementName(String elementName) { this.elementName = elementName; } public String getElementSetName() { return elementSetName; } public void setElementSetName(String elementSetName) { this.elementSetName = elementSetName; } public String getConstraintLanguage() { return constraintLanguage; } public void setConstraintLanguage(String constraintLanguage) { this.constraintLanguage = constraintLanguage; } public String getConstraint() { return constraint; } public void setConstraint(String constraint) { this.constraint = constraint; } public String getSortBy() { return sortBy; } public void setSortBy(String sortBy) { this.sortBy = sortBy; } public Boolean getDistributedSearch() { return distributedSearch; } public void setDistributedSearch(Boolean distributedSearch) { this.distributedSearch = distributedSearch; } public BigInteger getHopCount() { return hopCount; } public void setHopCount(BigInteger hopCount) { this.hopCount = hopCount; } public String getResponseHandler() { return responseHandler; } public void setResponseHandler(String responseHandler) { this.responseHandler = responseHandler; } /** * Convert the KVP values into a GetRecordsType, validates format of fields and enumeration * constraints required to meet the schema requirements of the GetRecordsType. No further * validation is done at this point * * @return GetRecordsType representation of this key-value representation * @throws CswException * An exception when some field cannot be converted to the equivalent GetRecordsType * value */ public GetRecordsType get202RecordsType() throws CswException { GetRecordsType getRecords = new GetRecordsType(); getRecords.setOutputSchema(getOutputSchema()); getRecords.setRequestId(getRequestId()); if (getMaxRecords() != null) { getRecords.setMaxRecords(getMaxRecords()); } if (getStartPosition() != null) { getRecords.setStartPosition(getStartPosition()); } if (getOutputFormat() != null) { getRecords.setOutputFormat(getOutputFormat()); } if (getResponseHandler() != null) { getRecords.setResponseHandler(Arrays.asList(getResponseHandler())); } if (getResultType() != null) { try { getRecords.setResultType(ResultType.fromValue(getResultType())); } catch (IllegalArgumentException iae) { LOGGER.warn("Failed to find \"{}\" as a valid ResultType, Exception {}", getResultType(), iae); throw new CswException( "A CSW getRecords request ResultType must be \"hits\", \"results\", or \"validate\""); } } if (getDistributedSearch() != null && getDistributedSearch()) { DistributedSearchType disSearch = new DistributedSearchType(); disSearch.setHopCount(getHopCount()); getRecords.setDistributedSearch(disSearch); } QueryType query = new QueryType(); Map<String, String> namespaces = parseNamespaces(getNamespace()); List<QName> typeNames = typeStringToQNames(getTypeNames(), namespaces); query.setTypeNames(typeNames); if (getElementName() != null && getElementSetName() != null) { LOGGER.warn( "CSW getRecords request received with mutually exclusive ElementName and SetElementName set"); throw new CswException( "A CSW getRecords request can only have an \"ElementName\" or an \"ElementSetName\""); } if (getElementName() != null) { query.setElementName(typeStringToQNames(getElementName(), namespaces)); } if (getElementSetName() != null) { try { ElementSetNameType eleSetName = new ElementSetNameType(); eleSetName.setTypeNames(typeNames); eleSetName.setValue(ElementSetType.fromValue(getElementSetName())); query.setElementSetName(eleSetName); } catch (IllegalArgumentException iae) { LOGGER.warn("Failed to find \"{}\" as a valid elementSetType, Exception {}", getElementSetName(), iae); throw new CswException( "A CSW getRecords request ElementSetType must be \"brief\", \"summary\", or \"full\""); } } if (getSortBy() != null) { SortByType sort = new SortByType(); List<SortPropertyType> sortProps = new LinkedList<SortPropertyType>(); String[] sortOptions = getSortBy().split(","); for (String sortOption : sortOptions) { if (sortOption.lastIndexOf(':') < 1) { throw new CswException("Invalid Sort Order format: " + getSortBy()); } SortPropertyType sortProperty = new SortPropertyType(); PropertyNameType propertyName = new PropertyNameType(); String propName = StringUtils.substringBeforeLast(sortOption, ":"); String direction = StringUtils.substringAfterLast(sortOption, ":"); propertyName.setContent(Arrays.asList((Object) propName)); SortOrderType sortOrder; if (direction.equals("A")) { sortOrder = SortOrderType.ASC; } else if (direction.equals("D")) { sortOrder = SortOrderType.DESC; } else { throw new CswException("Invalid Sort Order format: " + getSortBy()); } sortProperty.setPropertyName(propertyName); sortProperty.setSortOrder(sortOrder); sortProps.add(sortProperty); } sort.setSortProperty(sortProps); query.setElementName(typeStringToQNames(getElementName(), namespaces)); query.setSortBy(sort); } if (getConstraint() != null) { QueryConstraintType queryConstraint = new QueryConstraintType(); if (getConstraintLanguage().equalsIgnoreCase(CswConstants.CONSTRAINT_LANGUAGE_CQL)) { queryConstraint.setCqlText(getConstraint()); } else if (getConstraintLanguage() .equalsIgnoreCase(CswConstants.CONSTRAINT_LANGUAGE_FILTER)) { try { Unmarshaller unmarshaller = JAX_BCONTEXT.createUnmarshaller(); Reader reader = new StringReader(getConstraint()); @SuppressWarnings("unchecked") JAXBElement<FilterType> jaxbFilter = (JAXBElement<FilterType>) unmarshaller .unmarshal(reader); queryConstraint.setFilter(jaxbFilter.getValue()); } catch (JAXBException e) { throw new CswException("JAXBException parsing OGC Filter:" + getConstraint(), e); } catch (Exception e) { throw new CswException("Unable to parse OGC Filter:" + getConstraint(), e); } } else { throw new CswException( "Invalid Constraint Language defined: " + getConstraintLanguage()); } query.setConstraint(queryConstraint); } JAXBElement<QueryType> jaxbQuery = new JAXBElement<QueryType>( new QName(CswConstants.CSW_OUTPUT_SCHEMA), QueryType.class, query); getRecords.setAbstractQuery(jaxbQuery); return getRecords; } }