Dateien verwalten mit Modul jdk.httpserver
ulrich
2024-01-15 8e6840f2eaefe0f7b4763acd5edace0187bf29d3
src/de/uhilger/httpserver/cm/FileManager.java
@@ -17,6 +17,10 @@
 */
package de.uhilger.httpserver.cm;
import de.uhilger.httpserver.cm.actor.Zipper;
import de.uhilger.httpserver.cm.actor.Eraser;
import de.uhilger.httpserver.cm.actor.Unzipper;
import de.uhilger.httpserver.cm.actor.Renamer;
import com.google.gson.Gson;
import com.sun.net.httpserver.Authenticator;
import com.sun.net.httpserver.Headers;
@@ -31,7 +35,6 @@
import de.uhilger.httpserver.oauth.BearerAuthenticator;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
@@ -43,15 +46,9 @@
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.List;
import java.util.logging.Logger;
import java.util.logging.Level;
import java.util.zip.Adler32;
import java.util.zip.CheckedOutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;
/**
 * <p>Der FileManager verknuepft einen HTTP-Endpunkt mit einem Ordner des lokalen
@@ -105,9 +102,6 @@
 */
public class FileManager extends FileHandler implements ThreadListener {
  /* Der Logger fuer diesen ListFileHandler */
  private static final Logger logger = Logger.getLogger(FileManager.class.getName());
  /*
  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")};
@@ -158,7 +152,7 @@
      String userId = e.getPrincipal().getUsername();
      if(auth.hasRole(userId, e.getHttpContext().getAttributes().get(ATTR_ROLE).toString())) {
        String method = e.getRequestMethod();
        logger.fine("method: " + method);
        //logger.fine("method: " + method);
        HttpHelper helper = new HttpHelper();
        switch (method) {
          case HttpHelper.HTTP_GET:
@@ -187,7 +181,7 @@
    if (query != null) {
      String[] params = query.split("=");
      for (String param : params) {
        logger.fine("param: " + param);
        //logger.fine("param: " + param);
      }
      switch (params[0]) {
        case P_COPY:
@@ -199,19 +193,19 @@
        case P_DUPLICATE:
          if(Boolean.parseBoolean(params[1])) {
            String neuerDateiName = duplizieren(exchange, helper);
            logger.fine("neuer Name: " + neuerDateiName);
            //logger.fine("neuer Name: " + neuerDateiName);
            standardHeaderUndAntwort(exchange, SC_OK, neuerDateiName);
          }
          break;
        case P_RENAME:
          String neuerDateiName = umbenennen(exchange, helper, params[1]);
          logger.fine("neuer Name: " + neuerDateiName);
          String neuerDateiName = new Renamer().umbenennen(exchange, helper, params[1]);
          //logger.fine("neuer Name: " + neuerDateiName);
          standardHeaderUndAntwort(exchange, SC_OK, neuerDateiName);
          break;
        case P_ZIP:
          String path = exchange.getRequestURI().toString();
          logger.fine(path);
          String antwort = packFolder(helper.getFileName(exchange), path, exchange);
          //logger.fine(path);
          String antwort = new Zipper().packFolder(helper.getFileName(exchange), path, exchange.getHttpContext().getAttributes().get(FileHandler.ATTR_FILE_BASE).toString());
          if(antwort.equalsIgnoreCase("ok")) {
            standardHeaderUndAntwort(exchange, SC_OK, antwort);
          } else {
@@ -220,8 +214,8 @@
          break;
        case P_UNZIP:
          path = exchange.getRequestURI().toString();
          logger.fine(path);
          antwort = extractZipfile(helper.getFileName(exchange), path, exchange);
          //logger.fine(path);
          antwort = new Unzipper().extractZipfile(helper.getFileName(exchange), path, exchange.getHttpContext().getAttributes().get(FileHandler.ATTR_FILE_BASE).toString());
          if(antwort.equalsIgnoreCase("ok")) {
            standardHeaderUndAntwort(exchange, SC_OK, antwort);
          } else {
@@ -233,15 +227,39 @@
      speichern(exchange, helper);
    }
  }
  public class DirList {
    private String pfad;
    private List<Datei> dateien;
    public String getPfad() {
      return pfad;
    }
    public void setPfad(String pfad) {
      this.pfad = pfad;
    }
    public List<Datei> getDateien() {
      return dateien;
    }
    public void setDateien(List<Datei> dateien) {
      this.dateien = dateien;
    }
  }
  private void liste(HttpExchange e, HttpHelper helper) throws IOException {
    String path = e.getRequestURI().toString();
    logger.fine(path);
    //logger.fine(path);
    String fName = helper.getFileName(e);
    String dirListPath = e.getHttpContext().getPath() + fName;
    if (path.endsWith(STR_SLASH)) {      
      logger.fine("fName: " + fName);
      //logger.fine("fName: " + fName);
      File dir = new File(e.getHttpContext().getAttributes().get(FileHandler.ATTR_FILE_BASE).toString(), fName);
      logger.fine("absPath: " + dir.getAbsolutePath());
      //logger.fine("absPath: " + dir.getAbsolutePath());
      File[] files = dir.listFiles(new ImageFileFilter());
      if(files != null && files.length > 0) {
        Arrays.sort(files);
@@ -255,7 +273,7 @@
          } else {
            datei.setTyp(Datei.TYP_DATEI);
          }
          datei.setPfad(e.getHttpContext().getPath() + fName);
          //datei.setPfad(e.getHttpContext().getPath() + fName);
          String lowerName = dateiName.toLowerCase();
          if (lowerName.endsWith(ImageActor.JPEG)
                  || lowerName.endsWith(ImageActor.JPG)
@@ -276,8 +294,12 @@
          }
        }
        if(liste.size() > 0) {
          DirList list = new DirList();
          list.setPfad(dirListPath);
          list.setDateien(liste);
          Gson gson = new Gson();
          String json = gson.toJson(liste);
          //String json = gson.toJson(liste);
          String json = gson.toJson(list);
          //byte[] bytes = json.getBytes();
          //logger.fine("json: '" + json + "'");
          HttpResponder r = new HttpResponder();
@@ -295,7 +317,7 @@
        String fromName = fName.replace(ImageActor.B64, "");
        File fromFile = new File(e.getHttpContext().getAttributes().get(FileHandler.ATTR_FILE_BASE).toString(), fromName);
        File toFile = new File(e.getHttpContext().getAttributes().get(FileHandler.ATTR_FILE_BASE).toString(), fName);
        logger.fine("from " + fromFile.getAbsolutePath() + ", to " + toFile.getAbsolutePath());
        //logger.fine("from " + fromFile.getAbsolutePath() + ", to " + toFile.getAbsolutePath());
        if(!toFile.exists()) {
          actor.b64Image(fromFile, toFile);
        }
@@ -359,20 +381,20 @@
  private void emptyListResponse(HttpExchange e) throws IOException {
    HttpResponder r = new HttpResponder();
    String json = "{}";
    logger.log(Level.FINE, "json: ''{0}''", json);
    //logger.log(Level.FINE, "json: ''{0}''", json);
    r.antwortSenden(e, SC_OK, json);        
  }
  private void speichern(HttpExchange exchange, HttpHelper helper) throws IOException {
    String fileName = helper.getFileName(exchange);
    logger.info("fileName: " + fileName);
    //logger.info("fileName: " + fileName);
    // file ist die Datei, um die es geht
    File file = new File(exchange.getHttpContext().getAttributes().get(FileHandler.ATTR_FILE_BASE).toString(), fileName);
    String method = exchange.getRequestMethod();
    if (fileName.endsWith(STR_SLASH)) {
      logger.info("neuer Ordner: " + file.getAbsolutePath());
      //logger.info("neuer Ordner: " + file.getAbsolutePath());
      // neuen Ordner erstellen oder ablehnen, wenn der Ordner schon existiert
      if (method.equalsIgnoreCase(HttpHelper.HTTP_POST)) {
        if (!file.exists()) {
@@ -387,7 +409,7 @@
        standardHeaderUndAntwort(exchange, SC_METHOD_NOT_ALLOWED, antwort);        
      }
    } else {
      logger.info("Datei speichern: " + file.getAbsolutePath());
      //logger.info("Datei speichern: " + file.getAbsolutePath());
      // Datei speichern
      if (method.equalsIgnoreCase(HttpHelper.HTTP_POST)) {
        if (file.exists()) {
@@ -419,9 +441,9 @@
      // dekodieren
      String content = sb.toString();
      logger.fine(content);
      //logger.fine(content);
      String decoded = URLDecoder.decode(content, UTF8);
      logger.fine(decoded);
      //logger.fine(decoded);
      // in Datei schreiben
      byte[] bytes = decoded.getBytes();
@@ -438,7 +460,7 @@
  }
  private void copyOrMove(HttpExchange exchange, String quelle, String ziel, int op) throws IOException {
    logger.fine("quelle: " + quelle + ", ziel: " + ziel);
    //logger.fine("quelle: " + quelle + ", ziel: " + ziel);
    String[] dateiNamen = dateiliste(exchange);
    copyOrMoveFiles(quelle, ziel, dateiNamen, op, exchange);
    standardHeaderUndAntwort(exchange, SC_OK, "Dateien verarbeitet.");
@@ -450,9 +472,9 @@
    File targetDir = new File(e.getHttpContext().getAttributes().get(FileHandler.ATTR_FILE_BASE).toString(), toPath);
    for (String fileName : fileNames) {
      File srcFile = new File(srcDir, fileName);
      logger.fine("srcFile: " + srcFile);
      //logger.fine("srcFile: " + srcFile);
      if (srcFile.isDirectory()) {
        logger.fine("srcFile is directory.");
        //logger.fine("srcFile is directory.");
        OrdnerBearbeiter bearbeiter = new OrdnerBearbeiter();
        bearbeiter.setTargetDir(targetDir.toPath());
        bearbeiter.setOperation(operation);
@@ -484,13 +506,13 @@
  private void loeschen(HttpExchange exchange, HttpHelper helper) throws IOException {
    String[] dateiNamen = dateiliste(exchange);
    String relPfad = helper.getFileName(exchange);
    deleteFiles(relPfad, Arrays.asList(dateiNamen), exchange);
    new Eraser().deleteFiles(relPfad, Arrays.asList(dateiNamen), exchange.getHttpContext().getAttributes().get(FileHandler.ATTR_FILE_BASE).toString());
    standardHeaderUndAntwort(exchange, SC_OK, "Dateien geloescht.");
  }
  private String[] dateiliste(HttpExchange exchange) throws IOException {
    String body = new HttpHelper().bodyLesen(exchange);
    logger.fine("dateien: " + body);
    //logger.fine("dateien: " + body);
    Gson gson = new Gson();
    return gson.fromJson(body, String[].class);
  }
@@ -512,124 +534,17 @@
    return destFile.getName();
  }
  public String umbenennen(HttpExchange exchange, HttpHelper helper, String neuerName) throws IOException {
    File neueDatei;
    String relPfad = helper.getFileName(exchange);
    File file = new File(exchange.getHttpContext().getAttributes().get(FileHandler.ATTR_FILE_BASE).toString(), relPfad);
    String fname = file.getName().toLowerCase();
    if(fname.endsWith(ImageActor.JPEG) || fname.endsWith(ImageActor.JPG) || fname.endsWith(ImageActor.PNG)) {
      neueDatei = renameImgFiles(file.getParentFile(), file, neuerName);
    } else {
      neueDatei = new File(file.getParentFile(), neuerName);
      file.renameTo(neueDatei);
    }
    return neueDatei.getName();
  }
  public File renameImgFiles(File targetDir, File targetFile, String newName) throws IOException {
    String alt;
    String neu;
    File neueDatei = targetFile;
    int newdotpos = newName.lastIndexOf(STR_DOT);
    String newfname = newName.substring(0, newdotpos);
    String newext = newName.substring(newdotpos);
    logger.fine("newfname: " + newfname + ", newext: " + newext);
    String fnameext = targetFile.getName();
    int dotpos = fnameext.lastIndexOf(STR_DOT);
    String fname = fnameext.substring(0, dotpos);
    String ext = fnameext.substring(dotpos);
    logger.fine("fname: " + fname + ", ext: " + ext);
    DirectoryStream<Path> stream = Files.newDirectoryStream(targetDir.toPath(), fname + "*" + ext); //"*.{txt,doc,pdf,ppt}"
    for (Path path : stream) {
      logger.fine(path.getFileName().toString());
      alt = path.getFileName().toString();
      logger.fine("alt: " + alt);
      if(alt.contains(ImageActor.TN)) {
        neu = newfname + ImageActor.TN + newext;
      } else if (alt.contains(ImageActor.KL)) {
        neu = newfname + ImageActor.KL + newext;
      } else if(alt.contains(ImageActor.GR)) {
        neu = newfname + ImageActor.GR + newext;
      } else if(alt.contains(ImageActor.MT)) {
        neu = newfname + ImageActor.MT + newext;
      } else if(alt.contains(ImageActor.SM)) {
        neu = newfname + ImageActor.SM + newext;
      } else {
        neu = newName;
      }
      neueDatei = new File(targetDir, neu);
      path.toFile().renameTo(neueDatei);
    }
    stream.close();
    return neueDatei;
  }
  private String deleteFiles(String relPath, List<String> fileNames, HttpExchange e) {
    String result = null;
    try {
      logger.fine(fileNames.toString());
      if (!relPath.startsWith(STR_DOT)) {
        File targetDir = new File(e.getHttpContext().getAttributes().get(FileHandler.ATTR_FILE_BASE).toString(), relPath); // getTargetDir(relPath);
        logger.fine("targetDir: " + targetDir);
        for (String fileName : fileNames) {
          File targetFile = new File(targetDir, fileName);
          logger.fine(targetFile.getAbsolutePath());
          if (targetFile.isDirectory()) {
            OrdnerBearbeiter bearbeiter = new OrdnerBearbeiter();
            bearbeiter.setOperation(OP_DELETE);
            Files.walkFileTree(targetFile.toPath(), bearbeiter);
          } else {
            /*
                Wenn targetFile mit jpg, jpeg oder png endet,
                muss eine Unterfunktion eine Liste aller Dateien bilden,
                die so heissen, also z.B. alle [Dateiname]*.jpg
             */
            String fname = targetFile.getName().toLowerCase();
            if (fname.endsWith(ImageActor.JPEG)
                    || fname.endsWith(ImageActor.JPG)
                    || fname.endsWith(ImageActor.PNG)) {
              deleteImgFiles(targetDir, targetFile);
            } else {
              targetFile.delete();
            }
          }
        }
        result = "deleted";
      }
    } catch (Throwable ex) {
      logger.log(Level.SEVERE, ex.getLocalizedMessage(), ex);
    }
    return result;
  }
  private void deleteImgFiles(File targetDir, File targetFile) throws IOException {
    String fnameext = targetFile.getName();
    int dotpos = fnameext.lastIndexOf(STR_DOT);
    String fname = fnameext.substring(0, dotpos);
    String ext = fnameext.substring(dotpos);
    logger.fine("fname: " + fname + ", ext: " + ext);
    DirectoryStream<Path> stream = Files.newDirectoryStream(targetDir.toPath(), fname + "*" + ext); //"*.{txt,doc,pdf,ppt}"
    for (Path path : stream) {
      logger.fine(path.getFileName().toString());
      Files.delete(path);
    }
    stream.close();
  }
  private void moveImgFilesToDirectory(File srcFile, File srcDir, File targetDir, boolean createDestDir) throws IOException {
    String fnameext = srcFile.getName();
    int dotpos = fnameext.lastIndexOf(STR_DOT);
    String fname = fnameext.substring(0, dotpos);
    String ext = fnameext.substring(dotpos);
    logger.fine("fname: " + fname + ", ext: " + ext);
    //logger.fine("fname: " + fname + ", ext: " + ext);
    Path targetPath = targetDir.toPath();
    DirectoryStream<Path> stream = Files.newDirectoryStream(srcDir.toPath(), fname + "*" + ext); //"*.{txt,doc,pdf,ppt}"
    for (Path path : stream) {
      logger.fine(path.getFileName().toString());
      //logger.fine(path.getFileName().toString());
      //Files.delete(path);
      Files.move(path, targetPath.resolve(path.getFileName()));
    }
@@ -641,186 +556,4 @@
    resHeaders.add(CONTENT_TYPE, HttpHelper.CT_TEXT_HTML);
    new HttpResponder().antwortSenden(exchange, status, antwort);
  }  
  /* --------- ZIP entpacken ---------------- */
  public String extractZipfile(String fName, String relPath, HttpExchange e) {
    logger.fine("fName: " + fName + ", relPath: " + relPath);
    String result = null;
    if (!relPath.startsWith(".")) {
      try {
        //File targetDir = new File(fileBase, relPath);
        //File targetDir = getTargetDir(relPath);
        File archive = new File(e.getHttpContext().getAttributes().get(FileHandler.ATTR_FILE_BASE).toString(), fName);
        if(extract(archive)) {
          result = "ok";
        } else {
          result = "error while extracting";
        }
      } catch(Exception ex) {
        result = ex.getLocalizedMessage();
        logger.log(Level.SEVERE, ex.getLocalizedMessage(), ex);
      }
    } else {
      result = "Falsche relative Pfadangabe.";
    }
    return result;
  }
  /**
    * extract a given ZIP archive to the folder respective archive resides in
    * @param archive  the archive to extract
    * @throws Exception
    */
   private boolean extract(File archive) throws Exception {
      ZipFile zipfile = new ZipFile(archive);
      Enumeration en = zipfile.entries();
      while(en.hasMoreElements()) {
         ZipEntry zipentry = (ZipEntry) en.nextElement();
         unzip(zipfile, zipentry, archive.getParent());
      }
      zipfile.close();
      return true;
   }
   /**
    * unzip a given entry of a given zip file to a given location
    * @param zipfile  the zip file to read an entry from
    * @param zipentry  the zip entry to read
    * @param destPath  the path to the destination location for the extracted content
    * @throws IOException
    */
   private void unzip(ZipFile zipfile, ZipEntry zipentry, String destPath) throws IOException {
      byte buf[] = new byte[1024];
      InputStream is = zipfile.getInputStream(zipentry);
      String outFileName = destPath + File.separator + zipentry.getName();
      File file = new File(outFileName);
      if(!zipentry.isDirectory()) {
         file.getParentFile().mkdirs();
         if(!file.exists())
            file.createNewFile();
         FileOutputStream fos = new FileOutputStream(file);
         int i = is.read(buf, 0, 1024);
         while(i > -1) {
            fos.write(buf, 0, i);
            i = is.read(buf, 0, 1024);
         }
         fos.close();
         is.close();
      } else {
         file.mkdirs();
      }
   }
  /* --------------- Ordner packen ----------------- */
  /**
   * Einen Ordner packen.
   *
   * Als Ziel wird eine neue Datei mit Dateiendung '.zip' erzeugt, die so
   * heisst wie der Ordner, der gapckt werden soll. Die Datei mit
   * dem gepackten Ordnerinhalt wird in dem Ordner angelegt, der den zu
   * packenden Ordner enthaelt.
   *
   * @param fName  Name des zu packenden Ordners
   * @param relPath  relativer Pfad zum Ordner, der gepackt werden soll
   * @return die Meldung mit dem Ergebnis. Wenn die Meldung nicht "ok" lautet
   * wurde die ZIP-Datei nicht erzeugt und die Meldung nennt den Grund.
   */
  public String packFolder(String fName, String relPath, HttpExchange e) {
    if (!relPath.startsWith(".")) {
      try {
        //String fName = getFileName(e);
        logger.fine("fName: " + fName);
        if (fName.endsWith(STR_SLASH)) {
          File dir = new File(e.getHttpContext().getAttributes().get(FileHandler.ATTR_FILE_BASE).toString(), fName);
          if(dir.isDirectory()) {
            logger.fine("absPath: " + dir.getAbsolutePath());
            File parentDir = dir.getParentFile();
            StringBuilder fname = new StringBuilder();
            fname.append(dir.getName());
            fname.append(".zip");
            File archiveFile = new File(parentDir, fname.toString());
            pack(dir.getAbsolutePath(), archiveFile.getAbsolutePath());
            return "ok";
          } else {
            return "kein Ordner";
          }
        } else {
          return "kein Ordner";
        }
      } catch(Exception ex) {
        String result = ex.getLocalizedMessage();
        logger.log(Level.SEVERE, result, ex);
        return result;
      }
    } else {
      return "Falsche relative Pfadangabe";
    }
  }
   /**
    * pack the contents of a given folder into a new ZIP compressed archive
    * @param folder  absolute path and name of the folder to pack
    * @param archive  absolute path and name of the archive to create from the given files
    * @throws Exception
    */
   private boolean pack(String folder, String archive) throws Exception {
      File file = new File(archive);
      FileOutputStream fos = new FileOutputStream(file);
      CheckedOutputStream checksum = new CheckedOutputStream(fos, new Adler32());
      ZipOutputStream zos = new ZipOutputStream(checksum);
      pack(zos, folder, "");
      zos.flush();
      zos.finish();
      zos.close();
      fos.flush();
      fos.close();
      return true;
   }
   /**
    * go through the given file structure recursively
    * @param zipFile  the ZIP file to write to
    * @param srcDir  the directory to pack during this cycle
    * @param subDir  the subdirectory to append to names of file entries inside the archive
    * @throws IOException
    */
   private void pack(ZipOutputStream zipFile, String srcDir, String subDir) throws IOException {
      File[] files = new File(srcDir).listFiles();
      for(int i = 0; i < files.length; i++) {
         if(files[i].isDirectory()) {
            pack(zipFile, files[i].getAbsolutePath(), subDir + File.separator + files[i].getName());
         }
         else {
            packFile(zipFile, subDir, files[i]);
         }
      }
   }
   /**
    * pack a given file
    * @param zipFile  the ZIP archive to pack to
    * @param dir  the directory name to append to name of file entry inside archive
    * @param file  the file to pack
    * @throws IOException
    */
   private void packFile(ZipOutputStream zipFile, String dir, File file) throws IOException
   {
      FileInputStream fileinputstream = new FileInputStream(file);
      byte buf[] = new byte[fileinputstream.available()];
      fileinputstream.read(buf);
      String dirWithSlashes = dir.replace('\\', '/');
      //System.out.println("zipping " + dirWithSlashes + "/" + file.getName());
      ZipEntry ze = new ZipEntry(dirWithSlashes + "/" + file.getName());
      ze.setMethod(ZipEntry.DEFLATED);
      zipFile.putNextEntry(ze);
      zipFile.write(buf, 0, buf.length);
      zipFile.closeEntry();
      fileinputstream.close();
   }
}