View Javadoc
1   /*
2    * (c) Copyright 2006-2020 by rapiddweller GmbH & Volker Bergmann. All rights reserved.
3    *
4    * Redistribution and use in source and binary forms, with or without
5    * modification, is permitted under the terms of the
6    * GNU General Public License.
7    *
8    * For redistributing this software or a derivative work under a license other
9    * than the GPL-compatible Free Software License as defined by the Free
10   * Software Foundation or approved by OSI, you must first obtain a commercial
11   * license to this software product from rapiddweller GmbH & Volker Bergmann.
12   *
13   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
14   * WITHOUT A WARRANTY OF ANY KIND. ALL EXPRESS OR IMPLIED CONDITIONS,
15   * REPRESENTATIONS AND WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF
16   * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE
17   * HEREBY EXCLUDED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
18   * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21   * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22   * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24   * POSSIBILITY OF SUCH DAMAGE.
25   */
26  
27  package com.rapiddweller.platform.xml;
28  
29  import com.rapiddweller.benerator.consumer.AbstractConsumer;
30  import com.rapiddweller.benerator.consumer.FileExporter;
31  import com.rapiddweller.common.ConfigurationError;
32  import com.rapiddweller.common.IOUtil;
33  import com.rapiddweller.common.StringUtil;
34  import com.rapiddweller.common.SystemInfo;
35  import com.rapiddweller.common.converter.ToStringConverter;
36  import com.rapiddweller.model.data.ComplexTypeDescriptor;
37  import com.rapiddweller.model.data.Entity;
38  import org.apache.logging.log4j.LogManager;
39  import org.apache.logging.log4j.Logger;
40  import org.xml.sax.SAXException;
41  import org.xml.sax.helpers.AttributesImpl;
42  
43  import javax.xml.transform.OutputKeys;
44  import javax.xml.transform.Transformer;
45  import javax.xml.transform.TransformerConfigurationException;
46  import javax.xml.transform.sax.SAXTransformerFactory;
47  import javax.xml.transform.sax.TransformerHandler;
48  import javax.xml.transform.stream.StreamResult;
49  import java.io.FileNotFoundException;
50  import java.io.FileOutputStream;
51  import java.io.OutputStream;
52  import java.util.Map;
53  
54  /**
55   * Writes Entities to an XML file.<br/><br/>
56   * Created: 20.02.2008 15:39:23
57   *
58   * @author Volker Bergmann
59   * @since 0.5.0
60   */
61  public class XMLEntityExporter extends AbstractConsumer implements FileExporter {
62  
63    private static final Logger LOGGER = LogManager.getLogger(XMLEntityExporter.class);
64  
65    // defaults --------------------------------------------------------------------------------------------------------
66  
67    private static final String DEFAULT_ENCODING = SystemInfo.getFileEncoding();
68    private static final String DEFAULT_URI = "export.xml";
69  
70    private static final ToStringConverter converter = new ToStringConverter("", "yyyy-MM-dd", "yyyy-MM-dd'T'hh:mm:ss.SSS");
71  
72    // attributes ------------------------------------------------------------------------------------------------------
73  
74    private String uri;
75    private String encoding;
76  
77    private OutputStream out;
78    private TransformerHandler handler;
79  
80    // constructors ----------------------------------------------------------------------------------------------------
81  
82    /**
83     * Instantiates a new Xml entity exporter.
84     */
85    public XMLEntityExporter() {
86      this(DEFAULT_URI);
87    }
88  
89    /**
90     * Instantiates a new Xml entity exporter.
91     *
92     * @param uri the uri
93     */
94    public XMLEntityExporter(String uri) {
95      this(uri, DEFAULT_ENCODING);
96    }
97  
98    /**
99     * Instantiates a new Xml entity exporter.
100    *
101    * @param uri      the uri
102    * @param encoding the encoding
103    */
104   public XMLEntityExporter(String uri, String encoding) {
105     this.uri = uri;
106     this.encoding = encoding;
107   }
108 
109   // properties ------------------------------------------------------------------------------------------------------
110 
111   private static boolean hasSimpleType(Object value) {
112     return (!value.getClass().isArray() && !(value instanceof Entity));
113   }
114 
115   @Override
116   public String getUri() {
117     return uri;
118   }
119 
120   /**
121    * Sets uri.
122    *
123    * @param uri the uri
124    */
125   public void setUri(String uri) {
126     this.uri = uri;
127   }
128 
129   // Consumer interface ----------------------------------------------------------------------------------------------
130 
131   /**
132    * Sets encoding.
133    *
134    * @param encoding the encoding
135    */
136   public void setEncoding(String encoding) {
137     this.encoding = encoding;
138   }
139 
140   @Override
141   public void startProductConsumption(Object object) {
142     LOGGER.debug("startConsuming({})", object);
143     if (out == null) {
144       initHandler();
145     }
146     Entity../../../../com/rapiddweller/model/data/Entity.html#Entity">Entity entity = (Entity) object;
147     renderElementStart(entity);
148   }
149 
150   @Override
151   public void finishProductConsumption(Object object) {
152     LOGGER.debug("finishConsuming({})", object);
153     Entity../../../../com/rapiddweller/model/data/Entity.html#Entity">Entity entity = (Entity) object;
154     try {
155       handler.endElement("", "", entity.type());
156     } catch (SAXException e) {
157       throw new ConfigurationError("Error in processing element: " + entity, e);
158     }
159   }
160 
161   @Override
162   public void flush() {
163     IOUtil.flush(out);
164   }
165 
166   // private helpers -------------------------------------------------------------------------------------------------
167 
168   @Override
169   public void close() {
170     if (out != null) {
171       try {
172         if (handler != null) {
173           handler.endDocument();
174           handler = null;
175         }
176       } catch (SAXException e) {
177         throw new ConfigurationError("Error closing XML file.", e);
178       } finally {
179         IOUtil.close(out);
180       }
181     }
182   }
183 
184   private void renderSimpleType(Object value) throws SAXException {
185     String s = converter.convert(value);
186     char[] cc = StringUtil.getChars(s);
187     handler.characters(cc, 0, cc.length);
188   }
189 
190   private void renderElementStart(Entity entity) {
191     try {
192       AttributesImpl atts = new AttributesImpl();
193       for (Map.Entry<String, Object> entry : entity.getComponents().entrySet()) {
194         String key = entry.getKey();
195         Object value = entry.getValue();
196         if (value == null) {
197           continue;
198         }
199         if (key != null && !ComplexTypeDescriptor.__SIMPLE_CONTENT.equals(key) && hasSimpleType(value)) {
200           atts.addAttribute("", "", entry.getKey(), "CDATA", converter.convert(value));
201         }
202       }
203       handler.startElement("", "", entity.type(), atts);
204       Object content = entity.getComponent(ComplexTypeDescriptor.__SIMPLE_CONTENT);
205       if (content != null) {
206         renderSimpleType(content);
207       }
208     } catch (SAXException e) {
209       throw new ConfigurationError("Error in processing element: " + entity, e);
210     }
211   }
212 
213   private void initHandler() {
214     LOGGER.debug("Initializing {}", uri);
215     // create file
216     try {
217       // create file and write header
218       SAXTransformerFactory tf = (SAXTransformerFactory) SAXTransformerFactory.newInstance();
219       handler = tf.newTransformerHandler();
220 
221       Transformer transformer = handler.getTransformer();
222       transformer.setOutputProperty(OutputKeys.ENCODING, encoding);
223       transformer.setOutputProperty(OutputKeys.INDENT, "yes");
224       transformer.setOutputProperty("{http://xml.apache.org/xslt}" + "indent-amount", "2");
225 
226       out = new FileOutputStream(uri);
227       handler.setResult(new StreamResult(out));
228       handler.startDocument();
229     } catch (TransformerConfigurationException e) {
230       throw new ConfigurationError(e);
231     } catch (SAXException e) {
232       throw new ConfigurationError("Error in initializing XML file", e);
233     } catch (FileNotFoundException e) {
234       throw new RuntimeException("Error writing file " + uri, e);
235     }
236   }
237 
238   // java.lang.Object overrides --------------------------------------------------------------------------------------
239 
240   @Override
241   public String toString() {
242     return getClass().getSimpleName() + '[' + uri + ']';
243   }
244 
245 }