/*
* 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 javax.xml.stream.XMLStreamException;
import org.geotoolkit.xml.StaxStreamWriter;
import org.opengis.parameter.GeneralParameterDescriptor;
import org.opengis.parameter.ParameterDescriptor;
import org.opengis.parameter.ParameterDescriptorGroup;
import static org.geotoolkit.xml.parameter.ParameterConstants.*;
import org.opengis.util.InternationalString;
/**
* <p>This class provides a GeneralParameterValue writing method.</p>
*
* @author Samuel Andrés
* @module
*/
public class ParameterDescriptorWriter extends StaxStreamWriter {
private static final String ANY_STRING = "[0-9a-zA-Z]*";
/**
* <p>Writes an XML Schema mapping parameterDescriptor.</p>
*
* @param generalParameterDescriptor
*/
public void write(final GeneralParameterDescriptor generalParameterDescriptor) throws XMLStreamException {
writer.writeStartDocument("UTF-8", "1.0");
writer.setDefaultNamespace(URI_XSD);
writer.writeStartElement(URI_XSD, TAG_XSD_SCHEMA);
writer.writeNamespace(PREFIX_PARAMETER, URI_PARAMETER);
writer.writeAttribute("targetNamespace", URI_PARAMETER);
writer.writeAttribute("elementFormDefault", "qualified");
this.writeGeneralParameterDescriptor(generalParameterDescriptor);
writer.writeEndElement();
writer.writeEndDocument();
writer.flush();
}
/**
* <p>This method writes a ParameterDescriptor.</p>
*
* @param descriptor
* @throws XMLStreamException
*/
private void writeParameterDescriptor(final ParameterDescriptor descriptor)
throws XMLStreamException {
if (descriptor.getDefaultValue() != null) {
writer.writeAttribute(ATT_XSD_DEFAULT, descriptor.getDefaultValue().toString());
}
/*
* ParameterDescriptor (simple descriptor) is mapped as a simple type
* with specified base type and restrictions.
*/
writer.writeStartElement(URI_XSD, TAG_XSD_SIMPLE_TYPE);
/*
* Annotations contains
* - Remarks (description tag)
* - other values used by descriptor reader, as Java mapping class canonical name.
*/
this.writeAnnotations(descriptor);
writer.writeStartElement(URI_XSD, TAG_XSD_RESTRICTION);
/*
* Writting base of restriction XSD type. Default : xsd:string
*/
if (Integer.class.equals(descriptor.getValueClass())) {
writer.writeAttribute(ATT_XSD_BASE, TYPE_XSD_INT);
} else if (Long.class.equals(descriptor.getValueClass())) {
writer.writeAttribute(ATT_XSD_BASE, TYPE_XSD_LONG);
} else if (Float.class.equals(descriptor.getValueClass())) {
writer.writeAttribute(ATT_XSD_BASE, TYPE_XSD_FLOAT);
} else if (Double.class.equals(descriptor.getValueClass())) {
writer.writeAttribute(ATT_XSD_BASE, TYPE_XSD_DOUBLE);
} else if (Boolean.class.equals(descriptor.getValueClass())) {
writer.writeAttribute(ATT_XSD_BASE, TYPE_XSD_BOOLEAN);
} else {
writer.writeAttribute(ATT_XSD_BASE, TYPE_XSD_STRING);
}
/*
* -------------- WRITTING RESTRICTIONS --------------------------------
*/
/*
* Discrete topology : values enumeration (numbers, CharSequences, Booleans)
*/
if (descriptor.getValidValues() != null) {
for (Object value : descriptor.getValidValues()) {
writer.writeStartElement(URI_XSD, TAG_XSD_ENUMERATION);
writer.writeAttribute(ATT_XSD_VALUE, value.toString());
writer.writeEndElement();
}
}
/*
* Interval topology
*/
else {
// CASE of String
if (String.class.equals(descriptor.getValueClass())) {
String max = (String) descriptor.getMaximumValue();
String min = (String) descriptor.getMinimumValue();
if (min != null && max != null) {
int idx = this.writeIntervalPatterns(min, max);
this.writeBottomPatterns(idx, min);
this.writeTopPatterns(idx, max);
} else if (min != null) {
this.writeBottomPatterns(-1, min);
} else if (max != null) {
this.writeTopPatterns(-1, max);
}
} // CASE of Boolean interval
else if (Boolean.class.equals(descriptor.getValueClass())) {
if (descriptor.getMinimumValue() != null) {
writer.writeStartElement(URI_XSD, TAG_XSD_PATTERN);
writer.writeAttribute(ATT_XSD_VALUE, descriptor.getMinimumValue().toString());
writer.writeEndElement();
}
if (descriptor.getMaximumValue() != null) {
writer.writeStartElement(URI_XSD, TAG_XSD_PATTERN);
writer.writeAttribute(ATT_XSD_VALUE, descriptor.getMaximumValue().toString());
writer.writeEndElement();
}
} // CASE of numeric values
else {
if (descriptor.getMinimumValue() != null) {
writer.writeStartElement(URI_XSD, TAG_XSD_MIN_INCLUSIVE);
writer.writeAttribute(ATT_XSD_VALUE, descriptor.getMinimumValue().toString());
writer.writeEndElement();
}
if (descriptor.getMaximumValue() != null) {
writer.writeStartElement(URI_XSD, TAG_XSD_MAX_INCLUSIVE);
writer.writeAttribute(ATT_XSD_VALUE, descriptor.getMaximumValue().toString());
writer.writeEndElement();
}
}
}
/*
* --------------- END OF WRITTING RESTRICTIONS ------------------------
*/
writer.writeEndElement();
writer.writeEndElement();
}
/**
* <p>This method writes generic pattern between two CharSequences.</p>
*
* @param min
* @param max
* @return index of first different character
* @throws XMLStreamException
*/
private int writeIntervalPatterns(final String min, final String max)
throws XMLStreamException {
final StringBuilder sb = new StringBuilder();
final int l = Math.min(min.length(), max.length());
int idx = 0;
for (int i = 0; i < l; i++) {
idx = i;
// When characters are different
if (min.charAt(i) < max.charAt(i)
&& Character.isLetterOrDigit((min.charAt(i) + 1))
&& Character.isLetterOrDigit((max.charAt(i) - 1))) {
sb.append('[');
sb.append((char) (min.charAt(i) + 1));
sb.append('-');
sb.append((char) (max.charAt(i) - 1));
sb.append(']');
break;
} // While characters are equal
else if (min.charAt(i) == max.charAt(i)) {
sb.append(min.charAt(i));
} // Last character
else if (i == l - 1) {
} else {
throw new UnsupportedOperationException("Maximal String value"
+ "has to be greater than minimal value");
}
}
writer.writeStartElement(URI_XSD, TAG_XSD_PATTERN);
writer.writeAttribute(ATT_XSD_VALUE, sb.toString() + ANY_STRING);
writer.writeEndElement();
return idx;
}
/**
* <p>This method writes patterns like maximum String</p>
*
* @param idx starting index
* @param max maximum String
* @throws XMLStreamException
*/
private void writeTopPatterns(final int idx, final String max)
throws XMLStreamException {
for (int i = idx + 1; i < max.length() - 1; i++) {
if (Character.isLetterOrDigit(max.charAt(i) - 1)) {
StringBuilder sb2 = new StringBuilder(max.substring(0, i));
sb2.append((char) (max.charAt(i) - 1));
writer.writeStartElement(URI_XSD, TAG_XSD_PATTERN);
writer.writeAttribute(ATT_XSD_VALUE, sb2.toString() + ANY_STRING);
writer.writeEndElement();
}
}
writer.writeStartElement(URI_XSD, TAG_XSD_PATTERN);
writer.writeAttribute(ATT_XSD_VALUE, max);
writer.writeEndElement();
}
/**
* <p>This methods writes patterns like minimum String.</p>
*
* @param idx starting index
* @param min minimum String
* @throws XMLStreamException
*/
private void writeBottomPatterns(final int idx, final String min)
throws XMLStreamException {
for (int i = idx + 1; i < min.length() - 1; i++) {
if (Character.isLetterOrDigit(min.charAt(i) + 1)) {
StringBuilder sb2 = new StringBuilder(min.substring(0, i));
sb2.append((char) (min.charAt(i) + 1));
writer.writeStartElement(URI_XSD, TAG_XSD_PATTERN);
writer.writeAttribute(ATT_XSD_VALUE, sb2.toString() + ANY_STRING);
writer.writeEndElement();
}
}
writer.writeStartElement(URI_XSD, TAG_XSD_PATTERN);
writer.writeAttribute(ATT_XSD_VALUE, min + ANY_STRING);
writer.writeEndElement();
}
/**
* <p>This method writes a ParameterDescriptorGroup</p>
*
* @param descriptor
* @throws XMLStreamException
*/
private void writeParameterDescriptorGroup(final ParameterDescriptorGroup descriptor)
throws XMLStreamException {
writer.writeStartElement(URI_XSD, TAG_XSD_COMPLEX_TYPE);
writer.writeStartElement(URI_XSD, TAG_XSD_SEQUENCE);
this.writeAnnotations(descriptor);
for (GeneralParameterDescriptor d : descriptor.descriptors()) {
this.writeGeneralParameterDescriptor(d);
}
writer.writeEndElement();
writer.writeEndElement();
}
/**
* <p>This method writes a general parameter descriptor</p>
*
* @param parameterDescriptor
* @throws XMLStreamException
*/
private void writeGeneralParameterDescriptor(final GeneralParameterDescriptor parameterDescriptor)
throws XMLStreamException {
/*
* Each descriptor is mapped as an element.
*/
writer.writeStartElement(URI_XSD, TAG_XSD_ELEMENT);
writer.writeAttribute(ATT_XSD_NAME,
parameterDescriptor.getName().getCode().replace(' ', '_'));
/*
* Writting occurrences
*/
if (parameterDescriptor.getMinimumOccurs() != 1) {
writer.writeAttribute(ATT_XSD_MIN_OCCURS,
String.valueOf(parameterDescriptor.getMinimumOccurs()));
}
if (parameterDescriptor.getMaximumOccurs() != 1) {
if (parameterDescriptor.getMaximumOccurs() == Integer.MAX_VALUE) {
writer.writeAttribute(ATT_XSD_MAX_OCCURS, VAL_XSD_UNBOUNDED);
} else {
writer.writeAttribute(ATT_XSD_MAX_OCCURS,
String.valueOf(parameterDescriptor.getMaximumOccurs()));
}
}
/*
* ParameterDescriptor or ParameterDescriptorGroup ?
*/
if (parameterDescriptor instanceof ParameterDescriptor) {
this.writeParameterDescriptor((ParameterDescriptor) parameterDescriptor);
} else if (parameterDescriptor instanceof ParameterDescriptorGroup) {
this.writeParameterDescriptorGroup((ParameterDescriptorGroup) parameterDescriptor);
}
writer.writeEndElement();
}
/**
* <p>Wtites annotations (remarks and app infos)</p>
*
* @param parameterDescriptor
* @throws XMLStreamException
*/
private void writeAnnotations(final GeneralParameterDescriptor parameterDescriptor)
throws XMLStreamException {
if (parameterDescriptor.getRemarks() != null
|| parameterDescriptor.getName().getCodeSpace() != null
|| parameterDescriptor.getName().getVersion() != null
|| parameterDescriptor instanceof ParameterDescriptor) {
writer.writeStartElement(URI_XSD, TAG_XSD_ANNOTATION);
// Java mapping class canonical name
if (parameterDescriptor instanceof ParameterDescriptor) {
this.writeAppInfo("valueClass",
((ParameterDescriptor) parameterDescriptor).getValueClass().getCanonicalName());
}
// if(parameterDescriptor.getName().getCodeSpace() != null){
// this.writeAppInfo("codeSpace",parameterDescriptor.getName().getCodeSpace());
// }
// if(parameterDescriptor.getName().getVersion() != null){
// this.writeAppInfo("version",parameterDescriptor.getName().getVersion());
// }
// Remarks are written as documentation.
if (parameterDescriptor.getRemarks() != null) {
this.writeRemarks(parameterDescriptor.getRemarks());
}
writer.writeEndElement();
}
}
/**
* <p>This method writes remarks.</p>
*
* @param remarks
* @throws XMLStreamException
*/
private void writeRemarks(final InternationalString remarks)
throws XMLStreamException {
writer.writeStartElement(URI_XSD, TAG_XSD_DOCUMENTATION);
writer.writeCharacters(remarks.toString());
writer.writeEndElement();
}
/**
* <p>writes app infos.</p>
*
* @param pseudoTag
* @param info
* @throws XMLStreamException
*/
private void writeAppInfo(final String pseudoTag, final String info)
throws XMLStreamException {
writer.writeStartElement(URI_XSD, TAG_XSD_APP_INFO);
writer.writeCharacters(pseudoTag + ":" + info);
writer.writeEndElement();
}
}