Java tutorial
/* Copyright (C) 2016 Stephan Kreutzer * * This file is part of json_to_xml_1, a submodule of the * digital_publishing_workflow_tools package. * * json_to_xml_1 is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License version 3 or any later version, * as published by the Free Software Foundation. * * json_to_xml_1 is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License 3 for more details. * * You should have received a copy of the GNU Affero General Public License 3 * along with json_to_xml_1. If not, see <http://www.gnu.org/licenses/>. */ /** * @file $/json_to_xml/json_to_xml_1.java * @brief Wrapper to call a JSON-java JSON to XML conversion. * @author Stephan Kreutzer * @since 2016-02-13 */ import java.util.Locale; import java.util.ResourceBundle; import java.text.MessageFormat; import java.io.File; import java.io.BufferedWriter; import java.io.OutputStreamWriter; import java.io.FileOutputStream; import java.io.IOException; import java.io.FileNotFoundException; import java.io.UnsupportedEncodingException; import java.io.StringWriter; import java.io.PrintWriter; import java.util.List; import java.util.ArrayList; import javax.xml.stream.XMLInputFactory; import java.io.InputStream; import java.io.FileInputStream; import javax.xml.stream.XMLEventReader; import javax.xml.stream.events.XMLEvent; import javax.xml.stream.events.StartElement; import javax.xml.stream.events.Attribute; import javax.xml.namespace.QName; import javax.xml.stream.XMLStreamException; import java.net.URLDecoder; import java.util.Scanner; import java.io.BufferedReader; import java.io.FileReader; import java.util.Map; import java.util.HashMap; import java.util.Iterator; import org.json.JSONObject; import org.json.JSONTokener; import org.json.XML; public class json_to_xml_1 { protected json_to_xml_1() { // Singleton to protect json_to_xml_1.resultInfoFile from conflicting use. } public static json_to_xml_1 getInstance() { if (json_to_xml_1.json_to_xml_1Instance == null) { json_to_xml_1.json_to_xml_1Instance = new json_to_xml_1(); } return json_to_xml_1.json_to_xml_1Instance; } public static void main(String args[]) { System.out.print("json_to_xml_1 workflow Copyright (C) 2016 Stephan Kreutzer\n" + "This program comes with ABSOLUTELY NO WARRANTY.\n" + "This is free software, and you are welcome to redistribute it\n" + "under certain conditions. See the GNU Affero General Public License 3\n" + "or any later version for details. Also, see the source code repository\n" + "https://github.com/publishing-systems/digital_publishing_workflow_tools/ and\n" + "the project website http://www.publishing-systems.org.\n\n"); json_to_xml_1 converter = json_to_xml_1.getInstance(); converter.getInfoMessages().clear(); try { converter.execute(args); } catch (ProgramTerminationException ex) { converter.handleTermination(ex); } if (converter.resultInfoFile != null) { try { BufferedWriter writer = new BufferedWriter( new OutputStreamWriter(new FileOutputStream(converter.resultInfoFile), "UTF-8")); writer.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"); writer.write( "<!-- This file was created by json_to_xml_1, which is free software licensed under the GNU Affero General Public License 3 or any later version (see https://github.com/publishing-systems/digital_publishing_workflow_tools/ and http://www.publishing-systems.org). -->\n"); writer.write("<json-to-xml-1-result-information>\n"); if (converter.getInfoMessages().size() <= 0) { writer.write(" <success/>\n"); } else { writer.write(" <success>\n"); writer.write(" <info-messages>\n"); for (int i = 0, max = converter.getInfoMessages().size(); i < max; i++) { InfoMessage infoMessage = converter.getInfoMessages().get(i); writer.write(" <info-message number=\"" + i + "\">\n"); writer.write(" <timestamp>" + infoMessage.getTimestamp() + "</timestamp>\n"); String infoMessageText = infoMessage.getMessage(); String infoMessageId = infoMessage.getId(); String infoMessageBundle = infoMessage.getBundle(); Object[] infoMessageArguments = infoMessage.getArguments(); if (infoMessageBundle != null) { // Ampersand needs to be the first, otherwise it would double-encode // other entities. infoMessageBundle = infoMessageBundle.replaceAll("&", "&"); infoMessageBundle = infoMessageBundle.replaceAll("<", "<"); infoMessageBundle = infoMessageBundle.replaceAll(">", ">"); writer.write(" <id-bundle>" + infoMessageBundle + "</id-bundle>\n"); } if (infoMessageId != null) { // Ampersand needs to be the first, otherwise it would double-encode // other entities. infoMessageId = infoMessageId.replaceAll("&", "&"); infoMessageId = infoMessageId.replaceAll("<", "<"); infoMessageId = infoMessageId.replaceAll(">", ">"); writer.write(" <id>" + infoMessageId + "</id>\n"); } if (infoMessageText != null) { // Ampersand needs to be the first, otherwise it would double-encode // other entities. infoMessageText = infoMessageText.replaceAll("&", "&"); infoMessageText = infoMessageText.replaceAll("<", "<"); infoMessageText = infoMessageText.replaceAll(">", ">"); writer.write(" <message>" + infoMessageText + "</message>\n"); } if (infoMessageArguments != null) { writer.write(" <arguments>\n"); int argumentCount = infoMessageArguments.length; for (int j = 0; j < argumentCount; j++) { if (infoMessageArguments[j] == null) { writer.write(" <argument number=\"" + j + "\">\n"); writer.write(" <class></class>\n"); writer.write(" <value>null</value>\n"); writer.write(" </argument>\n"); continue; } String className = infoMessageArguments[j].getClass().getName(); // Ampersand needs to be the first, otherwise it would double-encode // other entities. className = className.replaceAll("&", "&"); className = className.replaceAll("<", "<"); className = className.replaceAll(">", ">"); String value = infoMessageArguments[j].toString(); // Ampersand needs to be the first, otherwise it would double-encode // other entities. value = value.replaceAll("&", "&"); value = value.replaceAll("<", "<"); value = value.replaceAll(">", ">"); writer.write(" <argument number=\"" + j + "\">\n"); writer.write(" <class>" + className + "</class>\n"); writer.write(" <value>" + value + "</value>\n"); writer.write(" </argument>\n"); } writer.write(" </arguments>\n"); } Exception exception = infoMessage.getException(); if (exception != null) { writer.write(" <exception>\n"); String className = exception.getClass().getName(); // Ampersand needs to be the first, otherwise it would double-encode // other entities. className = className.replaceAll("&", "&"); className = className.replaceAll("<", "<"); className = className.replaceAll(">", ">"); writer.write(" <class>" + className + "</class>\n"); StringWriter stringWriter = new StringWriter(); PrintWriter printWriter = new PrintWriter(stringWriter); exception.printStackTrace(printWriter); String stackTrace = stringWriter.toString(); // Ampersand needs to be the first, otherwise it would double-encode // other entities. stackTrace = stackTrace.replaceAll("&", "&"); stackTrace = stackTrace.replaceAll("<", "<"); stackTrace = stackTrace.replaceAll(">", ">"); writer.write(" <stack-trace>" + stackTrace + "</stack-trace>\n"); writer.write(" </exception>\n"); } writer.write(" </info-message>\n"); } writer.write(" </info-messages>\n"); writer.write(" </success>\n"); } writer.write("</json-to-xml-1-result-information>\n"); writer.flush(); writer.close(); } catch (FileNotFoundException ex) { ex.printStackTrace(); System.exit(-1); } catch (UnsupportedEncodingException ex) { ex.printStackTrace(); System.exit(-1); } catch (IOException ex) { ex.printStackTrace(); System.exit(-1); } } converter.getInfoMessages().clear(); converter.resultInfoFile = null; } public int execute(String args[]) throws ProgramTerminationException { this.getInfoMessages().clear(); if (args.length < 2) { throw constructTermination("messageArgumentsMissing", null, getI10nString("messageArgumentsMissingUsage") + "\n\tjson_to_xml_1 " + getI10nString("messageParameterList") + "\n"); } File resultInfoFile = new File(args[1]); try { resultInfoFile = resultInfoFile.getCanonicalFile(); } catch (SecurityException ex) { throw constructTermination("messageResultInfoFileCantGetCanonicalPath", ex, null, resultInfoFile.getAbsolutePath()); } catch (IOException ex) { throw constructTermination("messageResultInfoFileCantGetCanonicalPath", ex, null, resultInfoFile.getAbsolutePath()); } if (resultInfoFile.exists() == true) { if (resultInfoFile.isFile() == true) { if (resultInfoFile.canWrite() != true) { throw constructTermination("messageResultInfoFileIsntWritable", null, null, resultInfoFile.getAbsolutePath()); } } else { throw constructTermination("messageResultInfoPathIsntAFile", null, null, resultInfoFile.getAbsolutePath()); } } json_to_xml_1.resultInfoFile = resultInfoFile; File jobFile = new File(args[0]); try { jobFile = jobFile.getCanonicalFile(); } catch (SecurityException ex) { throw constructTermination("messageJobFileCantGetCanonicalPath", ex, null, jobFile.getAbsolutePath()); } catch (IOException ex) { throw constructTermination("messageJobFileCantGetCanonicalPath", ex, null, jobFile.getAbsolutePath()); } if (jobFile.exists() != true) { throw constructTermination("messageJobFileDoesntExist", null, null, jobFile.getAbsolutePath()); } if (jobFile.isFile() != true) { throw constructTermination("messageJobPathIsntAFile", null, null, jobFile.getAbsolutePath()); } if (jobFile.canRead() != true) { throw constructTermination("messageJobFileIsntReadable", null, null, jobFile.getAbsolutePath()); } System.out.println("json_to_xml_1: " + getI10nStringFormatted("messageCallDetails", jobFile.getAbsolutePath(), resultInfoFile.getAbsolutePath())); File inputFile = null; File outputFile = null; try { XMLInputFactory inputFactory = XMLInputFactory.newInstance(); InputStream in = new FileInputStream(jobFile); XMLEventReader eventReader = inputFactory.createXMLEventReader(in); while (eventReader.hasNext() == true) { XMLEvent event = eventReader.nextEvent(); if (event.isStartElement() == true) { String tagName = event.asStartElement().getName().getLocalPart(); if (tagName.equals("json-input-file") == true) { StartElement inputFileElement = event.asStartElement(); Attribute pathAttribute = inputFileElement.getAttributeByName(new QName("path")); if (pathAttribute == null) { throw constructTermination("messageJobFileEntryIsMissingAnAttribute", null, null, jobFile.getAbsolutePath(), tagName, "path"); } String inputFilePath = pathAttribute.getValue(); if (inputFilePath.isEmpty() == true) { throw constructTermination("messageJobFileAttributeValueIsEmpty", null, null, jobFile.getAbsolutePath(), tagName, "path"); } inputFile = new File(inputFilePath); if (inputFile.isAbsolute() != true) { inputFile = new File( jobFile.getAbsoluteFile().getParent() + File.separator + inputFilePath); } try { inputFile = inputFile.getCanonicalFile(); } catch (SecurityException ex) { throw constructTermination("messageInputFileCantGetCanonicalPath", ex, null, new File(inputFilePath).getAbsolutePath(), jobFile.getAbsolutePath()); } catch (IOException ex) { throw constructTermination("messageInputFileCantGetCanonicalPath", ex, null, new File(inputFilePath).getAbsolutePath(), jobFile.getAbsolutePath()); } if (inputFile.exists() != true) { throw constructTermination("messageInputFileDoesntExist", null, null, inputFile.getAbsolutePath(), jobFile.getAbsolutePath()); } if (inputFile.isFile() != true) { throw constructTermination("messageInputPathIsntAFile", null, null, inputFile.getAbsolutePath(), jobFile.getAbsolutePath()); } if (inputFile.canRead() != true) { throw constructTermination("messageInputFileIsntReadable", null, null, inputFile.getAbsolutePath(), jobFile.getAbsolutePath()); } } else if (tagName.equals("xml-output-file") == true) { StartElement outputFileElement = event.asStartElement(); Attribute pathAttribute = outputFileElement.getAttributeByName(new QName("path")); if (pathAttribute == null) { throw constructTermination("messageJobFileEntryIsMissingAnAttribute", null, null, jobFile.getAbsolutePath(), tagName, "path"); } String outputFilePath = pathAttribute.getValue(); if (outputFilePath.isEmpty() == true) { throw constructTermination("messageJobFileAttributeValueIsEmpty", null, null, jobFile.getAbsolutePath(), tagName, "path"); } outputFile = new File(outputFilePath); if (outputFile.isAbsolute() != true) { outputFile = new File( jobFile.getAbsoluteFile().getParent() + File.separator + outputFilePath); } try { outputFile = outputFile.getCanonicalFile(); } catch (SecurityException ex) { throw constructTermination("messageOutputFileCantGetCanonicalPath", ex, null, new File(outputFilePath).getAbsolutePath(), jobFile.getAbsolutePath()); } catch (IOException ex) { throw constructTermination("messageOutputFileCantGetCanonicalPath", ex, null, new File(outputFilePath).getAbsolutePath(), jobFile.getAbsolutePath()); } if (outputFile.exists() == true) { if (outputFile.isFile() == true) { if (outputFile.canWrite() != true) { throw constructTermination("messageOutputFileIsntWritable", null, null, outputFile.getAbsolutePath()); } } else { throw constructTermination("messageOutputPathIsntAFile", null, null, outputFile.getAbsolutePath()); } } } } } } catch (XMLStreamException ex) { throw constructTermination("messageJobFileErrorWhileReading", ex, null, jobFile.getAbsolutePath()); } catch (SecurityException ex) { throw constructTermination("messageJobFileErrorWhileReading", ex, null, jobFile.getAbsolutePath()); } catch (IOException ex) { throw constructTermination("messageJobFileErrorWhileReading", ex, null, jobFile.getAbsolutePath()); } if (inputFile == null) { throw constructTermination("messageJobFileNoInputFile", null, null, jobFile.getAbsolutePath()); } if (outputFile == null) { throw constructTermination("messageJobFileNoOutputFile", null, null, jobFile.getAbsolutePath()); } StringBuilder stringBuilder = new StringBuilder(); try { JSONObject json = new JSONObject(new JSONTokener(new BufferedReader(new FileReader(inputFile)))); stringBuilder.append(XML.toString(json)); } catch (Exception ex) { throw constructTermination("messageConversionError", ex, null, inputFile.getAbsolutePath()); } try { BufferedWriter writer = new BufferedWriter( new OutputStreamWriter(new FileOutputStream(outputFile), "UTF-8")); writer.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"); writer.write( "<!-- This file was created by json_to_xml_1, which is free software licensed under the GNU Affero General Public License 3 or any later version (see https://github.com/publishing-systems/digital_publishing_workflow_tools/ and http://www.publishing-systems.org). -->\n"); writer.write(stringBuilder.toString()); writer.flush(); writer.close(); } catch (FileNotFoundException ex) { throw constructTermination("messageOutputFileWritingError", ex, null, outputFile.getAbsolutePath()); } catch (UnsupportedEncodingException ex) { throw constructTermination("messageOutputFileWritingError", ex, null, outputFile.getAbsolutePath()); } catch (IOException ex) { throw constructTermination("messageOutputFileWritingError", ex, null, outputFile.getAbsolutePath()); } return 0; } public InfoMessage constructInfoMessage(String id, boolean outputToConsole, Exception exception, String message, Object... arguments) { if (message == null) { if (arguments == null) { message = "json_to_xml_1: " + getI10nString(id); } else { message = "json_to_xml_1: " + getI10nStringFormatted(id, arguments); } } if (outputToConsole == true) { System.out.println(message); if (exception != null) { System.out.println(exception.getMessage()); exception.printStackTrace(); } } return new InfoMessage(id, exception, message, L10N_BUNDLE, arguments); } public ProgramTerminationException constructTermination(String id, Exception cause, String message, Object... arguments) { if (message == null) { if (arguments == null) { message = "json_to_xml_1: " + getI10nString(id); } else { message = "json_to_xml_1: " + getI10nStringFormatted(id, arguments); } } return new ProgramTerminationException(id, cause, message, L10N_BUNDLE, arguments); } public int handleTermination(ProgramTerminationException ex) { String message = ex.getMessage(); String id = ex.getId(); String bundle = ex.getBundle(); Object[] arguments = ex.getArguments(); boolean normalTermination = ex.isNormalTermination(); if (message != null) { System.err.println(message); } Throwable innerException = ex.getCause(); if (innerException != null) { System.out.println(innerException.getMessage()); innerException.printStackTrace(); } if (json_to_xml_1.resultInfoFile != null) { try { BufferedWriter writer = new BufferedWriter( new OutputStreamWriter(new FileOutputStream(json_to_xml_1.resultInfoFile), "UTF-8")); writer.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"); writer.write( "<!-- This file was created by json_to_xml_1, which is free software licensed under the GNU Affero General Public License 3 or any later version (see https://github.com/publishing-systems/digital_publishing_workflow_tools/ and http://www.publishing-systems.org). -->\n"); writer.write("<json-to-xml-1-result-information>\n"); if (normalTermination == false) { writer.write(" <failure>\n"); } else { writer.write(" <success>\n"); } writer.write(" <timestamp>" + ex.getTimestamp() + "</timestamp>\n"); if (bundle != null) { // Ampersand needs to be the first, otherwise it would double-encode // other entities. bundle = bundle.replaceAll("&", "&"); bundle = bundle.replaceAll("<", "<"); bundle = bundle.replaceAll(">", ">"); writer.write(" <id-bundle>" + bundle + "</id-bundle>\n"); } if (id != null) { // Ampersand needs to be the first, otherwise it would double-encode // other entities. id = id.replaceAll("&", "&"); id = id.replaceAll("<", "<"); id = id.replaceAll(">", ">"); writer.write(" <id>" + id + "</id>\n"); } if (message != null) { // Ampersand needs to be the first, otherwise it would double-encode // other entities. message = message.replaceAll("&", "&"); message = message.replaceAll("<", "<"); message = message.replaceAll(">", ">"); writer.write(" <message>" + message + "</message>\n"); } if (arguments != null) { writer.write(" <arguments>\n"); int argumentCount = arguments.length; for (int i = 0; i < argumentCount; i++) { if (arguments[i] == null) { writer.write(" <argument number=\"" + i + "\">\n"); writer.write(" <class></class>\n"); writer.write(" <value>null</value>\n"); writer.write(" </argument>\n"); continue; } String className = arguments[i].getClass().getName(); // Ampersand needs to be the first, otherwise it would double-encode // other entities. className = className.replaceAll("&", "&"); className = className.replaceAll("<", "<"); className = className.replaceAll(">", ">"); String value = arguments[i].toString(); // Ampersand needs to be the first, otherwise it would double-encode // other entities. value = value.replaceAll("&", "&"); value = value.replaceAll("<", "<"); value = value.replaceAll(">", ">"); writer.write(" <argument number=\"" + i + "\">\n"); writer.write(" <class>" + className + "</class>\n"); writer.write(" <value>" + value + "</value>\n"); writer.write(" </argument>\n"); } writer.write(" </arguments>\n"); } if (innerException != null) { writer.write(" <exception>\n"); String className = innerException.getClass().getName(); // Ampersand needs to be the first, otherwise it would double-encode // other entities. className = className.replaceAll("&", "&"); className = className.replaceAll("<", "<"); className = className.replaceAll(">", ">"); writer.write(" <class>" + className + "</class>\n"); StringWriter stringWriter = new StringWriter(); PrintWriter printWriter = new PrintWriter(stringWriter); innerException.printStackTrace(printWriter); String stackTrace = stringWriter.toString(); // Ampersand needs to be the first, otherwise it would double-encode // other entities. stackTrace = stackTrace.replaceAll("&", "&"); stackTrace = stackTrace.replaceAll("<", "<"); stackTrace = stackTrace.replaceAll(">", ">"); writer.write(" <stack-trace>" + stackTrace + "</stack-trace>\n"); writer.write(" </exception>\n"); } if (this.getInfoMessages().size() > 0) { writer.write(" <info-messages>\n"); for (int i = 0, max = this.getInfoMessages().size(); i < max; i++) { InfoMessage infoMessage = this.getInfoMessages().get(i); writer.write(" <info-message>\n"); writer.write(" <timestamp>" + infoMessage.getTimestamp() + "</timestamp>\n"); String infoMessageText = infoMessage.getMessage(); String infoMessageId = ex.getId(); String infoMessageBundle = ex.getBundle(); Object[] infoMessageArguments = ex.getArguments(); if (infoMessageBundle != null) { // Ampersand needs to be the first, otherwise it would double-encode // other entities. infoMessageBundle = infoMessageBundle.replaceAll("&", "&"); infoMessageBundle = infoMessageBundle.replaceAll("<", "<"); infoMessageBundle = infoMessageBundle.replaceAll(">", ">"); writer.write(" <id-bundle>" + infoMessageBundle + "</id-bundle>\n"); } if (infoMessageId != null) { // Ampersand needs to be the first, otherwise it would double-encode // other entities. infoMessageId = infoMessageId.replaceAll("&", "&"); infoMessageId = infoMessageId.replaceAll("<", "<"); infoMessageId = infoMessageId.replaceAll(">", ">"); writer.write(" <id>" + infoMessageId + "</id>\n"); } if (infoMessageText != null) { // Ampersand needs to be the first, otherwise it would double-encode // other entities. infoMessageText = infoMessageText.replaceAll("&", "&"); infoMessageText = infoMessageText.replaceAll("<", "<"); infoMessageText = infoMessageText.replaceAll(">", ">"); writer.write(" <message>" + infoMessageText + "</message>\n"); } if (infoMessageArguments != null) { writer.write(" <arguments>\n"); int argumentCount = infoMessageArguments.length; for (int j = 0; j < argumentCount; j++) { if (infoMessageArguments[j] == null) { writer.write(" <argument number=\"" + j + "\">\n"); writer.write(" <class></class>\n"); writer.write(" <value>null</value>\n"); writer.write(" </argument>\n"); continue; } String className = infoMessageArguments[j].getClass().getName(); // Ampersand needs to be the first, otherwise it would double-encode // other entities. className = className.replaceAll("&", "&"); className = className.replaceAll("<", "<"); className = className.replaceAll(">", ">"); String value = infoMessageArguments[j].toString(); // Ampersand needs to be the first, otherwise it would double-encode // other entities. value = value.replaceAll("&", "&"); value = value.replaceAll("<", "<"); value = value.replaceAll(">", ">"); writer.write(" <argument number=\"" + j + "\">\n"); writer.write(" <class>" + className + "</class>\n"); writer.write(" <value>" + value + "</value>\n"); writer.write(" </argument>\n"); } writer.write(" </arguments>\n"); } writer.write(" </info-message>\n"); } writer.write(" </info-messages>\n"); } if (normalTermination == false) { writer.write(" </failure>\n"); } else { writer.write(" </success>\n"); } writer.write("</json-to-xml-1-result-information>\n"); writer.flush(); writer.close(); } catch (FileNotFoundException ex2) { ex2.printStackTrace(); } catch (UnsupportedEncodingException ex2) { ex2.printStackTrace(); } catch (IOException ex2) { ex2.printStackTrace(); } } json_to_xml_1.resultInfoFile = null; System.exit(-1); return -1; } public List<InfoMessage> getInfoMessages() { return this.infoMessages; } public Locale getLocale() { return Locale.getDefault(); } /** * @brief This method interprets l10n strings from a .properties file as encoded in UTF-8. */ private String getI10nString(String key) { if (this.l10nConsole == null) { this.l10nConsole = ResourceBundle.getBundle(L10N_BUNDLE, this.getLocale()); } try { return new String(this.l10nConsole.getString(key).getBytes("ISO-8859-1"), "UTF-8"); } catch (UnsupportedEncodingException ex) { return this.l10nConsole.getString(key); } } private String getI10nStringFormatted(String i10nStringName, Object... arguments) { MessageFormat formatter = new MessageFormat(""); formatter.setLocale(this.getLocale()); formatter.applyPattern(getI10nString(i10nStringName)); return formatter.format(arguments); } private static json_to_xml_1 json_to_xml_1Instance; public static File resultInfoFile = null; protected List<InfoMessage> infoMessages = new ArrayList<InfoMessage>(); private static final String L10N_BUNDLE = "l10n.l10nJsonToXml1Console"; private ResourceBundle l10nConsole; }