/** * 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.transformer; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; import java.io.Serializable; import java.util.ArrayList; import java.util.GregorianCalendar; import java.util.List; import java.util.Map; import javax.activation.MimeType; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBElement; import javax.xml.bind.JAXBException; import javax.xml.bind.Marshaller; import javax.xml.datatype.DatatypeConfigurationException; import javax.xml.datatype.DatatypeFactory; import javax.xml.namespace.QName; import org.codice.ddf.spatial.ogc.csw.catalog.common.CswConstants; import org.codice.ddf.spatial.ogc.csw.catalog.common.CswRecordCollection; import org.codice.ddf.spatial.ogc.csw.catalog.converter.GetRecordsResponseConverter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.XStreamException; import com.thoughtworks.xstream.io.naming.NoNameCoder; import com.thoughtworks.xstream.io.xml.StaxDriver; import ddf.catalog.data.BinaryContent; import ddf.catalog.data.Result; import ddf.catalog.data.impl.BinaryContentImpl; import ddf.catalog.operation.SourceResponse; import ddf.catalog.transform.CatalogTransformerException; import ddf.catalog.transform.QueryResponseTransformer; import net.opengis.cat.csw.v_2_0_2.AcknowledgementType; import net.opengis.cat.csw.v_2_0_2.EchoedRequestType; 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.ObjectFactory; import net.opengis.cat.csw.v_2_0_2.ResultType; /** * Implementation of {@link ddf.catalog.transform.QueryResponseTransformer} for CSW 2.0.2 * GetRecordsResponse */ public class CswQueryResponseTransformer implements QueryResponseTransformer { private static final Logger LOGGER = LoggerFactory.getLogger(CswQueryResponseTransformer.class); private XStream xstreamGetRecordsResponse; private XStream xstreamGetRecordByIdResponse; public CswQueryResponseTransformer(GetRecordsResponseConverter converter) { xstreamGetRecordsResponse = initXstream(CswConstants.GET_RECORDS_RESPONSE, converter); xstreamGetRecordByIdResponse = initXstream(CswConstants.GET_RECORD_BY_ID_RESPONSE, converter); } @Override public BinaryContent transform(SourceResponse sourceResponse, Map<String, Serializable> arguments) throws CatalogTransformerException { LOGGER.debug("Entering CswQueryResponseTransformer.transform()"); if (sourceResponse.getResults() == null && arguments.get(CswConstants.RESULT_TYPE_PARAMETER) == null) { LOGGER.warn("Attempted to Transform and empty Result list."); return null; } BinaryContent transformedContent = null; ByteArrayOutputStream os = new ByteArrayOutputStream(); LOGGER.debug("Creating recordCollection"); CswRecordCollection recordCollection = new CswRecordCollection(); for (Result result : sourceResponse.getResults()) { recordCollection.getCswRecords().add(result.getMetacard()); } recordCollection.setNumberOfRecordsMatched(sourceResponse.getHits()); recordCollection.setNumberOfRecordsReturned(sourceResponse.getResults().size()); recordCollection.setStartPosition(sourceResponse.getRequest().getQuery().getStartIndex()); LOGGER.debug("Evaluating Arguments"); evaluateArguments(arguments, recordCollection); if (recordCollection.isById()) { LOGGER.debug("Transforming GetRecordByIdResponse"); try { xstreamGetRecordByIdResponse.toXML(recordCollection, os); } catch (XStreamException e) { throw new CatalogTransformerException(e); } } else if (recordCollection.getResultType() != null && ResultType.VALIDATE .equals(recordCollection.getResultType())) { LOGGER.debug("Transforming Acknowledgement"); try { writeAcknowledgement(recordCollection.getRequest(), os); } catch (IOException e) { throw new CatalogTransformerException(e); } } else { LOGGER.debug("Transforming GetRecordsResponse"); try { xstreamGetRecordsResponse.toXML(recordCollection, os); } catch (XStreamException e) { LOGGER.warn("Failed to transform GetRecordsResponse", e); throw new CatalogTransformerException(e); } } ByteArrayInputStream bais = new ByteArrayInputStream(os.toByteArray()); transformedContent = new BinaryContentImpl(bais, new MimeType()); return transformedContent; } /* * Method to handle all the arguments and update the recordCollection based on which arguments are provided. */ private void evaluateArguments(Map<String, Serializable> arguments, CswRecordCollection recordCollection) { if (arguments != null) { Object elementSetTypeArg = arguments.get(CswConstants.ELEMENT_SET_TYPE); if (elementSetTypeArg instanceof ElementSetType) { ElementSetType elementSetType = (ElementSetType) elementSetTypeArg; recordCollection.setElementSetType(elementSetType); } Object elementNamesArg = arguments.get(CswConstants.ELEMENT_NAMES); if (elementNamesArg instanceof QName[]) { QName[] qnames = (QName[]) elementNamesArg; if (qnames.length > 0) { List<QName> elementNames = new ArrayList<QName>(); for (QName entry : qnames) { elementNames.add(entry); } recordCollection.setElementName(elementNames); } } Object isByIdQuery = arguments.get(CswConstants.IS_BY_ID_QUERY); if (isByIdQuery != null) { recordCollection.setById((Boolean) isByIdQuery); } Object arg = arguments.get((CswConstants.GET_RECORDS)); if (arg != null && arg instanceof GetRecordsType) { recordCollection.setRequest((GetRecordsType) arg); } Object resultType = arguments.get(CswConstants.RESULT_TYPE_PARAMETER); if (resultType instanceof ResultType) { recordCollection.setResultType((ResultType) resultType); } Object outputSchema = arguments.get(CswConstants.OUTPUT_SCHEMA_PARAMETER); if (outputSchema instanceof String) { recordCollection.setOutputSchema((String) outputSchema); } Object doWriteNamespaces = arguments.get(CswConstants.WRITE_NAMESPACES); if (doWriteNamespaces instanceof Boolean) { recordCollection.setDoWriteNamespaces((Boolean) doWriteNamespaces); } } } private XStream initXstream(final String elementName, GetRecordsResponseConverter converter) { XStream xstream = new XStream(new StaxDriver(new NoNameCoder())); xstream.setClassLoader(xstream.getClass().getClassLoader()); xstream.registerConverter(converter); xstream.alias( CswConstants.CSW_NAMESPACE_PREFIX + CswConstants.NAMESPACE_DELIMITER + elementName, CswRecordCollection.class); return xstream; } private void writeAcknowledgement(GetRecordsType request, OutputStream outStream) throws IOException { try { JAXBContext jaxBContext = JAXBContext.newInstance("net.opengis.cat.csw.v_2_0_2:" + "net.opengis.filter.v_1_1_0:net.opengis.gml.v_3_1_1:net.opengis.ows.v_1_0_0"); Marshaller marshaller = jaxBContext.createMarshaller(); marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); AcknowledgementType ack = new AcknowledgementType(); EchoedRequestType echoedRequest = new EchoedRequestType(); JAXBElement<GetRecordsType> jaxBRequest = new ObjectFactory().createGetRecords(request); echoedRequest.setAny(jaxBRequest); ack.setEchoedRequest(echoedRequest); try { ack.setTimeStamp(DatatypeFactory.newInstance() .newXMLGregorianCalendar(new GregorianCalendar())); } catch (DatatypeConfigurationException e) { LOGGER.warn("Failed to set timestamp on Acknowledgement, Exception {}", e); } JAXBElement<AcknowledgementType> jaxBAck = new ObjectFactory() .createAcknowledgement(ack); marshaller.marshal(jaxBAck, outStream); } catch (JAXBException e) { throw new IOException(e); } } }