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", new Integer(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.toSource(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 }