/* * 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.io.IOException; import java.lang.reflect.Array; import java.net.URI; import java.nio.file.Path; import java.nio.file.Paths; import java.util.*; import javax.xml.stream.XMLStreamConstants; import javax.xml.stream.XMLStreamException; import org.geotoolkit.parameter.Parameter; import org.geotoolkit.parameter.ParameterGroup; import org.apache.sis.util.ObjectConverters; import org.geotoolkit.xml.StaxStreamReader; import org.opengis.parameter.GeneralParameterDescriptor; import org.opengis.parameter.GeneralParameterValue; import org.opengis.parameter.ParameterDescriptor; import org.opengis.parameter.ParameterDescriptorGroup; import org.opengis.parameter.ParameterValueGroup; import static org.geotoolkit.xml.parameter.ParameterConstants.*; import org.opengis.parameter.ParameterNotFoundException; /** * <p>This class provides a GeneralParameterValue reading method.</p> * * @author Samuel Andrés * @module */ public class ParameterValueReader extends StaxStreamReader { private final GeneralParameterDescriptor rootDesc ; private final Deque<GeneralParameterDescriptor> stack = new ArrayDeque<GeneralParameterDescriptor>(); /** * <p>Constructs the value reader with a descriptor reader.</p> * * @param descriptorReader */ public ParameterValueReader(final ParameterDescriptorReader descriptorReader) throws IOException, XMLStreamException, ClassNotFoundException{ descriptorReader.read(); rootDesc = descriptorReader.getDescriptorsRoot(); descriptorReader.dispose(); } /** * <p>Construct the value reader with its associated descriptor.</p> * * @param descriptor */ public ParameterValueReader(final GeneralParameterDescriptor descriptor){ rootDesc = descriptor; } /** * <p>This method reads a parameter document whose root is * a GeneralParameterValue</p> * * @return */ public GeneralParameterValue read() throws XMLStreamException { while (reader.hasNext()) { switch (reader.next()) { case XMLStreamConstants.START_ELEMENT: final String eName = reader.getLocalName(); final String eUri = reader.getNamespaceURI(); if (URI_PARAMETER.equals(eUri)) { return this.readValue(eName); } break; } } return null; } /** * <p>This method reads a general value.</p> * * @param eName * @return * @throws XMLStreamException */ private GeneralParameterValue readValue(final String eName) throws XMLStreamException{ GeneralParameterDescriptor desc = stack.peekFirst(); desc = getDescriptor(desc, eName); stack.addFirst(desc); //push final GeneralParameterValue result; if(desc instanceof ParameterDescriptor){ Class targetClass = ((ParameterDescriptor) desc).getValueClass(); Object converted = null; //HACK for Path support // we don't use ObjectConverters to convert Path from a String because // there is an already existing converter that doesn't use protocol (URI scheme) if (Path.class.isAssignableFrom(targetClass)) { final String text = reader.getElementText(); if (!text.isEmpty()) { URI uri = URI.create(text); if (uri.getScheme() != null) { //may target a path on another file system converted = Paths.get(uri); } else { //assume path is on current file system (relative of absolute) converted = Paths.get(text); } } } else if (targetClass.isArray()) { List<Object> converteds = new ArrayList<>(); boucle: while (reader.hasNext()) { switch (reader.next()) { case XMLStreamConstants.START_ELEMENT: converteds.add(ObjectConverters.convert(reader.getElementText(), targetClass.getComponentType())); break; case XMLStreamConstants.END_ELEMENT: if (desc.getName().getCode().equals(reader.getLocalName()) && URI_PARAMETER.contains(reader.getNamespaceURI())) { break boucle; } break; } } converted = Array.newInstance(targetClass.getComponentType(), converteds.size()); for (int i = 0 ; i < converteds.size(); i++) { Array.set(converted, i, converteds.get(i)); } } else { final String text = reader.getElementText(); if (!text.isEmpty()) { converted = ObjectConverters.convert(text, targetClass); } } if (converted != null) { result = new Parameter((ParameterDescriptor) desc,converted); } else { result = null; } } else if(desc instanceof ParameterDescriptorGroup){ result = this.readValueGroup(); } else { result = null; } stack.removeFirst(); //pop return result; } /** * <p>This method reads a value group</p> * * @param desc * @return * @throws XMLStreamException */ private ParameterValueGroup readValueGroup() throws XMLStreamException{ final ParameterDescriptorGroup desc = (ParameterDescriptorGroup) stack.peekFirst(); final List<GeneralParameterValue> values = new ArrayList<GeneralParameterValue>(); boucle: while (reader.hasNext()) { switch (reader.next()) { case XMLStreamConstants.START_ELEMENT: final GeneralParameterValue value = this.readValue(reader.getLocalName()); if (value != null) { values.add(value); } break; case XMLStreamConstants.END_ELEMENT: if (desc.getName().getCode().equals(reader.getLocalName()) && URI_PARAMETER.contains(reader.getNamespaceURI())) { break boucle; } break; } } //try to fill missing parameters for(GeneralParameterDescriptor candidate : desc.descriptors()){ final int minOcc = candidate.getMinimumOccurs(); if(minOcc == 0) continue; int count = 0; for(GeneralParameterValue val : values){ if(val.getDescriptor().equals(candidate)){ count++; } } //create missing values for(;count<minOcc;count++){ values.add(candidate.createValue()); } } return new ParameterGroup( desc, values.toArray(new GeneralParameterValue[values.size()])); } private GeneralParameterDescriptor getDescriptor(GeneralParameterDescriptor desc, String name) throws XMLStreamException{ if(desc == null){ if(!rootDesc.getName().getCode().equals(name) && !rootDesc.getName().getCode().equals(name.replace('_', ' '))){ throw new XMLStreamException("Descriptor for name : "+name+" not found."); } return rootDesc; }else{ if(!(desc instanceof ParameterDescriptorGroup)){ throw new XMLStreamException("Was expecting a descriptor group for name : " + name); } ParameterDescriptorGroup pdg = (ParameterDescriptorGroup) desc; GeneralParameterDescriptor candidate = null; try{ return pdg.descriptor(name); }catch(ParameterNotFoundException ex){ //second try name = name.replace('_', ' '); } try{ return pdg.descriptor(name); }catch(ParameterNotFoundException ex){ throw new XMLStreamException("Descriptor for name : "+name+" not found."); } } } }