/** * Copyright 2013 SmartBear Software, Inc. * <p> * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * <p> * http://www.apache.org/licenses/LICENSE-2.0 * <p> * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.smartbear.swagger4j.impl; import com.smartbear.swagger4j.SwaggerFormat; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import javax.json.Json; import javax.json.JsonArrayBuilder; import javax.json.JsonObject; import javax.json.JsonObjectBuilder; import javax.json.JsonWriterFactory; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import java.io.IOException; import java.io.Writer; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import static javax.json.stream.JsonGenerator.PRETTY_PRINTING; /** * Utility class for abstraction of writing an actual format, since json and xml are read in the same way */ public abstract class SwaggerGenerator { public abstract SwaggerGenerator addString(String name, String value); public abstract void finish() throws IOException; public abstract SwaggerGenerator addObject(String name); public abstract SwaggerGenerator addArrayObject(String name); public abstract SwaggerGenerator addBoolean(String name, boolean value); public abstract SwaggerGenerator addInt(String name, int value); public abstract SwaggerGenerator addArray(String name, String[] values); /** * Builder for a SwaggerGenerator that can write XML */ public static SwaggerGenerator newXmlGenerator(Writer writer) throws IOException { return new SwaggerXmlGenerator(writer); } /** * Builder for a SwaggerGenerator that can write JSON */ public static SwaggerGenerator newJsonGenerator(Writer writer) { return new SwaggerJsonGenerator(writer); } /** * Builds a SwaggerGenerator for one of the supported formats * * @param writer the writer to write to * @param format the format * @return the SwaggerGenerator * @throws IOException */ public static SwaggerGenerator newGenerator(Writer writer, SwaggerFormat format) throws IOException { switch (format) { case xml: return newXmlGenerator(writer); case json: return newJsonGenerator(writer); default: throw new RuntimeException("Unknown format: " + format); } } /** * SwaggerGenerator implementation that reads JSON */ public static class SwaggerJsonGenerator extends SwaggerGenerator { private final JsonObjectBuilder builder; private Writer writer; private Map<String, SwaggerJsonGenerator> objects; private Map<String, List<SwaggerJsonGenerator>> arrayObjects; public SwaggerJsonGenerator(Writer writer) { this.writer = writer; builder = Json.createObjectBuilder(); } public SwaggerJsonGenerator(JsonObjectBuilder objectBuilder) { this.builder = objectBuilder; } @Override public SwaggerGenerator addString(String name, String value) { assert name != null; if (value != null) { builder.add(name, value); } return this; } JsonObjectBuilder getObjectBuilder() { return builder; } @Override public void finish() throws IOException { if (arrayObjects != null) { for (String name : arrayObjects.keySet()) { JsonArrayBuilder arrayBuilder = Json.createArrayBuilder(); for (SwaggerJsonGenerator w : arrayObjects.get(name)) { w.finish(); arrayBuilder.add(w.getObjectBuilder()); } builder.add(name, arrayBuilder); } } if (objects != null) { for (String name : objects.keySet()) { SwaggerJsonGenerator w = objects.get(name); w.finish(); builder.add(name, w.getObjectBuilder()); } } if (writer != null) { JsonObject jsonObject = builder.build(); JsonWriterFactory factory = Json.createWriterFactory( Collections.singletonMap(PRETTY_PRINTING, "true")); javax.json.JsonWriter jsonWriter = factory.createWriter(writer); jsonWriter.writeObject(jsonObject); jsonWriter.close(); } } @Override public SwaggerGenerator addObject(String name) { if (objects == null) { objects = new HashMap<String, SwaggerJsonGenerator>(); } SwaggerJsonGenerator result = new SwaggerJsonGenerator(Json.createObjectBuilder()); objects.put(name, result); return result; } @Override public SwaggerGenerator addArrayObject(String name) { assert name != null; if (arrayObjects == null) { arrayObjects = new HashMap<String, List<SwaggerJsonGenerator>>(); } if (!arrayObjects.containsKey(name)) { arrayObjects.put(name, new ArrayList<SwaggerJsonGenerator>()); } JsonObjectBuilder objectBuilder = Json.createObjectBuilder(); SwaggerJsonGenerator swaggerJsonGenerator = new SwaggerJsonGenerator(objectBuilder); arrayObjects.get(name).add(swaggerJsonGenerator); return swaggerJsonGenerator; } @Override public SwaggerGenerator addBoolean(String name, boolean value) { builder.add(name, value); return this; } @Override public SwaggerGenerator addInt(String name, int value) { builder.add(name, value); return this; } @Override public SwaggerGenerator addArray(String name, String[] values) { assert name != null && values != null; JsonArrayBuilder arrayBuilder = Json.createArrayBuilder(); for (String v : values) { arrayBuilder.add(v); } builder.add(name, arrayBuilder); return this; } } /** * SwaggerGenerator implementation that reads XML */ public static class SwaggerXmlGenerator extends SwaggerGenerator { private final Element elm; private Writer writer; private SwaggerXmlGenerator(Writer writer) throws IOException { this.writer = writer; try { Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument(); elm = (Element) document.appendChild(document.createElement(Constants.API_DOCUMENTATION)); } catch (Exception e) { throw new IOException(e); } } private SwaggerXmlGenerator(Element elm) { this.elm = elm; } @Override public SwaggerGenerator addString(String name, String value) { if (value != null) { Document document = elm.getOwnerDocument(); Node node = elm.appendChild(document.createElement(name)); node.appendChild(document.createTextNode(value)); } return this; } @Override public void finish() throws IOException { if (writer == null) { throw new RuntimeException("finish can only be called on root writer"); } try { Document document = elm.getOwnerDocument(); DOMSource domSource = new DOMSource(document); StreamResult result = new StreamResult(writer); TransformerFactory tf = TransformerFactory.newInstance(); Transformer transformer = tf.newTransformer(); transformer.transform(domSource, result); } catch (TransformerException ex) { throw new IOException(ex); } } @Override public SwaggerGenerator addObject(String name) { return addArrayObject(name); } @Override public SwaggerGenerator addArrayObject(String name) { Document document = elm.getOwnerDocument(); Node node = elm.appendChild(document.createElement(name)); return new SwaggerXmlGenerator((Element) node); } @Override public SwaggerXmlGenerator addBoolean(String name, boolean value) { addString(name, Boolean.toString(value)); return this; } @Override public SwaggerGenerator addInt(String name, int value) { addString(name, Integer.toString(value)); return this; } @Override public SwaggerGenerator addArray(String name, String[] values) { for (String v : values) { addString(name, v); } return this; } } }