Java tutorial
/******************************************************************************* * Copyright (c) 2010-2011 VIVO Harvester Team. For full list of contributors, please see the AUTHORS file provided. * All rights reserved. * This program and the accompanying materials are made available under the terms of the new BSD license which accompanies this distribution, and is available at http://www.opensource.org/licenses/bsd-license.html ******************************************************************************/ package org.vivoweb.harvester.util; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.StringReader; import java.io.StringWriter; import java.net.URL; import java.net.URLConnection; import java.util.Map; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.transform.OutputKeys; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import org.vivoweb.harvester.util.args.ArgDef; import org.vivoweb.harvester.util.args.ArgList; import org.vivoweb.harvester.util.args.ArgParser; import org.vivoweb.harvester.util.args.UsageException; import org.w3c.dom.Document; import org.xml.sax.InputSource; import org.apache.commons.io.IOUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Fetches SOAP-XML data from a SOAP compatible site placing the data in the supplied file. */ public class SOAPMessenger { /** * SLF4J Logger */ private static Logger log = LoggerFactory.getLogger(SOAPMessenger.class); /** * File to put XML in. */ private OutputStream outputFile; /** * URL to send message to */ private URL url; /** * Connection derived from that URL */ private URLConnection urlCon; /** * Inputstream with SOAP style XML message */ private InputStream inputFile; /** * String of XML gathered from the inputStream */ private String xmlString; /** * The authentication sessionID */ private String sessionID; Map<String, String> requestProperties; /** * Constructor * @param url address to connect with * @param output RecordHandler to write data to * @param xmlFile xml file to POST to the url * @param reqProperties a map of the properties which go into the header of the request * @throws IOException error talking with database */ public SOAPMessenger(URL url, String output, String xmlFile, String sesID, Map<String, String> reqProperties) throws IOException { this(url, FileAide.getOutputStream(output), FileAide.getInputStream(xmlFile), sesID, reqProperties); } /** * Command line Constructor * @param args commandline arguments * @throws IOException error creating task * @throws UsageException user requested usage message */ private SOAPMessenger(String[] args) throws IOException, UsageException { this(getParser().parse(args)); } /** * Arglist Constructor * @param args option set of parsed args * @throws IOException error creating task */ private SOAPMessenger(ArgList args) throws IOException { this(new URL(args.get("u")), FileAide.getOutputStream(args.get("o")), FileAide.getInputStream(args.get("m")), args.get("a"), args.getValueMap("p")); } /** * Library style Constructor * @param url URL to connect with. * @param output The stream to the output file * @param xmlFileStream The stream which points to the Soap Message * @throws IOException problem with opening url connection */ public SOAPMessenger(URL url, OutputStream output, InputStream xmlFileStream, String sesID, Map<String, String> reqProprties) throws IOException { this.outputFile = output; this.url = url; this.inputFile = xmlFileStream; this.sessionID = sesID; this.requestProperties = reqProprties; log.debug("Checking for NULL values"); if (this.outputFile == null) { log.debug("Outputfile = null"); log.error("Must provide output file!"); } else { log.debug("Outputfile = " + this.outputFile.toString()); } if (this.inputFile == null) { log.debug("Inputfile = null"); log.error("Must provide message file!"); } else { log.debug("Inputfile = " + this.inputFile.toString()); } if (this.url == null) { log.debug("URL = null"); log.error("Must provide url!"); } else { log.debug("URL = " + this.url.toString()); } if (this.sessionID == null) { log.debug("SessionID = null"); this.sessionID = ""; } else { log.debug("SessionID = " + this.sessionID); } if (this.requestProperties == null) { log.debug("Request Properties = null"); } else { log.debug("Request Properties:"); for (String prop : this.requestProperties.keySet()) { log.debug(prop + " = " + this.requestProperties.get(prop)); } } } /** * @param urlCon the location where the message is to. * @param message the xml message in the form of a string. * @throws IOException thrown if there is an issue with the stream. */ private void sendMessage(URLConnection urlCon, String message) throws IOException { // specify that we will send output and accept input this.urlCon.setDoInput(true); this.urlCon.setDoOutput(true); // this.urlCon.setConnectTimeout( 20000 ); // long timeout, but not infinite // this.urlCon.setReadTimeout( 20000 ); this.urlCon.setUseCaches(false); this.urlCon.setDefaultUseCaches(false); // tell the web server what we are sending this.urlCon.setRequestProperty("Content-Type", "application/soap+xml; charset=utf-8"); if (this.sessionID != "") { this.urlCon.setRequestProperty("Cookie", "SID=\"" + this.sessionID + "\""); } if (this.requestProperties != null) { for (String param : this.requestProperties.keySet()) { this.urlCon.setRequestProperty(param, this.requestProperties.get(param)); } } log.debug("getting writer for url connection"); OutputStreamWriter osWriter = new OutputStreamWriter(this.urlCon.getOutputStream()); log.debug("writting to url connection"); osWriter.write(this.xmlString); osWriter.close(); } /** * @param urlCon the url connection which the message it comming from. * @return the string version of the message * @throws IOException if there is a problem with the source. */ private String readMessage(URLConnection urlCon) throws IOException { InputStreamReader isReader = new InputStreamReader(this.urlCon.getInputStream()); StringBuilder buf = new StringBuilder(); char[] cbuf = new char[2048]; int num; while (-1 != (num = isReader.read(cbuf))) { buf.append(cbuf, 0, num); } return buf.toString(); } /** * Executes the task * @throws IOException error processing record handler or jdbc connection */ public void execute() throws IOException { this.xmlString = IOUtils.toString(this.inputFile, "UTF-8"); log.info("Built message"); log.debug("Message contents:\n" + this.xmlString); log.info("opening the url connection"); this.urlCon = this.url.openConnection(); sendMessage(this.urlCon, this.xmlString); // reading the response log.debug("getting reader for url connection"); String result = readMessage(this.urlCon); result = formatResult(result); log.debug("Response contents:\n" + result); OutputStreamWriter outputWriter = new OutputStreamWriter(this.outputFile); log.info("writing response"); outputWriter.write(result); outputWriter.close(); } /** * Take an XML string and ensure there are line breaks and indentation. * @param inputXml the input XML string * @return the formatted XML string */ public String formatResult(String inputXml) { try { StringReader reader = new StringReader(inputXml); InputSource source = new InputSource(reader); DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); Document document = builder.parse(source); Transformer transformer = TransformerFactory.newInstance().newTransformer(); transformer.setOutputProperty(OutputKeys.INDENT, "yes"); transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4"); StreamResult result = new StreamResult(new StringWriter()); DOMSource domSource = new DOMSource(document); transformer.transform(domSource, result); return result.getWriter().toString(); } catch (Exception e) { log.error(e.getMessage(), e); return inputXml; //log error and then just don't format the result } } /** * Get the ArgParser for this task * @return the ArgParser */ private static ArgParser getParser() { ArgParser parser = new ArgParser("SOAPMessenger"); parser.addArgument(new ArgDef().setShortOption('u').setLongOpt("url").withParameter(true, "URL") .setDescription("The URL which will receive the MESSAGE.").setRequired(true)); parser.addArgument(new ArgDef().setShortOption('m').setLongOpt("message").withParameter(true, "MESSAGE") .setDescription("The MESSAGE file path.").setRequired(true)); parser.addArgument(new ArgDef().setShortOption('o').setLongOpt("output").withParameter(true, "OUTPUT_FILE") .setDescription("XML result file path").setRequired(true)); parser.addArgument(new ArgDef().setShortOption('a').setLongOpt("authentication").withParameter(true, "AUTH") .setDescription("The authentication session ID").setRequired(false)); parser.addArgument(new ArgDef().setShortOption('p').setLongOpt("requestproperty") .withParameterValueMap("PARAM", "VALUE") .setDescription("request properties to be associated with the SOAP request").setRequired(false)); return parser; } /** * Main method * @param args commandline arguments */ public static void main(String... args) { Exception error = null; try { InitLog.initLogger(args, getParser()); log.info(getParser().getAppName() + ": Start"); new SOAPMessenger(args).execute(); } catch (IllegalArgumentException e) { log.error(e.getMessage()); log.debug("Stacktrace:", e); System.out.println(getParser().getUsage()); error = e; } catch (UsageException e) { log.info("Printing Usage:"); System.out.println(getParser().getUsage()); error = e; } catch (Exception e) { log.error(e.getMessage()); log.debug("Stacktrace:", e); error = e; } finally { log.info(getParser().getAppName() + ": End"); if (error != null) { System.exit(1); } } } }