/*
* Geotoolkit - An Open Source Java GIS Toolkit
* http://www.geotoolkit.org
*
* (C) 2010, 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; either
* version 2.1 of the License, or (at your option) any later version.
*
* 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.xml.parameter;
import java.util.AbstractMap.SimpleEntry;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException;
import org.apache.sis.parameter.DefaultParameterDescriptorGroup;
import org.apache.sis.parameter.ParameterBuilder;
import org.apache.sis.util.iso.DefaultInternationalString;
import org.apache.sis.referencing.NamedIdentifier;
import org.apache.sis.util.ObjectConverters;
import org.geotoolkit.xml.StaxStreamReader;
import static org.geotoolkit.xml.parameter.ParameterConstants.*;
import org.geotoolkit.xml.parameter.ParameterConstants.ValueType;
import org.geotoolkit.xml.parameter.ParameterConstants.ValuesTopology;
import org.opengis.metadata.citation.Citation;
import org.opengis.parameter.GeneralParameterDescriptor;
import org.opengis.parameter.ParameterDescriptor;
import org.opengis.parameter.ParameterDescriptorGroup;
import org.opengis.metadata.Identifier;
import org.opengis.util.InternationalString;
/**
* <p>This class provides a GeneralParameterValue reading method.</p>
*
* @author Samuel Andrés
* @module
*/
public class ParameterDescriptorReader extends StaxStreamReader {
private GeneralParameterDescriptor root;
/**
* <p>This method reads a parameter document whose root is
* a GeneralParameterValue</p>
*
* @return
*/
public void read() throws XMLStreamException, ClassNotFoundException {
while (reader.hasNext()) {
switch (reader.next()) {
case XMLStreamConstants.START_ELEMENT:
final String eName = reader.getLocalName();
final String eUri = reader.getNamespaceURI();
if (URI_XSD.equals(eUri)) {
if (TAG_XSD_ELEMENT.equals(eName)) {
String descriptorCodeName = reader.getAttributeValue(null, ATT_XSD_NAME).replace('_', ' ');
int maxOccurs = (reader.getAttributeValue(null, ATT_XSD_MAX_OCCURS) == null)
? 1 : this.readOccurrences(reader.getAttributeValue(null, ATT_XSD_MAX_OCCURS));
int minOccurs = (reader.getAttributeValue(null, ATT_XSD_MIN_OCCURS) == null)
? 1 : this.readOccurrences(reader.getAttributeValue(null, ATT_XSD_MIN_OCCURS));
String defaultValue = reader.getAttributeValue(null, ATT_XSD_DEFAULT);
this.root = this.readGeneralParameterDescriptor(
descriptorCodeName, minOccurs, maxOccurs, defaultValue);
}
}
break;
}
}
}
/**
*
* @return General Parameter Descriptor root.
*/
public GeneralParameterDescriptor getDescriptorsRoot() {
return this.root;
}
/**
* <p>Reads an occurrence value.</p>
*
* @param occurrence
* @return
*/
private int readOccurrences(final String occurrence) {
if (VAL_XSD_UNBOUNDED.equals(occurrence)) {
return Integer.MAX_VALUE;
} else {
return Integer.parseInt(occurrence);
}
}
/**
* <p>Reads a general parameter descriptor.</p>
*
* @param descriptorCodeName
* @param minOcc
* @param maxOcc
* @param defaultValue
* @return
* @throws XMLStreamException
* @throws ClassNotFoundException
*/
private GeneralParameterDescriptor readGeneralParameterDescriptor(
final String descriptorCodeName, final int minOcc, final int maxOcc, final String defaultValue)
throws XMLStreamException, ClassNotFoundException {
GeneralParameterDescriptor descriptor = null;
boucle:
while (reader.hasNext()) {
switch (reader.next()) {
case XMLStreamConstants.START_ELEMENT:
final String eName = reader.getLocalName();
final String eUri = reader.getNamespaceURI();
if (URI_XSD.equals(eUri)) {
if (TAG_XSD_SIMPLE_TYPE.equals(eName)) {
descriptor = this.readParameterDescriptor(
descriptorCodeName, minOcc, defaultValue);
} else if (TAG_XSD_SEQUENCE.equals(eName)) {
descriptor = this.readParameterDescriptorGroup(
descriptorCodeName, minOcc, maxOcc);
}
}
break;
case XMLStreamConstants.END_ELEMENT:
if (TAG_XSD_ELEMENT.equals(reader.getLocalName())
&& URI_XSD.contains(reader.getNamespaceURI())) {
break boucle;
}
break;
}
}
return descriptor;
}
/**
* <p>This method reads a ParameterDescriptor</p>
*
* @param descriptorCodeName
* @param minOcc
* @param maxOcc
* @param defaultValue
* @return
* @throws XMLStreamException
* @throws ClassNotFoundException
*/
private ParameterDescriptor readParameterDescriptor(
final String descriptorCodeName, final int minOcc, Object defaultValue)
throws XMLStreamException, ClassNotFoundException {
Class c = null;
Identifier name = null;
SimpleEntry<Object, ValueType>[] values = null;
ValuesTopology topology = null;
CharSequence remarks = null;
Citation authority = null;
Comparable minimum = null, maximum = null;
boucle:
while (reader.hasNext()) {
switch (reader.next()) {
case XMLStreamConstants.START_ELEMENT:
final String eName = reader.getLocalName();
final String eUri = reader.getNamespaceURI();
if (URI_XSD.equals(eUri)) {
if (TAG_XSD_RESTRICTION.equals(eName)) {
SimpleEntry<ValuesTopology, SimpleEntry<Object, ValueType>[]> result = this.readValues(c);
values = result.getValue();
topology = result.getKey();
} else if (TAG_XSD_DOCUMENTATION.equals(eName)) {
remarks = reader.getElementText();
} else if (TAG_XSD_APP_INFO.equals(eName)) {
String[] appInfoLine = reader.getElementText().split(":");
if ("valueClass".equals(appInfoLine[0])) {
c = Class.forName(appInfoLine[1]);
}
// if("codeSpace".equals(appInfoLine[0])){
// codeSpace = appInfoLine[1];
// }
// if("version".equals(appInfoLine[0])){
// version = appInfoLine[1];
// }
}
}
break;
case XMLStreamConstants.END_ELEMENT:
if (TAG_XSD_SIMPLE_TYPE.equals(reader.getLocalName())
&& URI_XSD.contains(reader.getNamespaceURI())) {
break boucle;
}
break;
}
}
// MIN and/or MAX values
final Object[] valuesTab = new Object[values.length];
for (int i = 0, length = values.length; i < length; i++) {
valuesTab[i] = values[i].getKey();
if (values[i].getValue() == ValueType.MIN) {
minimum = (Comparable) valuesTab[i];
} else if (values[i].getValue() == ValueType.MAX) {
maximum = (Comparable) valuesTab[i];
}
}
// DEFAULT value
if (defaultValue != null) {
defaultValue = ObjectConverters.convert(defaultValue, c);
}
// Are values in INTERVAL or DISCRETE range ?
if (topology == ValuesTopology.INTERVAL) {
// Is there minimum and/or maximum boundarie ?
if (minimum == null && maximum == null) {
return new ParameterBuilder()
.addName(descriptorCodeName)
.setRemarks(remarks)
.setRequired(minOcc!=0)
.create(c, defaultValue);
} else {
return new ParameterBuilder()
.addName(authority, descriptorCodeName)
.setRequired(minOcc!=0)
.createBounded(c, minimum, maximum, (Comparable)defaultValue);
}
} else {
return new ParameterBuilder()
.addName(authority, descriptorCodeName)
.setRequired(minOcc!=0)
.createEnumerated(c, valuesTab, defaultValue);
}
}
/**
* <p>This method reads a ParameterDescriptorGroup</p>
*
* @param descriptorCodeName
* @param minimumOccurs
* @param maximumOccurs
* @return
* @throws XMLStreamException
* @throws ClassNotFoundException
*/
private ParameterDescriptorGroup readParameterDescriptorGroup(
final String descriptorCodeName, final int minimumOccurs, final int maximumOccurs)
throws XMLStreamException, ClassNotFoundException {
final List<GeneralParameterDescriptor> descs = new ArrayList<GeneralParameterDescriptor>();
final Map<String, Object> properties = new HashMap<String, Object>();
String codeSpace = null, version = null;
InternationalString remarks = null;
boucle:
while (reader.hasNext()) {
switch (reader.next()) {
case XMLStreamConstants.START_ELEMENT:
final String eName = reader.getLocalName();
final String eUri = reader.getNamespaceURI();
if (URI_XSD.equals(eUri)) {
if (TAG_XSD_ELEMENT.equals(eName)) {
String dcn = reader.getAttributeValue(null, ATT_XSD_NAME).replace('_', ' ');
int maxO = (reader.getAttributeValue(null, ATT_XSD_MAX_OCCURS) == null)
? 1 : this.readOccurrences(reader.getAttributeValue(null, ATT_XSD_MAX_OCCURS));
int minO = (reader.getAttributeValue(null, ATT_XSD_MIN_OCCURS) == null)
? 1 : this.readOccurrences(reader.getAttributeValue(null, ATT_XSD_MIN_OCCURS));
String defaultValue = reader.getAttributeValue(null, ATT_XSD_DEFAULT);
descs.add(this.readGeneralParameterDescriptor(dcn, minO, maxO, defaultValue));
} else if (TAG_XSD_DOCUMENTATION.equals(eName)) {
remarks = new DefaultInternationalString(reader.getElementText());
} else if (TAG_XSD_APP_INFO.equals(eName)) {
// String[] appInfoLine = reader.getElementText().split(":");
//
// if("codeSpace".equals(appInfoLine[0])){
// codeSpace = appInfoLine[1];
// }
// if("version".equals(appInfoLine[0])){
// version = appInfoLine[1];
// }
}
}
break;
case XMLStreamConstants.END_ELEMENT:
if (TAG_XSD_SEQUENCE.equals(reader.getLocalName())
&& URI_XSD.contains(reader.getNamespaceURI())) {
break boucle;
}
break;
}
}
properties.put("name", this.readName(descriptorCodeName, codeSpace, version));
properties.put("remarks", remarks);
return new DefaultParameterDescriptorGroup(properties, minimumOccurs, maximumOccurs,
descs.toArray(new GeneralParameterDescriptor[descs.size()]));
// return new DefaultParameterDescriptorGroup(
// name.getCode(),
// descriptors.toArray(new GeneralParameterDescriptor[descriptors.size()]));
}
/**
* <p>This method reads a descriptor name.</p>
*
* @param code
* @param codeSpace
* @param version
* @return
*/
private Identifier readName(
final String code, final String codeSpace, final String version) {
// Citation authority = null;
final Map<String, Object> properties = new HashMap<String, Object>();
properties.put("code", code);
// UNSUPPORTED PROPERTIES
// properties.put("authority", authority);
// properties.put("codespace", codeSpace);
// properties.put("version", version);
return new NamedIdentifier(properties);
//return new NamedIdentifier(authority, code, version);
//return new ImmutableIdentifier(authority, codeSpace, code, version, remarks);
}
/**
* <p>This method reads values with them type (default, maximum...).
* If a value has not particular type, ValueType is set to null.</p>
*
* @param c
* @return
* @throws XMLStreamException
* @throws ClassNotFoundException
*/
private SimpleEntry<ValuesTopology, SimpleEntry<Object, ValueType>[]> readValues(final Class c)
throws XMLStreamException, ClassNotFoundException {
final List<SimpleEntry<Object, ValueType>> values = new ArrayList<SimpleEntry<Object, ValueType>>();
String minString = null, maxString = null;
ValuesTopology topology = ValuesTopology.INTERVAL;
boucle:
while (reader.hasNext()) {
switch (reader.next()) {
case XMLStreamConstants.START_ELEMENT:
final String eName = reader.getLocalName();
final String eUri = reader.getNamespaceURI();
if (URI_XSD.equals(eUri)) {
// INTERVAL TOPOLOGY
if (TAG_XSD_MAX_INCLUSIVE.equals(eName)) {
ValueType tv = ValueType.MAX;
Object ov = ObjectConverters.convert(
reader.getAttributeValue(null, ATT_XSD_VALUE), c);
values.add(new SimpleEntry<Object, ValueType>(ov, tv));
} else if (TAG_XSD_MIN_INCLUSIVE.equals(eName)) {
ValueType tv = ValueType.MIN;
Object ov = ObjectConverters.convert(
reader.getAttributeValue(null, ATT_XSD_VALUE), c);
values.add(new SimpleEntry<Object, ValueType>(ov, tv));
} else if (TAG_XSD_PATTERN.equals(eName)) {
if (Boolean.class.equals(c)) {
ValueType tv = null;
Boolean ov = (Boolean) ObjectConverters.convert(
reader.getAttributeValue(null, ATT_XSD_VALUE), c);
tv = (ov) ? ValueType.MAX : ValueType.MIN;
values.add(new SimpleEntry<Object, ValueType>(ov, tv));
} else {
String tempString = reader.getAttributeValue(null, ATT_XSD_VALUE);
// Index of the beginning of variable pattern part
int idx = tempString.indexOf('[');
if (idx == -1) {
idx = tempString.length();
}
// Update of min and max CharSequences
if (idx > 0) {
tempString = tempString.substring(0, idx);
if (minString == null) {
minString = tempString;
maxString = minString;
} else if (tempString.compareTo(minString) < 0) {
minString = tempString;
} else if (tempString.compareTo(maxString) > 0) {
maxString = tempString;
}
}
}
} // DISCRETE TOPOLOGY
else if (TAG_XSD_ENUMERATION.equals(eName)) {
topology = ValuesTopology.DISCRETE;
ValueType tv = null;
Object ov = ObjectConverters.convert(
reader.getAttributeValue(null, ATT_XSD_VALUE), c);
values.add(new SimpleEntry<Object, ValueType>(ov, tv));
}
}
break;
case XMLStreamConstants.END_ELEMENT:
if (TAG_XSD_RESTRICTION.equals(reader.getLocalName())
&& URI_XSD.contains(reader.getNamespaceURI())) {
break boucle;
}
break;
}
}
// If String interval
if (minString != null) {
values.add(new SimpleEntry<Object, ValueType>(
ObjectConverters.convert(minString, c),
ValueType.MIN));
values.add(new SimpleEntry<Object, ValueType>(
ObjectConverters.convert(maxString, c),
ValueType.MAX));
}
return new SimpleEntry<ValuesTopology, SimpleEntry<Object, ValueType>[]>(
topology, values.toArray(new SimpleEntry[values.size()]));
}
}