package javacodebook.xml.transport.http.post;

import java.net.*;
import java.io.*;

/**
 * Die XMLPoster-Klasse benutzt ein URL- bzw. ein URLConnection-Objekt um Strings
 * an beliebige, z.B. über die Kommandozeile übergebene URLs zu verschicken.  Dabei wird
 * die http-post-Methode verwendet.
 */
public class XMLPoster {
  private static final String USAGE =
      "\nBenutzerhinweis: javacodebook.xml.transport.http.post.XMLPoster " +
      "<url> <dateiName> [<dateiName> ...]\n\nwobei\n\n<url>\n" +
      "die URL ist, an die die XML-Dokumente gepostet werden sollen und\n\n<dateiName> [<dateiName> ...]\n" +
      "ein oder mehrere durch Leerzeichen getrennte Dateinamen von XML-Dateien sind, die \n" +
      "per post verschickt werden sollen";

  /**
   * An die main-Methode müssen die Parameter <url> und eine durch Leerzeichen getrennte Folge von
   * Dateinamen <dateiName> [<dateiName> ...] übergeben werden.  Es wird ein Objekt vom Typ XMLPoster instanziiert.
   * Der erste Parameter wird als URL ausgelesen.  Für jeden weiteren Paramter wird versucht den Inhalt der entsprechenden
   * Datei über die loadXML-Methode in einen String zu laden.  Dieser String wird dann über die postXML2URL-Methode
   * des XMLPoster-Objekts an die URL verschickt.
   */
  public static void main(String args[]) {
    if (args.length < 2) {
      System.out.println(getUsage());
      System.exit(1);
    }
    else {
      String urlString = args[0];
      XMLPoster xMLPoster = new XMLPoster();
      for (int i = 1; i < args.length; i++) {
        String fileName = args[i];
        try {
          String xml = xMLPoster.loadXML(fileName);
          xMLPoster.postXML2URL(xml, urlString);
        }
        catch (Exception e) {
          System.out.println("Probleme bei der Ausführung: " + e);
        }
      }
    }
  }

  private String postXML2URL(String xml, String urlString) throws Exception {
    String answerFromServer = "";
    try {
      // Instanziierung eines URL-Objektes nach RFC 2396: Uniform Resource Identifiers (URI): 'Generic Syntax'
      // nachgebessert durch RFC 2732: 'Format for Literal IPv6 Addresses in URLs'.
      URL url = new URL(urlString);

      // Über das URL-Objekt wird ein URLConnection-Object erzeugt werden.  Das URLConnection-Object stellt die
      // Verbindung zur entfernten Resource mit all ihren Eigenschaften dar.
      URLConnection con = url.openConnection();

      // Die Eigenschaften der Verbindung werden so gesetzt, dass sowohl gesendet als auch empfangen werden kann.
      // Dabei soll nicht gecached werden.
      con.setDoInput(true);
      con.setDoOutput(true);
      con.setUseCaches(false);

      // Setzen der vom HTTP-Standard definierten Request-Property 'CONTENT_LENGTH'
      con.setRequestProperty("CONTENT_LENGTH", "" + xml.length());

      // Von der Verbindung wird eine Referenz auf den OutputStrem geholt, um zum
      // Server schreiben zu können.
      OutputStream os = con.getOutputStream();

      // Ein OutputStreamWriter-Object wird instanziiert um dann über die write-Methode
      // den XML-String zum Server zu schreiben.
      OutputStreamWriter osw = new OutputStreamWriter(os);
      osw.write(xml);

      // Auf das OutputStreamWriter-Object muss die flush-Methode aufgerufen werden, um
      // den String vollständig zu übermitteln.
      osw.flush();

      // Letztlich muss die close-Methode aufgerufen werden um entsprechende Resourcen wieder freizugeben
      osw.close();

      // Durch das Aufrufen, der getInputStream-Methode auf das URLConnection-Objekt wird der
      // HTTP-Request beim Server abgesetzt.  (NICHT wie intuitiv vielleicht erwartet schon beim
      // schreiben in den Output-Stream)
      InputStream is = con.getInputStream();

      // Nun wird die Antwort ausgelesen
      InputStreamReader isr = new InputStreamReader(is);
      BufferedReader br = new BufferedReader(isr);
      String line = null;
      while ( (line = br.readLine()) != null) {
        answerFromServer = answerFromServer + line;
      }
      // Auch hier muss der InputStreamReader und somit der InputStream wieder geschlossen werden, da es sonst
      // zu Resourcenverschwendung kommt.  Besonders auf Solaris-Systemen kann das fatale Folgen haben, da für jeden
      // nicht geschlossenen InputStream ein File-Descriptor offen gehalten wird und die Zahl der erlaubten offenen
      // File-Descriptoren oft relativ eingeschränkt ist.
      System.out.println("Answer from Server: " + answerFromServer);
      isr.close();
    }
    catch (Exception e) {
      throw new Exception("Probleme beim aufrufen der URL '" + urlString +
                          "' mit: " + e);
    }
    return answerFromServer;
  }

  /**
   * Die methode loadXML nimmt einen String als Parameter, der einen Dateinamen
   * repräsentiert.  Diese Datei wird in der Methode in einen String gelesen und
   * als solcher zurück gegeben.  Falls dabei etwas schief geht schmeißt die Methode
   * eine Exception.
   */
  private String loadXML(String fileName) throws Exception {
    try {
      String xml = "";
      BufferedReader br = new BufferedReader(new InputStreamReader(new
          FileInputStream(fileName)));
      String line = br.readLine();
      while (line != null) {
        xml = xml + line + "\n";
        line = br.readLine();
      }
      return xml;
    }
    catch (Exception e) {
      throw new Exception("Die Datei '" + fileName +
                          "' konnte nicht geladen werden: " + e);
    }
  }

  public static String getUsage() {
    return USAGE;
  }
}