/*
* Geotoolkit - An Open Source Java GIS Toolkit
* http://www.geotoolkit.org
*
* (C) 2012, Geomatys
*
* This library 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;
* version 2.1 of the License.
*
* This library 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.
*/
package org.geotoolkit.feature.xml.jaxp;
import java.io.IOException;
import java.lang.reflect.Array;
import java.util.Collection;
import java.util.Map;
import java.util.logging.Level;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.stream.XMLStreamException;
import org.apache.sis.feature.FeatureExt;
import org.geotoolkit.data.FeatureStoreUtilities;
import org.geotoolkit.data.FeatureCollection;
import org.geotoolkit.data.FeatureIterator;
import org.geotoolkit.factory.FactoryFinder;
import org.geotoolkit.feature.xml.Utils;
import org.geotoolkit.feature.xml.XmlFeatureWriter;
import org.geotoolkit.gml.JTStoGeometry;
import org.geotoolkit.gml.xml.AbstractGeometry;
import org.geotoolkit.gml.xml.GMLMarshallerPool;
import org.geotoolkit.xml.StaxStreamWriter;
import org.geotoolkit.gml.xml.v321.ObjectFactory;
import org.apache.sis.storage.DataStoreException;
import org.apache.sis.xml.MarshallerPool;
import org.geotoolkit.util.NamesExt;
import org.opengis.feature.Attribute;
import org.opengis.feature.Feature;
import org.opengis.feature.FeatureType;
import org.opengis.filter.expression.Expression;
import org.opengis.util.FactoryException;
/**
*
* @author Guilhem Legal (Geomatys)
*/
public class JAXPStreamValueCollectionWriter extends StaxStreamWriter implements XmlFeatureWriter {
private static final MarshallerPool GML_32_POOL = GMLMarshallerPool.getInstance();
/**
* Object factory to build a geometry.
*/
private static final ObjectFactory GML32_FACTORY = new ObjectFactory();
private static final String GML_NAMESPACE = "http://www.opengis.net/gml/3.2";
private static final String WFS_NAMESPACE = "http://www.opengis.net/wfs/2.0";
private final String valueReference;
public JAXPStreamValueCollectionWriter(final String valueReference) {
this.valueReference = valueReference;
}
/**
* Dispose the allocated resources. <strong>Must</strong> be called when closing the feautre writer.
*
* @throws IOException
* @throws XMLStreamException
*/
@Override
public void dispose() throws IOException, XMLStreamException{
super.dispose();
}
/**
* {@inheritDoc}
*/
@Override
public void write(final Object candidate, final Object output) throws IOException, XMLStreamException, DataStoreException {
write(candidate, output, null);
}
/**
* {@inheritDoc}
*/
@Override
public void write(final Object candidate, final Object output, final Integer nbMatched) throws IOException, XMLStreamException, DataStoreException {
setOutput(output);
FeatureCollection collection;
if (candidate instanceof Feature) {
collection = FeatureStoreUtilities.collection((Feature)candidate);
} else if (candidate instanceof FeatureCollection) {
collection = (FeatureCollection) candidate;
} else {
throw new IllegalArgumentException("The given object is not a Feature or a" +
" FeatureCollection: "+ candidate);
}
writeValueCollection(collection, nbMatched);
}
/**
* Write the feature into the stream.
*
* @param feature The feature
* @throws XMLStreamException
*/
private void writeFeature(final Feature feature) throws XMLStreamException {
final FeatureType type = feature.getType();
//write properties in the type order
Expression exp = FactoryFinder.getFilterFactory(null).property(valueReference);
Object valueA = exp.evaluate(feature);
if (valueA instanceof Collection) {
for (Object value : (Collection)valueA) {
writer.writeStartElement("wfs", "member", WFS_NAMESPACE);
writeValue(value);
writer.writeEndElement();
}
} else if (valueA instanceof Map) {
final Map<?,?> map = (Map)valueA;
for (Map.Entry<?,?> entry : map.entrySet()) {
writer.writeStartElement("wfs", "member", WFS_NAMESPACE);
final Object key = entry.getKey();
if (key != null) {
writer.writeAttribute("name", (String)key);
}
writeValue(entry.getValue());
writer.writeEndElement();
}
} else if (valueA != null && valueA.getClass().isArray()) {
final int length = Array.getLength(valueA);
for (int i = 0; i < length; i++){
writer.writeStartElement("wfs", "member", WFS_NAMESPACE);
final Object value = Array.get(valueA, i);
final String textValue;
if (value != null && value.getClass().isArray()) { // matrix
final StringBuilder sb = new StringBuilder();
final int length2 = Array.getLength(value);
for (int j = 0; j < length2; j++) {
final Object subValue = Array.get(value, j);
sb.append(Utils.getStringValue(subValue)).append(" ");
}
textValue = sb.toString();
} else {
textValue = Utils.getStringValue(value);
}
writer.writeCharacters(textValue);
writer.writeEndElement();
}
} else if (valueA instanceof com.vividsolutions.jts.geom.Geometry) {
writer.writeStartElement("wfs", "member", WFS_NAMESPACE);
AbstractGeometry gmlGeometry = null;
try {
gmlGeometry = JTStoGeometry.toGML("3.2.1", (com.vividsolutions.jts.geom.Geometry) valueA, FeatureExt.getCRS(type));
} catch (FactoryException ex) {
LOGGER.log(Level.WARNING, "Factory exception when transforming JTS geometry to GML binding", ex);
}
final JAXBElement element = GML32_FACTORY.buildAnyGeometry(gmlGeometry);
try {
final Marshaller marshaller;
marshaller = GML_32_POOL.acquireMarshaller();
marshaller.setProperty(Marshaller.JAXB_FRAGMENT, true);
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, false);
marshaller.marshal(element, writer);
GML_32_POOL.recycle(marshaller);
} catch (JAXBException ex) {
LOGGER.log(Level.WARNING, "JAXB Exception while marshalling the iso geometry: " + ex.getMessage(), ex);
}
writer.writeEndElement();
} else {
String value = Utils.getStringValue(valueA);
if (value != null) {
writer.writeStartElement("wfs", "member", WFS_NAMESPACE);
writeValue(value);
writer.writeEndElement();
}
}
}
private void writeValue(final Object value) throws XMLStreamException {
if (value instanceof Feature) {
final JAXPStreamFeatureWriter featureWriter = new JAXPStreamFeatureWriter("3.2.1", "2.0.0", null);
try {
featureWriter.write(value, getWriter());
} catch (IOException ex) {
LOGGER.log(Level.WARNING, null, ex);
} catch (DataStoreException ex) {
LOGGER.log(Level.WARNING, null, ex);
}
} else if (value instanceof Attribute) {
final Attribute att = (Attribute) value;
final Object attValue = att.getValue();
if (attValue instanceof Collection) {
for (Object o : (Collection) attValue) {
writer.writeStartElement(NamesExt.getNamespace(att.getName()), att.getName().tip().toString());
writer.writeCharacters(Utils.getStringValue(o));
writer.writeEndElement();
}
} else {
writer.writeStartElement(NamesExt.getNamespace(att.getName()), att.getName().tip().toString());
writer.writeCharacters(Utils.getStringValue(attValue));
writer.writeEndElement();
}
} else {
writer.writeCharacters(Utils.getStringValue(value));
}
}
/**
*
* @param featureCollection
* @param writer
* @param fragment : true if we write in a stream, dont write start and end elements
* @throws DataStoreException
*/
public void writeValueCollection(final FeatureCollection featureCollection, final Integer nbMatched) throws DataStoreException, XMLStreamException {
// the XML header
writer.writeStartDocument("UTF-8", "1.0");
// the root Element
writer.writeStartElement("wfs", "ValueCollection", WFS_NAMESPACE);
writer.writeNamespace("gml", GML_NAMESPACE);
writer.writeNamespace("wfs", WFS_NAMESPACE);
/*if (schemaLocation != null && !schemaLocation.equals("")) {
writer.writeNamespace("xsi", "http://www.w3.org/2001/XMLSchema-instance");
writer.writeAttribute("xsi", "http://www.w3.org/2001/XMLSchema-instance", "schemaLocation", schemaLocation);
}*/
/*
* Other WFS value collection attribute
*/
writer.writeAttribute("numberReturned", Integer.toString(featureCollection.size()));
if (nbMatched != null) {
writer.writeAttribute("numberMatched", Integer.toString(nbMatched));
}
FeatureType type = featureCollection.getFeatureType();
if (type != null && type.getName() != null) {
String namespace = NamesExt.getNamespace(type.getName());
if (namespace != null && !(namespace.equals("http://www.opengis.net/gml") || namespace.equals("http://www.opengis.net/gml/3.2"))) {
Prefix prefix = getPrefix(namespace);
writer.writeNamespace(prefix.prefix, namespace);
}
}
// we write each feature member of the collection
FeatureIterator iterator = featureCollection.iterator();
try {
while (iterator.hasNext()) {
final Feature f = iterator.next();
writeFeature(f);
}
} finally {
// we close the stream
iterator.close();
}
writer.writeEndElement();
writer.writeEndDocument();
writer.flush();
writer.close();
}
}