Persoenliche Mediazentrale
ulrich
2021-04-08 dfb7d34f88efbb3eb7632ae628ccfd4576824477
REST-Konformitaet des StorageHandler verbessert
6 files modified
2 files added
256 ■■■■ changed files
src/de/uhilger/mediaz/Server.java 22 ●●●●● patch | view | raw | blame | history
src/de/uhilger/mediaz/api/StorageHandler.java 98 ●●●● patch | view | raw | blame | history
src/de/uhilger/mediaz/entity/Abspielliste.java 48 ●●●●● patch | view | raw | blame | history
src/de/uhilger/mediaz/entity/Titel.java 44 ●●●●● patch | view | raw | blame | history
src/de/uhilger/mediaz/store/FileStorage.java 4 ●●●● patch | view | raw | blame | history
src/de/uhilger/mediaz/store/Storage.java 2 ●●●●● patch | view | raw | blame | history
src/mediaz_de_DE.properties 2 ●●● patch | view | raw | blame | history
www/ui/js/app.js 36 ●●●●● patch | view | raw | blame | history
src/de/uhilger/mediaz/Server.java
@@ -104,23 +104,18 @@
    String wwwData = App.getInitParameter(App.getRs(App.RB_AP_WWW_DATA));
    File wwwDir = new File(wwwData);
    //String ui = App.getInitParameter(App.getRs(App.RB_AP_UI));
    //File uiDir = new File(ui);
    HttpServer server = HttpServer.create(new InetSocketAddress(port), 0);
    server.createContext(ctx + App.getRs(RB_WEBROOT),
            new FileHandler(wwwDir.getAbsolutePath()));
    server.createContext(ctx + App.getRs(RB_WEBROOT), new FileHandler(wwwDir.getAbsolutePath()));
    ablageorteEinklinken(server);
    server.createContext(ctx + App.getRs(RB_STORE), new StorageHandler());
    //server.createContext(ctx + App.getRs(RB_UI_ROOT), new FileHandler(uiDir.getAbsolutePath()));
    server.createContext(ctx + App.getRs(RB_STOP_SERVER), new StopServerHandler());
    //server.createContext(ctx + App.getRs(RB_ABLAGE_TEST), new AblageTestHandler());
    //server.createContext(ctx + App.getRs(RB_STORE_TEST), new StoreTestHandler());
    server.setExecutor(Executors.newFixedThreadPool(20));
    server.start();
  }
  private void ablageorteEinklinken(HttpServer server) throws ClassNotFoundException, IOException {
  private void ablageorteEinklinken(HttpServer server)
              throws ClassNotFoundException, IOException {
    String typ = Ablageort.class.getSimpleName();
    FileStorage store = new FileStorage(App.getInitParameter(App.getRs(App.RB_AP_CONF)));
    List<String> orte = store.list(typ);
@@ -129,12 +124,11 @@
      String ortName = i.next();
      Entity e = store.read(typ, ortName);
      if(e instanceof Ablageort) {
        Ablageort ort = (Ablageort) e;
          Ablageort ablageort = (Ablageort) e;
          logger.fine(ctx + ablageort.getUrl());
          logger.fine(ablageort.getOrt());
          server.createContext(ctx + ablageort.getUrl(),
                  new ListFileHandler(new File(ablageort.getOrt()).getAbsolutePath()));
        Ablageort ablageort = (Ablageort) e;
        logger.log(Level.FINE, "{0}{1}", new Object[]{ctx, ablageort.getUrl()});
        logger.fine(ablageort.getOrt());
        server.createContext(ctx + ablageort.getUrl(),
          new ListFileHandler(new File(ablageort.getOrt()).getAbsolutePath()));
      }
    }
  }
src/de/uhilger/mediaz/api/StorageHandler.java
@@ -27,7 +27,6 @@
import de.uhilger.mediaz.store.FileStorage;
import de.uhilger.mediaz.entity.Entity;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
@@ -48,13 +47,29 @@
  
  /*
    PUT Die angegebene Ressource wird angelegt. Wenn die Ressource bereits
           existiert, wird sie geändert.
    Das REST-Muster sieht je Entitaet fuenf Faelle vor (Beispiel Ablageort):
    
    1. HTTP GET Ablageort/[Name]: Liefere den Ablageort als JSON
    2. HTTP GET Ablageort/: Liefere einer Liste von Ablageorten als JSON
    3. HTTP PUT: schreibe einen neuen Ablageort auf die Platte
    4. HTTP POST: schreibe Aenderungen auf die Platte
    5. HTTP DELETE: loesche den Ablageort
    1. HTTP GET Ablageort/[Name]  - Liefere den Ablageort namens [Name] als JSON
    2. HTTP GET Ablageort/liste/  - Liefere eine Liste mit Namen aller Ablageorte
                                     Es duerfen also keine Elemente namens "liste" angelegt werden
    3. HTTP GET Ablageort/        - Liefere eine Liste aller Ablageort-Objekte als JSON
    4. HTTP PUT Ablageort/[Name]  - Die angegebene Ressource wird angelegt. Wenn die Ressource
                                     bereits existiert, wird sie geändert.
    5. HTTP DELETE                - loesche den Ablageort
    falsch:
    1. HTTP GET Ablageort/[Name]  - Liefere den Ablageort namens [Name] als JSON
    2. HTTP GET Ablageort/liste/  - Liefere eine Liste mit Namen aller Ablageorte
    2. HTTP GET Ablageort/  - Liefere eine Liste aller Ablageort-Objekte als JSON
    3. HTTP PUT  - schreibe einen neuen Ablageort auf die Platte
    4. HTTP POST  - schreibe Aenderungen auf die Platte
    5. HTTP DELETE  - loesche den Ablageort
  
    Beispiele:
  
@@ -64,18 +79,14 @@
    HTTP GET an /mz/api/store/Ablageort/liste/  
    liefert eine Liste der Namen vorhandener Ablageorte
  
    HTTP GET an /mz/api/store/Ablageort/Katalog
    liest den Ablageort namens "Katalog"
    HTTP GET an /mz/api/store/Ablageort/[Name]
    liest den Ablageort namens [Name]
  
    HTTP POST an /mz/api/store/Ablageort
    schreibt den neuen Ablageort im Body der Anfrage (Neu)
    HTTP PUT an /mz/api/store/Ablageort/[Name]
    wenn [Name] existiert: Aenderung, sonst neu anlegen
  
    HTTP PUT an /mz/api/store/Ablageort
    sucht den Ablageort mit dem Namen laut Body der Anfrage
    und schreibt den Inhalt aus der Anfrage in die Datei (Aenderung)
    HTTP DELETE an /mz/api/store/Ablageort/Katalog
    löscht den Ablageort namens "Katalog"
    HTTP DELETE an /mz/api/store/Ablageort/[Name]
    löscht den Ablageort namens [Name]
  
  */
  
@@ -110,11 +121,12 @@
        break;
        
      case HTTP_PUT:
        response = aendern(e);
        response = put(e);
        break;
        
      case HTTP_POST:
        response = neu(e);
        response = "nicht unterstuertzt.";
        code = 404;
        break;
        
      case HTTP_DELETE:
@@ -133,6 +145,51 @@
    os.close();        
  }
  
  private String put(HttpExchange e) throws IOException {
    String path = e.getRequestURI().toString();
    String[] elems = path.split(App.getRs(Server.RB_SLASH));
    String type = elems[elems.length - 2];
    String elemName = elems[elems.length - 1]; // alter Name, wenn Aenderung
    if(!elemName.equalsIgnoreCase(App.getRs(RB_EP_LISTE))) {
      FileStorage fs = new FileStorage(App.getInitParameter(App.getRs(App.RB_AP_CONF)));
      Gson gson = new Gson();
      logger.log(Level.FINE, "type: {0}, token: {1}", new Object[]{type, fs.typeFromName(type).getType().getTypeName()});
      Object o = gson.fromJson(bodyLesen(e), fs.typeFromName(type).getType());
      if(o instanceof Entity) {
        Entity entity = (Entity) o;
        if(fs.exists(type, elemName)) {
          fs.delete(type, elemName);
          fs.write(entity, true);
        } else {
          fs.write(entity, false);
        }
        return type + App.getRs(Server.RB_SLASH) + entity.getName();
      } else {
        return "Ungueltiges Objekt im Body.";
      }
    } else {
      return "Ungueltiger Elementname: " + App.getRs(RB_EP_LISTE);
    }
  }
  /*
  private String schreiben(FileStorage fs, String typ, String name, String body, boolean overwrite) {
    Gson gson = new Gson();
    logger.log(Level.FINE, "type: {0}, token: {1}", new Object[]{typ, fs.typeFromName(typ).getType().getTypeName()});
    Object o = gson.fromJson(body, fs.typeFromName(typ).getType());
    if(o instanceof Entity) {
      Object antwortObjekt = fs.write((Entity) o, overwrite);
      if(antwortObjekt instanceof File) {
        File file = (File) antwortObjekt;
        logger.log(Level.FINE, "Datei {0} geschrieben.", file.getAbsolutePath());
        String filename = file.getName();
        return typ + FileHandler.STR_BLANK + filename;
      }
    }
    return typ + FileHandler.STR_BLANK + " etwas Seltsames ist passiert.";
  }
  */
  /*
  private String neu(HttpExchange e) throws IOException {
    return schreiben(e, false);
  }
@@ -140,7 +197,9 @@
  private String aendern(HttpExchange e) throws IOException {
    return schreiben(e, true);
  }
  */
  
  /*
  private String schreiben(HttpExchange e, boolean overwrite) throws IOException {
    String path = e.getRequestURI().toString();
    String[] elems = path.split(App.getRs(Server.RB_SLASH));
@@ -162,6 +221,7 @@
    }
    return type + FileHandler.STR_BLANK + " Operation 'neu' fuer bereits existierende Entitaet.";
  }
  */
  
  /*
  private String aendern(HttpExchange e) throws IOException {
@@ -184,7 +244,7 @@
    FileStorage fs = new FileStorage(App.getInitParameter(App.getRs(App.RB_AP_CONF)));
    if(path.endsWith(App.getRs(RB_SLASH))) {
      List list = null;
      if(path.endsWith(App.getRs(RB_EP_LISTE))) {
      if(elems[elems.length - 1].equalsIgnoreCase(App.getRs(RB_EP_LISTE))) {
        String type = elems[elems.length - 2];
        logger.fine(type);
        list = fs.list(type);
src/de/uhilger/mediaz/entity/Abspielliste.java
New file
@@ -0,0 +1,48 @@
/*
  Mediazentrale - Personal Media Center
  Copyright (C) 2021  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 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 <https://www.gnu.org/licenses/>.
 */
package de.uhilger.mediaz.entity;
import java.util.List;
/**
 *
 * @author ulrich
 */
public class Abspielliste implements Entity {
  private String name;
  private List<Titel> titel;
  public List<Titel> getTitel() {
    return titel;
  }
  public void setTitel(List titel) {
    this.titel = titel;
  }
  @Override
  public String getName() {
    return name;
  }
  public void setName(String name) {
    this.name = name;
  }
}
src/de/uhilger/mediaz/entity/Titel.java
New file
@@ -0,0 +1,44 @@
/*
  Mediazentrale - Personal Media Center
  Copyright (C) 2021  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 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 <https://www.gnu.org/licenses/>.
 */
package de.uhilger.mediaz.entity;
/**
 *
 * @author ulrich
 */
public class Titel {
  private String katalogUrl;
  private String name;
  public String getKatalogUrl() {
    return katalogUrl;
  }
  public void setKatalogUrl(String katalogUrl) {
    this.katalogUrl = katalogUrl;
  }
  public String getName() {
    return name;
  }
  public void setName(String titel) {
    this.name = titel;
  }
}
src/de/uhilger/mediaz/store/FileStorage.java
@@ -218,4 +218,8 @@
    return list;
  }
  
  public boolean exists(String typ, String name) {
    return getFile(typ, name).exists();
  }
}
src/de/uhilger/mediaz/store/Storage.java
@@ -102,4 +102,6 @@
   * @return true, wenn geloeschn, false wenn nicht
   */
  public boolean delete(String typ, String name);
  public boolean exists(String typ, String name);
}
src/mediaz_de_DE.properties
@@ -10,7 +10,7 @@
webroot=/
# uiroot=/ui
store=/api/store
epliste=liste/
epliste=liste
stopServer=/api/server/stop
testAblage=/api/test/ablage
testStore=/api/test/store
www/ui/js/app.js
@@ -193,19 +193,22 @@
          document.querySelector('#abspieler-url').value
        );
        var daten = JSON.stringify(abspieler);        
        if(typeof pl === "undefined" || pl.key !== plname) {
        //if(typeof pl === "undefined" || pl.key !== plname) {
        if(typeof pl.name === "undefined" || pl.name.length < 1) {
          // neu
          self.http_post('../api/store/Abspieler', daten, function (responseText) {
          self.http_put('../api/store/Abspieler/' + plname, daten, function (responseText) {
            // hier die Antwort verarbeiten
            self.abspieler_auswahl_fuellen();
            self.abspieler_liste();
          });
        } else {
          // aendern
          self.http_put('../api/store/Abspieler', daten, function (responseText) {
          self.http_put('../api/store/Abspieler/' + pl.name, daten, function (responseText) {
            // hier die Antwort verarbeiten
            self.abspieler_auswahl_fuellen();
            self.abspieler_liste();
          });
        }
        //document.querySelector(".zentraler-inhalt").innerHTML = '';
        self.abspieler_liste();
      });
      self.addEvtListener('#cancel-btn', 'click', function () {
        //document.querySelector(".zentraler-inhalt").innerHTML = '';
@@ -221,6 +224,7 @@
              // hier die Antwort verarbeiten
              self.dialog_schliessen();
              //document.querySelector(".zentraler-inhalt").innerHTML = '';
              self.abspieler_auswahl_fuellen();
              self.abspieler_liste();
            });
          });
@@ -240,19 +244,20 @@
          document.querySelector('#einstellung-value').value
        );
        var daten = JSON.stringify(pref);        
        if(typeof k === "undefined" || k.key !== pkey) {
        //if(typeof k === "undefined" || k.key !== pkey) {
        if(typeof k.key === "undefined" ||  k.key.length < 1) {
          // neu
          self.http_post('../api/store/Einstellung', daten, function (responseText) {
          self.http_put('../api/store/Einstellung/' + pkey, daten, function (responseText) {
            // hier die Antwort verarbeiten
            self.prefs_liste();
          });
        } else {
          // aendern
          self.http_put('../api/store/Einstellung', daten, function (responseText) {
          self.http_put('../api/store/Einstellung/' + k.key, daten, function (responseText) {
            // hier die Antwort verarbeiten
            self.prefs_liste();
          });
        }
        //document.querySelector(".zentraler-inhalt").innerHTML = '';
        self.prefs_liste();
      });
      self.addEvtListener('#cancel-btn', 'click', function () {
        //document.querySelector(".zentraler-inhalt").innerHTML = '';
@@ -296,19 +301,20 @@
          document.querySelector('#ablageort-url').value
        );
        var daten = JSON.stringify(a);        
        if(typeof ort === "undefined" || ort.name !== aName) {
        //if(typeof ort === "undefined" || ort.name !== aName) {
        if(typeof ort.name === "undefined"  || ort.name.length < 1) {
          // neu
          self.http_post('../api/store/Ablageort', daten, function (responseText) {
          self.http_put('../api/store/Ablageort/' + aName, daten, function (responseText) {
            // hier die Antwort verarbeiten
            self.ablageort_liste();
          });
        } else {
          // aendern
          self.http_put('../api/store/Ablageort', daten, function (responseText) {
          self.http_put('../api/store/Ablageort/' + ort.name, daten, function (responseText) {
            // hier die Antwort verarbeiten
            self.ablageort_liste();
          });
        }
        //document.querySelector(".zentraler-inhalt").innerHTML = '';
        self.ablageort_liste();
      });
      self.addEvtListener('#cancel-btn', 'click', function () {
        //document.querySelector(".zentraler-inhalt").innerHTML = '';