001package org.javasimon.console.action;
002
003import org.javasimon.Sample;
004import org.javasimon.Simon;
005import org.javasimon.console.Action;
006import org.javasimon.console.ActionContext;
007import org.javasimon.console.ActionException;
008import org.javasimon.console.SimonType;
009import org.javasimon.console.SimonTypeFactory;
010import org.javasimon.console.TimeFormatType;
011import org.javasimon.console.reflect.Getter;
012import org.javasimon.console.reflect.GetterFactory;
013import org.javasimon.console.text.Stringifier;
014import org.javasimon.console.text.StringifierFactory;
015import org.w3c.dom.Document;
016import org.w3c.dom.Element;
017
018import java.io.IOException;
019import java.util.Iterator;
020
021import javax.servlet.ServletException;
022import javax.xml.parsers.DocumentBuilder;
023import javax.xml.parsers.DocumentBuilderFactory;
024import javax.xml.parsers.ParserConfigurationException;
025import javax.xml.transform.Transformer;
026import javax.xml.transform.TransformerException;
027import javax.xml.transform.TransformerFactory;
028import javax.xml.transform.dom.DOMSource;
029import javax.xml.transform.stream.StreamResult;
030
031/**
032 * Base for actions returning data in XML format.
033 *
034 * @author gquintana
035 */
036public abstract class AbstractXmlAction extends Action {
037
038        protected AbstractXmlAction(ActionContext context) {
039                super(context);
040        }
041
042        /** Converter Object → HTML String. */
043        protected final StringifierFactory stringifierFactory = new StringifierFactory();
044
045        @Override
046        public void readParameters() {
047                final TimeFormatType timeFormat = getContext().getParameterAsEnum("timeFormat", TimeFormatType.class, TimeFormatType.MILLISECOND);
048                stringifierFactory.init(timeFormat,
049                        StringifierFactory.ISO_DATE_PATTERN,
050                        StringifierFactory.READABLE_NUMBER_PATTERN
051                );
052        }
053
054        /**
055         * Transforms a Simon into a JSON object.
056         *
057         * @param simon Simon
058         * @return JSON object
059         */
060        @SuppressWarnings("unchecked")
061        protected Element createElement(Document document, Simon simon) {
062                // Simon type is used as element name
063                Sample sample = simon.sample();
064                SimonType lType = SimonTypeFactory.getValueFromInstance(sample);
065                Element element = document.createElement(lType.name().toLowerCase());
066                // Only to have the name as first attribute
067                element.setAttribute("name", sample.getName());
068                // Export properties using reflection
069                for (Getter getter : GetterFactory.getGetters(sample.getClass())) {
070                        Object propertyValue = getter.get(sample);
071                        if (propertyValue != null) {
072                                Stringifier propertyStringifier = stringifierFactory
073                                        .getStringifier(getter.getType(), getter.getSubType());
074                                if (propertyStringifier != null) {
075                                        element.setAttribute(getter.getName(), propertyStringifier.toString(propertyValue));
076                                }
077                        }
078                }
079                // Export attribute map
080                Iterator<String> attributeNameIter = simon.getAttributeNames();
081                while (attributeNameIter.hasNext()) {
082                        String attributeName = attributeNameIter.next();
083                        Object attributeValue = simon.getAttribute(attributeName);
084                        if (attributeValue != null) {
085                                Stringifier attributeStringifier = stringifierFactory
086                                        .getStringifier(attributeValue.getClass());
087                                if (attributeStringifier != null) {
088                                        Element attributeElt = document.createElement("attribute");
089                                        attributeElt.setAttribute("name", attributeName);
090                                        attributeElt.setAttribute("value", attributeStringifier.toString(attributeValue));
091                                        element.appendChild(attributeElt);
092                                }
093                        }
094
095                }
096                return element;
097
098        }
099
100        @Override
101        public void execute() throws ServletException, IOException, ActionException {
102                dontCache();
103                getContext().setContentType("text/xml");
104                try {
105                        DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
106                        DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
107                        Document document = documentBuilder.newDocument();
108                        fillDocument(document);
109                        TransformerFactory transformerFactory = TransformerFactory.newInstance();
110                        Transformer transformer = transformerFactory.newTransformer();
111                        transformer.transform(new DOMSource(document),
112                                new StreamResult(getContext().getOutputStream()));
113                } catch (ParserConfigurationException | TransformerException parserConfigurationException) {
114                        throw new ActionException("XML Parser error", parserConfigurationException);
115                } finally {
116                        getContext().getOutputStream().flush();
117                }
118        }
119
120        protected abstract void fillDocument(Document document);
121}