Java Web Services via REST bereitstellen
ulrich
2014-11-16 1da1cadfe51b9fc9970091e0d2ee6bedbcfd859b
AbstractServlet eingebaut
1 files added
2 files modified
459 ■■■■ changed files
src/de/uhilger/transit/web/AbstractServlet.java 96 ●●●●● patch | view | raw | blame | history
src/de/uhilger/transit/web/TransitServlet.java 277 ●●●● patch | view | raw | blame | history
src/de/uhilger/transit/web/TransitServletRS.java 86 ●●●●● patch | view | raw | blame | history
src/de/uhilger/transit/web/AbstractServlet.java
New file
@@ -0,0 +1,96 @@
/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package de.uhilger.transit.web;
import java.io.IOException;
import java.io.PrintWriter;
import java.security.Principal;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
 *
 * @author ulrich
 */
public abstract class AbstractServlet extends HttpServlet {
  public static final String MIME_JSON = "application/json";
  public static final String MIME_XML = "text/xml";
  public static final String KLASSEN_TRENNER = ";";
  private static final String[] specialChars = {new String("\u00c4"), new String("\u00d6"),
      new String("\u00dc"), new String("\u00e4"), new String("\u00f6"), new String("\u00fc"), new String("\u00df")};
  /** Name, der als Benutzername verwendet wird, wenn kein Benutzer angemeldet ist */
  public static final String ANONYMER_NUTZER = "anonymous";
  protected String[] klassen;
  @Override
  public void init(ServletConfig servletConfig) throws ServletException{
    this.klassen = servletConfig.getInitParameter("klassen").split(KLASSEN_TRENNER);
    super.init(servletConfig);
  }
  /**
   * Den Namen des angemeldeten Benutzers ermitteln.
   *
   * @param req  die Anfrage, deren Benutzer ermittelt werden soll
   * @return Name des Benutzers oder <code>anonymous</code>, wenn
   * kein Benutzer angemeldet ist
   */
  protected String getUserName(HttpServletRequest req) {
    String userName = null;
      Principal p = req.getUserPrincipal();
        if(p != null) {
            userName = p.getName();
        }
        if(userName == null) {
            userName = ANONYMER_NUTZER;
        }
        return userName;
    }
  public String escapeHtml(String text) {
    text = text.replace(specialChars[0], "&Auml;");
    text = text.replace(specialChars[1], "&Ouml;");
    text = text.replace(specialChars[2], "&Uuml;");
    text = text.replace(specialChars[3], "&auml;");
    text = text.replace(specialChars[4], "&ouml;");
    text = text.replace(specialChars[5], "&uuml;");
    text = text.replace(specialChars[6], "&szlig;");
    return text;
  }
  /**
   * Hier wird geprueft, ob der Name einer Klasse der Liste der erlaubten
   * Klassen bzw. Packages entspricht. Im Deployment Descriptor wird ein
   * Ausdruck wie z.B.
   *
   * de.uhilger.test.web;de.uhilger.test.api;de.uhilger.test.db.KlassenName
   *
   * erwartet. Diese Methode spaltet diesen Ausdruck an den ';' auf und prueft
   * fuer jeden Ausdruck, ob der KlassenName mit diesem Ausdruck beginnt.
   * Beginnt der Klassenname mit einem der Ausdruecke, wird der Zugriff erlaubt
   *
   * @param klassenName  Name der Klasse, fuer die der Zugriff geprueft
   * werden soll
   * @return true, wenn die Klasse laut dem Eintrag im Deployment Desccriptor
   * aufgerufen werden darf, false wenn nicht
   */
  protected boolean istErlaubt(String klassenName) {
      boolean erlaubt = false;
      for(int i = 0; i < klassen.length && !erlaubt; i++) {
          erlaubt = klassenName.startsWith(klassen[i]);
      }
      return erlaubt;
  }
}
src/de/uhilger/transit/web/TransitServlet.java
@@ -1,136 +1,148 @@
/*
    Transit - Remote procedure calls made simple
    Copyright (c) 2012  Ulrich Hilger
 Transit - Remote procedure calls made simple
 Copyright (c) 2012  Ulrich Hilger
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.
 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU Affero General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.
    This program 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 for more details.
 This program 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 for more details.
    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
 You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package de.uhilger.transit.web;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.Writer;
import java.io.InputStream;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Enumeration;
import java.util.Map;
import java.util.ArrayList;
import java.util.List;
import de.uhilger.transit.*;
/**
 * Das TransitServlet macht beliebige Klassen und Methoden
 * ueber HTTP zugaenglich.
 *
 * <p><b>Achtung:</b>Das TransitServlet sollte nur in einem
 * per Authentifizierung und Autorisierung geschuetzten
 * Bereich einer Webanwendung bereitgestellt werden da andernfalls
 * durchweg alle Klassen und Methoden, die sich auf dem Server
 * finden, zugaenglich werden.</p>
 *
 * <p>Fuer die Bereitstellung von Funktionen ist eine Berechtigungspruefung
 * noetig, die am besten in Form eines Filters implementiert wird.</p>
 *
 * Das TransitServlet macht beliebige Klassen und Methoden ueber HTTP
 * zugaenglich.
 *
 * <p>
 * <b>Achtung:</b>Das TransitServlet sollte nur in einem per Authentifizierung
 * und Autorisierung geschuetzten Bereich einer Webanwendung bereitgestellt
 * werden da andernfalls durchweg alle Klassen und Methoden, die sich auf dem
 * Server finden, zugaenglich werden.</p>
 *
 * <p>
 * Fuer die Bereitstellung von Funktionen ist eine Berechtigungspruefung noetig,
 * die am besten in Form eines Filters implementiert wird.</p>
 *
 * @author Copyright (c) Ulrich Hilger, http://uhilger.de
 * @author Published under the terms and conditions of
 * the <a href="http://www.gnu.org/licenses/agpl-3.0" target="_blank">GNU Affero General Public License</a>
 *
 * @author Published under the terms and conditions of the
 * <a href="http://www.gnu.org/licenses/agpl-3.0" target="_blank">GNU Affero
 * General Public License</a>
 *
 * @version 1, September 16, 2012
 */
public class TransitServlet extends HttpServlet {
public class TransitServlet extends AbstractServlet {
  /** Proforma Konstante fuer Schnittstelle Serializable */
  /**
   * Proforma Konstante fuer Schnittstelle Serializable
   */
  public static final long serialVersionUID = 42L;
  /** Name des Parameters Klasse */
  /**
   * Name des Parameters Klasse
   */
  public static final String CLASS_NAME = "c";
  /** Name des Parameters Methode */
  /**
   * Name des Parameters Methode
   */
  public static final String METHOD_NAME = "m";
  /** Name des Parameters Parameter */
  /**
   * Name des Parameters Parameter
   */
  public static final String PARAMETER_NAME = "p";
  /** Name des Parameters Format */
  /**
   * Name des Parameters Format
   */
  public static final String FORMAT_NAME = "f";
  public static final String MIME_JSON = "application/json";
  public static final String MIME_XML = "text/xml";
  private static final String[] specialChars = {new String("\u00c4"), new String("\u00d6"),
      new String("\u00dc"), new String("\u00e4"), new String("\u00f6"), new String("\u00fc"), new String("\u00df")};
  /**
   * Eine Anfrage via HTTP GET verarbeiten
   *
   * <p>Folgende Parameter werden erwartet:</p>
   * <p>c: Klasse, z.B. de.uhilger.test.EineKlasse<br>
   *
   * <p>
   * Folgende Parameter werden erwartet:</p>
   * <p>
   * c: Klasse, z.B. de.uhilger.test.EineKlasse<br>
   * m: Methode<br>
   * p: Erster Parameter der Methode in der Reihenfolge der Deklaration<br>
   * p: Zweiter Parameter der Methode in der Reihenfolge der Deklaration<br>
   *  .<br>
   *  .<br>
   * .
   * <br>
   * .
   * <br>
   * p: Letzter Parameter der Methode in der Reihenfolge der Deklaration</p>
   *
   * <p>Das Ergebnis der Verarbeitung wird in Form einer Zeichenkette im
   * Format der JavaScript Object Notation (JSON) in die Antwort der
   * HTTP-Anfrage geschrieben.</p>
   *
   *
   * <p>
   * Das Ergebnis der Verarbeitung wird in Form einer Zeichenkette im Format der
   * JavaScript Object Notation (JSON) in die Antwort der HTTP-Anfrage
   * geschrieben.</p>
   *
   * @param req die Anfrage, die verarbeitet werden soll
   * @param resp das Objekt, mit dem das Ergebnis der Verarbeitung mitgeteilt wird
   * @param resp das Objekt, mit dem das Ergebnis der Verarbeitung mitgeteilt
   * wird
   */
  @Override
  protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    anfrageAusfuehren(req, resp);
  }
  /**
   * Eine Anfrage via HTTP POST verarbeiten
   *
   * <p>Folgende Parameter werden erwartet:</p>
   * <p>c: Klasse, z.B. de.uhilger.test.EineKlasse<br>
   *
   * <p>
   * Folgende Parameter werden erwartet:</p>
   * <p>
   * c: Klasse, z.B. de.uhilger.test.EineKlasse<br>
   * m: Methode<br>
   * p: Erster Parameter der Methode in der Reihenfolge der Deklaration<br>
   * p: Zweiter Parameter der Methode in der Reihenfolge der Deklaration<br>
   *  .<br>
   *  .<br>
   * .
   * <br>
   * .
   * <br>
   * p: Letzter Parameter der Methode in der Reihenfolge der Deklaration</p>
   *
   * <p>Das Ergebnis der Verarbeitung wird in Form einer Zeichenkette im
   * Format der JavaScript Object Notation (JSON) in die Antwort der
   * HTTP-Anfrage geschrieben.</p>
   *
   *
   * <p>
   * Das Ergebnis der Verarbeitung wird in Form einer Zeichenkette im Format der
   * JavaScript Object Notation (JSON) in die Antwort der HTTP-Anfrage
   * geschrieben.</p>
   *
   * @param req die Anfrage, die verarbeitet werden soll
   * @param resp das Objekt, mit dem das Ergebnis der Verarbeitung mitgeteilt wird
   * @param resp das Objekt, mit dem das Ergebnis der Verarbeitung mitgeteilt
   * wird
   */
  @Override
  protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    anfrageAusfuehren(req, resp);
  }
  /**
   * Diese Methode verarbeitet die Anfragen, die via HTTP GET und HTTP POST
   * an dieses Servlet gestellt werden.
   *
   * Diese Methode verarbeitet die Anfragen, die via HTTP GET und HTTP POST an
   * dieses Servlet gestellt werden.
   *
   * @param req die Anfrage, die verarbeitet werden soll
   * @param resp das Objekt, mit dem das Ergebnis der Verarbeitung mitgeteilt wird
   * @param resp das Objekt, mit dem das Ergebnis der Verarbeitung mitgeteilt
   * wird
   */
  @SuppressWarnings("unchecked")
  public void anfrageAusfuehren(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
@@ -141,90 +153,83 @@
      List parameterListe = new ArrayList();
      String formatName = null;
      Enumeration en = req.getParameterNames();
      while(en.hasMoreElements()) {
      while (en.hasMoreElements()) {
        String pName = en.nextElement().toString();
        String[] pWerte = req.getParameterValues(pName);
        if(pName.equals(CLASS_NAME)) {
        if (pName.equals(CLASS_NAME)) {
          klassenName = pWerte[0];
        } else if(pName.equals(METHOD_NAME)) {
        } else if (pName.equals(METHOD_NAME)) {
          methodenName = pWerte[0];
        } else if(pName.equals(FORMAT_NAME)) {
        } else if (pName.equals(FORMAT_NAME)) {
          formatName = pWerte[0];
        } else {
          for(int i = 0; i < pWerte.length; i++) {
          for (int i = 0; i < pWerte.length; i++) {
            parameterListe.add(pWerte[i]);
          }
        }
      }
      Object[] parameter = parameterListe.toArray(new Object[0]);
      StringBuffer buf = new StringBuffer();
      server = new JavaServer();
      server.wandlerHinzufuegen(new JsonWandler());
      server.wandlerHinzufuegen(new JsonFlatWandler());
      server.wandlerHinzufuegen(new XmlWandler());
      Class cls = server.klasseFinden(klassenName);
      if(cls != null) {
        Object o = cls.newInstance();
        if(o != null) {
          if(o instanceof NutzerKontext) {
            ((NutzerKontext) o).setNutzerId(Waechter.getUserName(req));
          }
          if(o instanceof WebKontext) {
            ((WebKontext) o).setServletContext(getServletContext());
          }
          if(o instanceof RequestKontext) {
            ((RequestKontext) o).setRequest(req);
          }
          if(o instanceof VerbindungsKontext) {
            ((VerbindungsKontext) o).setVerbindung(req.getSession());
          }
        }
        Object resultat = null;
        if(formatName != null) {
          resultat = server.methodeAusfuehren(o, methodenName, formatName, parameter);
        } else {
          resultat = server.methodeAusfuehren(o, methodenName, JsonWandler.FORMAT_JSON, parameter);
        }
        if(resultat != null) {
          if(formatName == null) {
            resp.setContentType(MIME_JSON);
          } else {
            if(formatName.equalsIgnoreCase(JsonWandler.FORMAT_JSON) || formatName.equalsIgnoreCase(JsonFlatWandler.FORMAT_FLATJSON)) {
              resp.setContentType(MIME_JSON);
            } else if(formatName.equalsIgnoreCase(XmlWandler.FORMAT_XML)) {
              resp.setContentType(MIME_XML);
      StringBuilder buf = new StringBuilder();
      if (istErlaubt(klassenName)) {
        server = new JavaServer();
        server.wandlerHinzufuegen(new JsonWandler());
        server.wandlerHinzufuegen(new JsonFlatWandler());
        server.wandlerHinzufuegen(new XmlWandler());
        Class cls = server.klasseFinden(klassenName);
        if (cls != null) {
          Object o = cls.newInstance();
          if (o != null) {
            if (o instanceof NutzerKontext) {
              ((NutzerKontext) o).setNutzerId(getUserName(req));
            }
            if (o instanceof WebKontext) {
              ((WebKontext) o).setServletContext(getServletContext());
            }
            if (o instanceof RequestKontext) {
              ((RequestKontext) o).setRequest(req);
            }
            if (o instanceof VerbindungsKontext) {
              ((VerbindungsKontext) o).setVerbindung(req.getSession());
            }
          }
          buf.append(escapeHtml(resultat.toString()));
          Object resultat = null;
          if (formatName != null) {
            resultat = server.methodeAusfuehren(o, methodenName, formatName, parameter);
          } else {
            resultat = server.methodeAusfuehren(o, methodenName, JsonWandler.FORMAT_JSON, parameter);
          }
          if (resultat != null) {
            if (formatName == null) {
              resp.setContentType(MIME_JSON);
            } else {
              if (formatName.equalsIgnoreCase(JsonWandler.FORMAT_JSON) || formatName.equalsIgnoreCase(JsonFlatWandler.FORMAT_FLATJSON)) {
                resp.setContentType(MIME_JSON);
              } else if (formatName.equalsIgnoreCase(XmlWandler.FORMAT_XML)) {
                resp.setContentType(MIME_XML);
              }
            }
            buf.append(escapeHtml(resultat.toString()));
          } else {
            buf.append("<p>Resultat von server.methodeAusfuehren ist null.</p>");
          }
        } else {
          buf.append("<p>Resultat von server.methodeAusfuehren ist null.</p>");
          buf.append("<p>Ergebnis von server.klasseFinden ist null (Klasse nicht gefunden?).</p>");
        }
      } else {
        buf.append("<p>Ergebnis von server.klasseFinden ist null (Klasse nicht gefunden?).</p>");
        buf.append("<p>Klasse " + klassenName + " nicht erlaubt.</p>");
      }
      Writer w = resp.getWriter();
      w.write(buf.toString());
      w.flush();
      w.close();
    } catch(Exception ex) {
    } catch (Exception ex) {
      throw new ServletException(ex);
    } finally {
      if(server != null) {
      if (server != null) {
        server.aufloesen();
        server = null;
      }
    }
  }
  public String escapeHtml(String text) {
    text = text.replace(specialChars[0], "&Auml;");
    text = text.replace(specialChars[1], "&Ouml;");
    text = text.replace(specialChars[2], "&Uuml;");
    text = text.replace(specialChars[3], "&auml;");
    text = text.replace(specialChars[4], "&ouml;");
    text = text.replace(specialChars[5], "&uuml;");
    text = text.replace(specialChars[6], "&szlig;");
    return text;
  }
}
}
src/de/uhilger/transit/web/TransitServletRS.java
@@ -48,28 +48,13 @@
 * 
 * @version 1, September 16, 2012
 */
public class TransitServletRS extends HttpServlet {
public class TransitServletRS extends AbstractServlet {
  /** Proforma Konstante fuer Schnittstelle Serializable */
  public static final long serialVersionUID = 42L;
  
  private static final Logger logger = Logger.getLogger(TransitServletRS.class.getName());
  public static final String MIME_JSON = "application/json";
  public static final String MIME_XML = "text/xml";
  private static final String[] specialChars = {new String("\u00c4"), new String("\u00d6"),
      new String("\u00dc"), new String("\u00e4"), new String("\u00f6"), new String("\u00fc"), new String("\u00df")};
  public static final String KLASSEN_TRENNER = ";";
  //private String klassen;
  private String[] klassen;
  public void init(ServletConfig servletConfig) throws ServletException{
    this.klassen = servletConfig.getInitParameter("klassen").split(KLASSEN_TRENNER);
    super.init(servletConfig);
  }
  /**
   * Eine Anfrage via HTTP GET verarbeiten
   * 
@@ -130,46 +115,21 @@
    JavaServer server = null;
    try {
      /*
      String klassenName = null;
      String methodenName = null;
      List parameterListe = new ArrayList();
      String formatName = null;
      Enumeration en = req.getParameterNames();
      while(en.hasMoreElements()) {
        String pName = en.nextElement().toString();
        String[] pWerte = req.getParameterValues(pName);
        if(pName.equals(CLASS_NAME)) {
          klassenName = pWerte[0];
        } else if(pName.equals(METHOD_NAME)) {
          methodenName = pWerte[0];
        } else if(pName.equals(FORMAT_NAME)) {
          formatName = pWerte[0];
        } else {
          for(int i = 0; i < pWerte.length; i++) {
            parameterListe.add(pWerte[i]);
          }
        }
      }
      */
      /*
        http://server:port/contextpfad/servletpfad/de.irgend.eine.Klasse/methode/format/param1/param2/../paramN
        wird zu
        elemente[0] = /
        elemente[1] = de.irgend.eine.Klasse
        elemente[2] = methode
        elemente[3] = format
        elemente[4]-[n] = param1
        elemente[4]-[n] = param1 - paramn
      */
      
      String pathInfo = req.getPathInfo();
      logger.info("pathInfo: " + pathInfo);
      logger.log(Level.INFO, "pathInfo: {0}", pathInfo);
      String[] elemente = pathInfo.split("/");
      String klassenName = elemente[1];
      StringBuffer buf = new StringBuffer();
      StringBuilder buf = new StringBuilder();
      if(istErlaubt(klassenName)) {
      //if(this.klassen.contains(klassenName)) {
      //if(this.klassen.matches(klassenName)) {
        String methodenName = elemente[2];
        String formatName = elemente[3];
        List parameterListe = new ArrayList();
@@ -188,7 +148,7 @@
          Object o = cls.newInstance();
          if(o != null) {
            if(o instanceof NutzerKontext) {
              ((NutzerKontext) o).setNutzerId(Waechter.getUserName(req));
              ((NutzerKontext) o).setNutzerId(getUserName(req));
            }
            if(o instanceof WebKontext) {
              ((WebKontext) o).setServletContext(getServletContext());
@@ -240,38 +200,4 @@
    }
  }    
  
  /**
   * Hier wird geprueft, ob der Name einer Klasse der Liste der erlaubten
   * Klassen bzw. Packages entspricht. Im Deployment Descriptor wird ein
   * Ausdruck wie z.B.
   *
   * de.uhilger.test.web;de.uhilger.test.api;de.uhilger.test.db.KlassenName
   *
   * erwartet. Diese Methode spaltet diesen Ausdruck an den ';' auf und prueft
   * fuer jeden Ausdruck, ob der KlassenName mit diesem Ausdruck beginnt.
   * Beginnt der Klassenname mit einem der Ausdruecke, wird der Zugriff erlaubt
   *
   * @param klassenName  Name der Klasse, fuer die der Zugriff geprueft
   * werden soll
   * @return true, wenn die Klasse laut dem Eintrag im Deployment Desccriptor
   * aufgerufen werden darf, false wenn nicht
   */
  private boolean istErlaubt(String klassenName) {
      boolean erlaubt = false;
      for(int i = 0; i < klassen.length && !erlaubt; i++) {
          erlaubt = klassenName.startsWith(klassen[i]);
      }
      return erlaubt;
  }
  public String escapeHtml(String text) {
    text = text.replace(specialChars[0], "&Auml;");
    text = text.replace(specialChars[1], "&Ouml;");
    text = text.replace(specialChars[2], "&Uuml;");
    text = text.replace(specialChars[3], "&auml;");
    text = text.replace(specialChars[4], "&ouml;");
    text = text.replace(specialChars[5], "&uuml;");
    text = text.replace(specialChars[6], "&szlig;");
    return text;
  }
}