Dateiverwaltung für die WebBox
ulrich
2017-03-08 438b168cad54853a8b419e6c19e639b6d2f70bc0
src/java/de/uhilger/filecms/api/FileMgr.java
@@ -1,147 +1,385 @@
/*
    Dateiverwaltung - File management in your browser
    Copyright (C) 2017 Ulrich Hilger, http://uhilger.de
    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 <http://www.gnu.org/licenses/>.
*/
package de.uhilger.filecms.api;
import de.uhilger.filesystem.FileRef;
import de.uhilger.transit.web.RequestKontext;
import de.uhilger.transit.web.WebKontext;
import de.uhilger.filecms.data.FileRef;
import de.uhilger.filecms.web.Initialiser;
import de.uhilger.wbx.Bild;
import java.awt.Container;
import java.awt.Image;
import java.awt.MediaTracker;
import java.awt.Toolkit;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Reader;
import java.security.Principal;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.io.FileUtils;
/**
 *
 * @author ulrich
 */
public class FileMgr implements WebKontext, RequestKontext {
public class FileMgr extends Api {
  private static final Logger logger = Logger.getLogger(FileMgr.class.getName());
  
  public static final String FILE_BASE = "fileBase";
  public static final String PUB_DIR_PATH = "www/";
  public static final String HOME_DIR_PATH = "home/";
  public static final String PUB_DIR_NAME = "Oeffentlich";
  public static final String HOME_DIR_NAME = "Persoenlicher Ordner";
  
  private ServletContext ctx;
  private HttpServletRequest req;
  public static final int OP_COPY = 1;
  public static final int OP_MOVE = 2;
  
  public String hallo() {
    return "Hallo Welt!";
  }
  
  // http://localhost:8097/file-cms/rpc/de.uhilger.filecms.api.FileMgr/getBase/JSONNICE
  public FileRef getBase() {
    FileRef ref = null;
    //String fileBase = getServletContext().getInitParameter(FILE_BASE);
    // -Dfilecms.base=/pfad/zu/daten
    //String fileBase = System.getProperty("filecms.base");
    //File file = new File(fileBase);
    //logger.info(file.getAbsolutePath());
    //logger.info(getWebappsDir().getAbsolutePath());
    /*
        file = new File("."); liefert
        /home/ulrich/dev/lib/java/tomcat/tomcat2-8.5.9/bin/.
        ..auf der WebBox aber
        /home/ulrich/srv/wbx_probe/.
        ..weil das Startskript dort liegt
        der Tomcat der WebBox ist unter
        sys/jrs/tomcat/bin
        also z.B.
        /home/ulrich/srv/wbx_probe/sys/jrs/tomcat/bin
        das Datenverzeichnis ist z.B. auf
        /home/ulrich/srv/wbx_probe/daten
        dann ist das Datenverzeichnis unter
        ../../../daten
        Der Ausdruck file = new File("."); liefert stets den
        Ort von dem aus der Java-Prozess gestartet wurde.
        Die unten folgende Bestimmung des Datenverzeichnisses
        ist beschraenkt auf das Datenverzeichnis der WebBox,
        entweder relativ zum Startskript der WebBox oder
        dem Startskript von Tomcat, wie es aus Netbeans heraus
        waehrend der Entwicklung genutzt wird.
        Besser ware vielleicht eine Bestimmung ueber einen
        Systemparameter -Dfilecms.base=... wie weiter oben
        auskommentiert. Damit liesse sich das file-cms auch
        ohne WebBox einsetzen. Allerdings muss dann das
        Datenverzeichnis im Start-Skript gebildet werden,
        also ausserhalb von Java, wenn es dynamisch aus
        einem Pfad relativ zum Start-Skript erzeugt werden
        soll.
    */
    File file = new File(".");
    String path = file.getAbsolutePath();
    path = path.substring(0, path.length() - 1);
    file = new File(path);
    if(path.endsWith("bin")) {
      file = file.getParentFile().getParentFile().getParentFile();
  public List<FileRef> list(String relPath) {
    List<FileRef> files = new ArrayList();
    if(relPath.length() == 0) {
      FileRef namedPublicFolder = new FileRef(PUB_DIR_NAME, true);
      logger.finer(namedPublicFolder.getAbsolutePath());
      FileRef namedHomeFolder = new FileRef(HOME_DIR_NAME, true);
      logger.finer(namedHomeFolder.getAbsolutePath());
      files = new ArrayList();
      files.add(namedHomeFolder);
      files.add(namedPublicFolder);
    } else {
    }
    file = new File(file, "daten/");
    ref = new FileRef(file.getAbsolutePath(), file.isDirectory());
    return ref;
      String path = getTargetDir(relPath).getAbsolutePath();
      logger.fine("listing path: " + path);
      File dir = new File(path);
      if(dir.exists()) {
        File[] fileArray = dir.listFiles();
        for(int i = 0; i < fileArray.length; i++) {
          logger.fine(fileArray[i].toURI().toString());
          String fname = fileArray[i].toURI().toString().replace("file:/", "");
          if(fileArray[i].isDirectory()) {
            fname = fname.substring(0, fname.length() - 1);
          }
          logger.fine(fname);
          files.add(new FileRef(fname, fileArray[i].isDirectory()));
        }
      }
    }
    return files;
  }
  
  public FileRef saveTextFile(String relPath, String fileName, String contents) {
    FileRef savedFile = null;
  public FileRef newFolder(String relPath, String folderName) {
    logger.finer(relPath);
    String targetPath = null;
    if(relPath.startsWith(PUB_DIR_NAME)) {
      targetPath = PUB_DIR_PATH + getUserName() + "/" + relPath.substring(PUB_DIR_NAME.length()) + "/" + folderName;
    } else if(relPath.startsWith(HOME_DIR_NAME)) {
      targetPath = HOME_DIR_PATH + getUserName() + "/" + relPath.substring(HOME_DIR_NAME.length()) + "/" + folderName;
    } else {
      // kann eigentlich nicht sein..
    }
    logger.finer(targetPath);
    File targetDir = new File(getBase().getAbsolutePath(), targetPath);
    targetDir.mkdirs();
    return new FileRef(targetDir.getAbsolutePath(), true);
  }
  public String getCode(String relPath, String fileName) {
    String code = null;
    Object p = getRequest().getUserPrincipal();
    if(p instanceof Principal) {
      Reader reader = null;
      try {
        File targetFile = new File(getTargetDir(relPath), fileName);
        //reader = new InputStreamReader(new FileInputStream(targetFile), "UTF8");
        reader = new FileReader(targetFile);
        StringBuffer buf = new StringBuffer();
        char[] readBuffer = new char[1024];
        int charsRead = reader.read(readBuffer);
        while(charsRead > -1) {
          buf.append(readBuffer, 0, charsRead);
          charsRead = reader.read(readBuffer);
        }
        code = buf.toString();
      } catch (FileNotFoundException ex) {
        Logger.getLogger(FileMgr.class.getName()).log(Level.SEVERE, null, ex);
      } catch (IOException ex) {
        Logger.getLogger(FileMgr.class.getName()).log(Level.SEVERE, null, ex);
      } finally {
        try {
          reader.close();
        } catch (IOException ex) {
          Logger.getLogger(FileMgr.class.getName()).log(Level.SEVERE, null, ex);
        }
      }
    }
    return code;
  }
  public String renameFile(String relPath, String fname, String newName) {
    File targetDir = getTargetDir(relPath);
    File file = new File(targetDir, fname);
    file.renameTo(new File(targetDir, newName));
    return fname + " umbenannt zu " + newName;
  }
  public String deleteFiles(String relPath, List fileNames) {
    String result = null;
    try {
      FileRef datenRef = getBase();
      File daten = new File(datenRef.getAbsolutePath());
      Object p = getRequest().getUserPrincipal();
      if(p instanceof Principal) {
        File userDir = new File(daten, "www/" + ((Principal) p).getName());
        File saveDir = new File(userDir, relPath);
        File targetFile = new File(saveDir, fileName);
        if(!targetFile.exists()) {
          targetFile.getParentFile().mkdirs();
          targetFile.createNewFile();
          FileWriter w = new FileWriter(targetFile);
          w.write(contents);
          w.flush();
          w.close();
          savedFile = new FileRef(targetFile.getAbsolutePath(), targetFile.isDirectory(), targetFile.isHidden(), targetFile.lastModified(), targetFile.length());
      logger.fine(fileNames.toString());
      File targetDir = getTargetDir(relPath);
      for(int i=0; i < fileNames.size(); i++) {
        Object o = fileNames.get(i);
        if(o instanceof ArrayList) {
          ArrayList al = (ArrayList) o;
          logger.fine(al.get(0).toString());
          File targetFile = new File(targetDir, al.get(0).toString());
          logger.fine(targetFile.getAbsolutePath());
          if(targetFile.isDirectory()) {
            FileUtils.deleteDirectory(targetFile);
          } else {
            targetFile.delete();
          }
        }
      }
      result = "deleted";
    } catch (Throwable ex) {
      logger.log(Level.SEVERE, ex.getLocalizedMessage(), ex);
    }
    return result;
  }
  public String copyFiles(String fromPath, String toPath, List fileNames) {
    return copyOrMoveFiles(fromPath, toPath, fileNames, OP_COPY);
  }
  public String moveFiles(String fromPath, String toPath, List fileNames) {
    return copyOrMoveFiles(fromPath, toPath, fileNames, OP_MOVE);
  }
  private String copyOrMoveFiles(String fromPath, String toPath, List fileNames, int operation) {
    String result = null;
    try {
      File srcDir = getTargetDir(fromPath);
      File targetDir = getTargetDir(toPath);
      Iterator i = fileNames.iterator();
      while(i.hasNext()) {
        Object o = i.next();
        if (o instanceof ArrayList) {
          ArrayList al = (ArrayList) o;
          File srcFile = new File(srcDir, al.get(0).toString());
          if(srcFile.isDirectory()) {
            if(operation == OP_MOVE) {
              FileUtils.moveDirectoryToDirectory(srcFile, targetDir, false);
            } else {
              FileUtils.copyDirectoryToDirectory(srcFile, targetDir);
            }
          } else {
            if(operation == OP_MOVE) {
              FileUtils.moveFileToDirectory(srcFile, targetDir, false);
            } else {
              FileUtils.copyFileToDirectory(srcFile, targetDir);
            }
          }
        }
      }
    } catch (IOException ex) {
      logger.log(Level.SEVERE, null, ex);
      logger.log(Level.SEVERE, ex.getLocalizedMessage(), ex);
    }
    return result;
  }
  public FileRef saveTextFileAs(String relPath, String fileName, String contents) {
    FileRef savedFile = null;
    logger.fine(relPath + " " + fileName);
    //FileRef datenRef = getBase();
    Object p = getRequest().getUserPrincipal();
    if(p instanceof Principal) {
      File targetFile = new File(getTargetDir(relPath), fileName);
      if(targetFile.exists()) {
        targetFile = getNewFileName(targetFile);
      } else {
        targetFile.getParentFile().mkdirs();
      }
      saveToFile(targetFile, contents);
    }
    return savedFile;
  }
  
  private File getWebappsDir() {
    File cfile = new File(this.getClass().getResource(this.getClass().getSimpleName() + ".class").getFile());
    String path = cfile.getAbsolutePath();
    return new File(path.substring(0, path.indexOf(req.getContextPath())));
  }
  @Override
  public ServletContext getServletContext() {
    return ctx;
  }
  @Override
  public void setServletContext(ServletContext servletContext) {
    this.ctx = servletContext;
  }
  @Override
  public HttpServletRequest getRequest() {
    return req;
  }
  @Override
  public void setRequest(HttpServletRequest r) {
    this.req = r;
  }
  private File getNewFileName(File file) {
    File dir = file.getParentFile();
    String targetName = file.getName();
    logger.fine("targetName: " + targetName);
    String ext = "";
    int dotpos = targetName.indexOf(".");
    if(dotpos > -1) {
      ext = targetName.substring(dotpos);
      targetName = targetName.substring(0, dotpos);
    }
    logger.fine("targetName: " + targetName + ", ext: " + ext);
    int i = 1;
    while(file.exists()) {
      StringBuffer buf = new StringBuffer();
      buf.append(targetName);
      buf.append("-");
      buf.append(i);
      if(ext.length() > 0) {
        buf.append(ext);
      }
      file = new File(dir, buf.toString());
      i++;
    }
    logger.fine("new file: " + file.getName());
    return file;
  }
  
}
  private FileRef saveToFile(File targetFile, String contents) {
    FileRef savedFile = null;
    try {
      targetFile.createNewFile();
      FileWriter w = new FileWriter(targetFile);
      //w.write(StringEscapeUtils.unescapeHtml(contents));
      w.write(contents);
      w.flush();
      w.close();
      savedFile = new FileRef(
              targetFile.getAbsolutePath(),
              targetFile.isDirectory(),
              targetFile.isHidden(),
              targetFile.lastModified(),
              targetFile.length());
    } catch (IOException ex) {
      logger.log(Level.SEVERE, ex.getLocalizedMessage(), ex);
    }
    return savedFile;
  }
  public FileRef saveTextFile(String relPath, String fileName, String contents) {
    FileRef savedFile = null;
    logger.fine(relPath + " " + fileName);
    //FileRef datenRef = getBase();
    Object p = getRequest().getUserPrincipal();
    if(p instanceof Principal) {
      File targetFile = new File(getTargetDir(relPath), fileName);
      if(targetFile.exists()) {
        /*
          muss delete() sein?
          pruefen: ueberschreibt der FileWriter den alteen Inhalt oder
          entsteht eine unerwuenschte Mischung aus altem und neuem
          Inhalt?
        */
        targetFile.delete();
      } else {
        targetFile.getParentFile().mkdirs();
      }
      saveToFile(targetFile, contents);
    }
    return savedFile;
  }
  public String bildVerkleinern(String relPath, String bildName) {
    File dir = getTargetDir(relPath);
    File original = new File(dir, bildName);
    Bild bild = new Bild();
    //for (int i = 0; i < Bild.GR.length; i++) {
      //int gr = bild.getVariantenGroesse(i);
      String ext = "";
      String nurname = bildName;
      int dotpos = bildName.indexOf(".");
      if (dotpos > -1) {
        ext = bildName.substring(dotpos);
        nurname = bildName.substring(0, dotpos);
      }
      Image image = Toolkit.getDefaultToolkit().getImage(original.getAbsolutePath());
      MediaTracker mediaTracker = new MediaTracker(new Container());
      mediaTracker.addImage(image, 0);
      try {
        mediaTracker.waitForID(0);
        if(!mediaTracker.isErrorAny()) {
          for(int i = 0; i < Bild.GR.length; i++) {
            StringBuffer buf = new StringBuffer();
            buf.append(nurname);
            buf.append(bild.getVariantenName(i));
            buf.append(ext);
            File newImgFile = new File(dir, buf.toString());
            if(!newImgFile.exists()) {
              logger.fine(original.getAbsolutePath() + " " + newImgFile.getAbsolutePath());
              bild.writeImageFile(image, bild.getVariantenGroesse(i), bild.getMimeType(original), original.getAbsolutePath(), newImgFile.getAbsolutePath());
              //bild.writeImageFile(image, photo.getVariantenGroesse(i), photo.getMimetype(), photo.getAbsolutePath(basisPfad), photo.getVariantenName(basisPfad, i));
            }
          }
        }
      } catch(IOException | InterruptedException ex) {
        logger.log(Level.SEVERE, ex.getLocalizedMessage(), ex);
      }
    return "ok";
  }
  /* ---- Hilfsfunktionen ---- */
  private File getTargetDir(String relPath) {
    logger.fine(relPath);
    String targetPath = null;
    if(relPath.startsWith(PUB_DIR_NAME)) {
      targetPath = PUB_DIR_PATH + getUserName() + relPath.substring(PUB_DIR_NAME.length());
    } else if(relPath.startsWith(HOME_DIR_NAME)) {
      targetPath = HOME_DIR_PATH + getUserName() + relPath.substring(HOME_DIR_NAME.length());
    } else {
      // kann eigentlich nicht sein..
    }
    logger.fine(targetPath);
    File targetDir = new File(getBase().getAbsolutePath(), targetPath);
    return targetDir;
  }
  private FileRef getBase() {
    FileRef base = null;
    Object o = getServletContext().getAttribute(Initialiser.FILE_BASE);
    if(o instanceof String) {
      String baseStr = (String) o;
      logger.fine(baseStr);
      File file = new File(baseStr);
      base = new FileRef(file.getAbsolutePath(), file.isDirectory());
    }
    return base;
  }
  private String getUserName() {
    String userName = null;
    Object p = getRequest().getUserPrincipal();
    if(p instanceof Principal) {
      userName = ((Principal) p).getName();
    }
    return userName;
  }
}