View Javadoc
1   /*
2    * This file is part of Waarp Project (named also Waarp or GG).
3    *
4    *  Copyright (c) 2019, Waarp SAS, and individual contributors by the @author
5    *  tags. See the COPYRIGHT.txt in the distribution for a full listing of
6    * individual contributors.
7    *
8    *  All Waarp Project is free software: you can redistribute it and/or
9    * modify it under the terms of the GNU General Public License as published by
10   * the Free Software Foundation, either version 3 of the License, or (at your
11   * option) any later version.
12   *
13   * Waarp is distributed in the hope that it will be useful, but WITHOUT ANY
14   * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
15   * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
16   *
17   *  You should have received a copy of the GNU General Public License along with
18   * Waarp . If not, see <http://www.gnu.org/licenses/>.
19   */
20  
21  package org.waarp.openr66.protocol.http.restv2.utils;
22  
23  import org.waarp.common.exception.InvalidArgumentException;
24  import org.waarp.common.file.FileUtils;
25  import org.waarp.common.utility.ParametersChecker;
26  import org.waarp.openr66.protocol.http.restv2.errors.RestErrorException;
27  import org.waarp.openr66.protocol.http.restv2.errors.RestErrors;
28  
29  import javax.ws.rs.InternalServerErrorException;
30  import javax.xml.XMLConstants;
31  import javax.xml.bind.JAXBContext;
32  import javax.xml.bind.JAXBException;
33  import javax.xml.bind.Marshaller;
34  import javax.xml.bind.Unmarshaller;
35  import javax.xml.transform.Source;
36  import javax.xml.transform.Transformer;
37  import javax.xml.transform.TransformerConfigurationException;
38  import javax.xml.transform.TransformerException;
39  import javax.xml.transform.TransformerFactory;
40  import javax.xml.transform.stream.StreamResult;
41  import javax.xml.transform.stream.StreamSource;
42  import java.io.BufferedReader;
43  import java.io.FileNotFoundException;
44  import java.io.FileReader;
45  import java.io.FileWriter;
46  import java.io.IOException;
47  import java.io.StringReader;
48  import java.io.StringWriter;
49  
50  import static javax.xml.transform.OutputKeys.*;
51  
52  /**
53   * A series of utility methods for serializing and deserializing XML.
54   */
55  public final class XmlUtils {
56  
57    /**
58     * Prevents the default constructor from being called.
59     */
60    private XmlUtils() throws InstantiationException {
61      throw new InstantiationException(
62          getClass().getName() + " cannot be instantiated.");
63    }
64  
65    // ######################### PUBLIC METHODS #################################
66  
67    /**
68     * Converts a serializable Java object into XML format as a String.
69     *
70     * @param object the object to convert to XML
71     *
72     * @return the object's representation in XML
73     *
74     * @throws InternalServerErrorException if an unexpected error
75     *     occurred
76     */
77    public static String objectToXml(final XmlSerializable object) {
78      try {
79        final StringWriter writer = new StringWriter();
80        final JAXBContext context = JAXBContext.newInstance(object.getClass());
81        final Marshaller marshaller = context.createMarshaller();
82        marshaller.setProperty(Marshaller.JAXB_FRAGMENT, true);
83        marshaller.marshal(object, writer);
84  
85        return writer.toString();
86      } catch (final JAXBException e) {
87        throw new InternalServerErrorException(e);
88      }
89    }
90  
91    /**
92     * Converts an XML String into a serializable Java object.
93     *
94     * @param xml the string to convert into an object
95     * @param clazz the class of the serializable object
96     *
97     * @return the deserialized Java object
98     *
99     * @throws InternalServerErrorException if an unexpected error
100    *     occurred
101    */
102   public static <T extends XmlSerializable> T xmlToObject(final String xml,
103                                                           final Class<T> clazz) {
104     try {
105       ParametersChecker.checkSanityString(xml);
106     } catch (final InvalidArgumentException e) {
107       throw new InternalServerErrorException(e);
108     }
109     try {
110       final StringReader reader = new StringReader(xml);
111       final StreamSource source = new StreamSource(reader);
112       final JAXBContext context = JAXBContext.newInstance(clazz);
113       final Unmarshaller unmarshaller = context.createUnmarshaller();
114 
115       return unmarshaller.unmarshal(source, clazz).getValue();
116     } catch (final JAXBException e) {
117       throw new InternalServerErrorException(e);
118     }
119   }
120 
121   /**
122    * Saves an XML String to a file at the given location.
123    *
124    * @param xml the XML String
125    * @param filePath the path where to save the XML file
126    *
127    * @throws InternalServerErrorException if an unexpected error
128    *     occurred
129    */
130   public static void saveXML(final String xml, final String filePath) {
131     try {
132       ParametersChecker.checkSanityString(xml);
133     } catch (final InvalidArgumentException e) {
134       throw new InternalServerErrorException(e);
135     }
136     FileWriter fileWriter = null;
137     try {
138       fileWriter = new FileWriter(filePath, false);
139       final String formattedXML = pretty(xml);
140       fileWriter.write(formattedXML);
141       fileWriter.flush();
142     } catch (final IOException e) {
143       throw new InternalServerErrorException(e);
144     } finally {
145       FileUtils.close(fileWriter);
146     }
147   }
148 
149   /**
150    * Loads an XML file into a String.
151    *
152    * @param filePath the path of the XML file to load
153    *
154    * @return the content of the XML file
155    *
156    * @throws InternalServerErrorException if an unexpected error
157    *     occurred
158    */
159   public static String loadXML(final String filePath) {
160     FileReader fr = null;
161     BufferedReader buff = null;
162     try {
163       fr = new FileReader(filePath);
164       buff = new BufferedReader(fr);
165       final StringBuilder stringBuilder = new StringBuilder();
166       String line;
167       while ((line = buff.readLine()) != null) {
168         stringBuilder.append(line.trim());
169       }
170       return stringBuilder.toString();
171     } catch (final FileNotFoundException e) {
172       throw new RestErrorException(RestErrors.FILE_NOT_FOUND(filePath));
173     } catch (final IOException e) {
174       throw new InternalServerErrorException(e);
175     } finally {
176       FileUtils.close(buff);
177       FileUtils.close(fr);
178     }
179   }
180 
181   /**
182    * Saves a serializable Java object to an XML file at the given location.
183    *
184    * @param object the object to save as XML
185    * @param filePath the path where to save the XML file
186    *
187    * @throws InternalServerErrorException if an unexpected error
188    *     occurred
189    */
190   public static void saveObject(final XmlSerializable object,
191                                 final String filePath) {
192 
193     final String xml = objectToXml(object);
194     saveXML(xml, filePath);
195   }
196 
197   /**
198    * Loads the given XML file into a corresponding serializable Java object.
199    *
200    * @param filePath path of the file to load
201    * @param clazz class of the target Java object
202    *
203    * @return the deserialized XML object
204    *
205    * @throws InternalServerErrorException if an unexpected error
206    *     occurred
207    */
208   public static <T extends XmlSerializable> T loadObject(final String filePath,
209                                                          final Class<T> clazz) {
210 
211     final String xml = loadXML(filePath);
212     return xmlToObject(xml, clazz);
213   }
214 
215   // ######################### PRIVATE METHODS #################################
216 
217   /**
218    * Formats an unformatted XML String into a human readable one.
219    *
220    * @param input The unformatted XML String.
221    *
222    * @return The XML String in human readable format.
223    *
224    * @throws InternalServerErrorException if an unexpected error
225    *     occurred
226    */
227   private static String pretty(final String input) {
228     if (ParametersChecker.isEmpty(input)) {
229       throw new InternalServerErrorException("Input empty but should not");
230     }
231     try {
232       final Source xmlInput = new StreamSource(new StringReader(input));
233       final StringWriter stringWriter = new StringWriter();
234       final StreamResult xmlOutput = new StreamResult(stringWriter);
235       final TransformerFactory factory =//NOSONAR
236           TransformerFactory.newInstance();//NOSONAR
237       factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
238       factory.setAttribute("indent-number", 2);
239       final Transformer transformer = factory.newTransformer();
240       transformer.setOutputProperty(INDENT, "yes");
241       transformer.setOutputProperty(OMIT_XML_DECLARATION, "yes");
242       transformer.transform(xmlInput, xmlOutput);
243       return xmlOutput.getWriter().toString();
244     } catch (final TransformerConfigurationException e) {
245       throw new InternalServerErrorException(e);
246     } catch (final TransformerException e) {
247       throw new InternalServerErrorException(e);
248     }
249   }
250 }