001    /**
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     *
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    package org.apache.camel.view;
018    
019    import java.io.File;
020    import java.io.FileNotFoundException;
021    import java.io.FileOutputStream;
022    import java.io.IOException;
023    import java.io.OutputStream;
024    import java.io.OutputStreamWriter;
025    import java.util.List;
026    import java.util.Properties;
027    
028    import javax.xml.bind.Binder;
029    import javax.xml.bind.JAXBContext;
030    import javax.xml.bind.JAXBException;
031    import javax.xml.bind.annotation.XmlRootElement;
032    import javax.xml.parsers.ParserConfigurationException;
033    import javax.xml.transform.OutputKeys;
034    import javax.xml.transform.Result;
035    import javax.xml.transform.TransformerException;
036    import javax.xml.transform.TransformerFactory;
037    import javax.xml.transform.stream.StreamResult;
038    
039    import org.w3c.dom.Document;
040    import org.w3c.dom.Element;
041    import org.w3c.dom.Node;
042    
043    import org.apache.camel.RuntimeCamelException;
044    import org.apache.camel.RuntimeTransformException;
045    import org.apache.camel.builder.xml.Namespaces;
046    import org.apache.camel.converter.jaxp.XmlConverter;
047    import org.apache.camel.model.RouteDefinition;
048    import org.apache.camel.model.RoutesDefinition;
049    import org.apache.camel.util.ObjectHelper;
050    
051    public class ModelFileGenerator {
052    
053        private static final String DEFAULT_ROOT_ELEMENT_NAME = "routes";
054        private final JAXBContext jaxbContext;
055        private Binder<Node> binder;
056    
057        public ModelFileGenerator(JAXBContext jaxbContext) {
058            this.jaxbContext = jaxbContext;
059        }
060    
061        /**
062         * Write the specified 'routeTypes' to 'fileName' as XML using JAXB.
063         */
064        public void marshalRoutesUsingJaxb(String fileName, List<RouteDefinition> routeTypes) throws IOException {
065            OutputStream outputStream = outputStream(fileName);
066    
067            try {
068                XmlConverter converter = converter();
069                Document doc = converter.createDocument();
070    
071                Element root = doc.createElement(rootElementName());
072                root.setAttribute("xmlns", Namespaces.DEFAULT_NAMESPACE);
073                doc.appendChild(root);
074    
075                for (RouteDefinition routeType : routeTypes) {
076                    addJaxbElementToNode(root, routeType);
077                }
078    
079                Result result = new StreamResult(new OutputStreamWriter(outputStream, XmlConverter.defaultCharset));
080    
081                copyToResult(converter, doc, result);
082            } catch (ParserConfigurationException e) {
083                throw new RuntimeTransformException(e);
084            } catch (TransformerException e) {
085                throw new RuntimeTransformException(e);
086            } finally {
087                outputStream.close();
088            }
089        }
090    
091        /**
092         * Returns a configured XmlConverter
093         */
094        private XmlConverter converter() {
095            XmlConverter converter = new XmlConverter();
096            TransformerFactory transformerFactory = converter.getTransformerFactory();
097            transformerFactory.setAttribute("indent-number", 2);
098            return converter;
099        }
100    
101        /**
102         * Copies the given input Document into the required result using the provided converter.
103         */
104        private void copyToResult(XmlConverter converter, Document doc, Result result) throws TransformerException {
105            Properties outputProperties = converter.defaultOutputProperties();
106            outputProperties.put(OutputKeys.OMIT_XML_DECLARATION, "no");
107            outputProperties.put(OutputKeys.INDENT, "yes");
108    
109            converter.toResult(converter.toDOMSource(doc), result, outputProperties);
110        }
111    
112        /**
113         * Convert the specified object into XML and add it as a child of 'node' using JAXB.
114         */
115        private void addJaxbElementToNode(Node node, Object jaxbElement) {
116            try {
117                if (binder == null) {
118                    binder = jaxbContext.createBinder();
119                }
120                binder.marshal(jaxbElement, node);
121            } catch (JAXBException e) {
122                throw new RuntimeCamelException(e);
123            }
124        }
125    
126        /**
127         * Return the root element name for the list of routes.
128         */
129        private String rootElementName() {
130            XmlRootElement annotation = (RoutesDefinition.class).getAnnotation(XmlRootElement.class);
131            if (annotation != null) {
132                String elementName = annotation.name();
133                if (ObjectHelper.isNotEmpty(elementName)) {
134                    return elementName;
135                }
136            }
137            return DEFAULT_ROOT_ELEMENT_NAME;
138        }
139    
140        /**
141         * returns an output stream for the filename specified.
142         */
143        private OutputStream outputStream(String fileName) throws FileNotFoundException {
144            File file = new File(fileName);
145            if (!file.exists()) {
146                File parentFile = file.getParentFile();
147                if (parentFile != null) {
148                    parentFile.mkdirs();
149                }
150            }
151            return new FileOutputStream(file);
152        }
153    }