001/*
002 *  Copyright 2018 Anyware Services
003 *
004 *  Licensed under the Apache License, Version 2.0 (the "License");
005 *  you may not use this file except in compliance with the License.
006 *  You may obtain a copy of the License at
007 *
008 *      http://www.apache.org/licenses/LICENSE-2.0
009 *
010 *  Unless required by applicable law or agreed to in writing, software
011 *  distributed under the License is distributed on an "AS IS" BASIS,
012 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 *  See the License for the specific language governing permissions and
014 *  limitations under the License.
015 */
016package org.ametys.runtime.model.type.xml;
017
018import java.lang.reflect.Array;
019import java.util.ArrayList;
020import java.util.List;
021
022import org.apache.avalon.framework.configuration.Configuration;
023import org.apache.avalon.framework.configuration.ConfigurationException;
024import org.apache.cocoon.xml.XMLUtils;
025import org.apache.commons.lang3.StringUtils;
026import org.xml.sax.ContentHandler;
027import org.xml.sax.SAXException;
028
029import org.ametys.runtime.model.exception.BadItemTypeException;
030import org.ametys.runtime.model.type.ElementType;
031
032/**
033 * Interfaces for XML parameter types
034 * @param <T> Type of the parameter value
035 */
036public interface XMLElementType<T> extends ElementType<T>
037{
038    /**
039     * Read the value in the given XML configuration
040     * @param parentConfiguration XML configuration containing the value
041     * @param name the name of the element to read
042     * @return the value
043     * @throws ConfigurationException if an error occurs while reading the given configuration
044     */
045    public default Object read(Configuration parentConfiguration, String name) throws ConfigurationException
046    {
047        Configuration elementConfiguration = parentConfiguration.getChild(name);
048        
049        return readValueFromNode(elementConfiguration);
050    }
051    
052    /**
053     * Read the value in the given XML configuration (the node directly, not the parent configuration)
054     * @param elementConfiguration XML configuration node containing the value
055     * @return the value
056     * @throws ConfigurationException if an error occurs while reading the given configuration
057     */
058    public default Object readValueFromNode(Configuration elementConfiguration) throws ConfigurationException
059    {
060        if (elementConfiguration == null)
061        {
062            return null;
063        }
064        
065        // Multiple element management
066        Configuration[] valuesConfiguration = elementConfiguration.getChildren("value");
067        if (valuesConfiguration.length > 0)
068        {
069            List<T> values = new ArrayList<>();
070            for (Configuration valueConfiguration : valuesConfiguration)
071            {
072                T value = parseConfiguration(valueConfiguration);
073                if (value != null)
074                {
075                    values.add(value);
076                }
077            }
078            return Array.newInstance(getManagedClass(), values.size());
079        }
080        else
081        {
082            // Simple element management
083            return parseConfiguration(elementConfiguration);
084        }
085    }
086    
087    /**
088     * Write the value into the given content handler
089     * @param contentHandler the content handler where to SAX into.
090     * @param name the name of the element to write
091     * @param value the value to write
092     * @throws SAXException if an errors occurs during the value writing
093     * @throws BadItemTypeException If the given value doesn't match this element type
094     */
095    @SuppressWarnings("unchecked")
096    public default void write(ContentHandler contentHandler, String name, Object value) throws SAXException, BadItemTypeException
097    {
098        if (value == null)
099        {
100            XMLUtils.createElement(contentHandler, name);
101        }
102        else if (getManagedClass().isInstance(value))
103        {
104            XMLUtils.createElement(contentHandler, name, StringUtils.defaultString(toString((T) value)));
105        }
106        else if (getManagedClassArray().isInstance(value))
107        {
108            XMLUtils.startElement(contentHandler, name);
109            for (T singleValue : (T[]) value)
110            {
111                XMLUtils.createElement(contentHandler, "value", StringUtils.defaultString(toString(singleValue)));
112            }
113            XMLUtils.endElement(contentHandler, name);
114        }
115        else
116        {
117            throw new BadItemTypeException("Try to write the non " + getManagedClass().getName() + " value '" + value + "' on element named '" + name + "'");
118        }
119    }
120}