Dateien verwalten mit Modul jdk.httpserver
ulrich
2021-07-07 66173fabcb016cb9918e937d88b926a4c21646b7
commit | author | age
7fdd7e 1 /*
U 2   http-cm - File management extensions to jdk.httpserver
3   Copyright (C) 2021  Ulrich Hilger
4
5   This program is free software: you can redistribute it and/or modify
6   it under the terms of the GNU Affero General Public License as
7   published by the Free Software Foundation, either version 3 of the
8   License, or (at your option) any later version.
9
10   This program is distributed in the hope that it will be useful,
11   but WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   GNU Affero General Public License for more details.
14
15   You should have received a copy of the GNU Affero General Public License
16   along with this program.  If not, see <https://www.gnu.org/licenses/>.
17  */
18 package de.uhilger.httpserver.cm;
19
20 import com.google.gson.Gson;
21 import com.sun.net.httpserver.Authenticator;
22 import com.sun.net.httpserver.Headers;
23 import com.sun.net.httpserver.HttpExchange;
24 import de.uhilger.httpserver.base.HttpResponder;
25 import de.uhilger.httpserver.base.HttpHelper;
26 import de.uhilger.httpserver.base.handler.FileHandler;
27 import de.uhilger.httpserver.image.Datei;
28 import de.uhilger.httpserver.image.ImageActor;
29 import de.uhilger.httpserver.image.ImageThread;
30 import de.uhilger.httpserver.image.ImageThread.ThreadListener;
31 import de.uhilger.httpserver.oauth.BearerAuthenticator;
32 import java.io.BufferedReader;
33 import java.io.File;
34 import java.io.FileInputStream;
35 import java.io.FileOutputStream;
36 import java.io.IOException;
37 import java.io.InputStream;
38 import java.io.InputStreamReader;
39 import java.io.OutputStream;
40 import java.net.URLDecoder;
41 import java.nio.file.DirectoryStream;
42 import java.nio.file.Files;
43 import java.nio.file.Path;
44 import java.util.ArrayList;
45 import java.util.Arrays;
46 import java.util.Enumeration;
47 import java.util.List;
48 import java.util.logging.Logger;
49 import java.util.logging.Level;
50 import java.util.zip.Adler32;
51 import java.util.zip.CheckedOutputStream;
52 import java.util.zip.ZipEntry;
53 import java.util.zip.ZipFile;
54 import java.util.zip.ZipOutputStream;
55
56 /**
57  * <p>Der FileManager verknuepft einen HTTP-Endpunkt mit einem Ordner des lokalen
58  * Dateisystems.</p>
59  *
60  * <p>HTTP GET fuer eine Datei innerhalb dieses Ordners liefert den Dateiinhalt aus</p>
61  *
62  * <p>HTTP GET fuer einen Ordner liefert eine Liste von dessen Inhalt in JSON</p>
63  *
64  * <p>HTTP PUT fuer eine Datei ueberschreibt eine bestehende Datei mit dem im Body
65  * uebergebenen Inhalt oder legt eine Datei mit diesem Inhalt an</p>
66  *
67  * <p>HTTP POST fuer eine Datei legt eine neue Datei mit dem im Body uebergebenen
68  * Inhalt an oder erzeugt eine neue Datei mit einer laufenden Nummer, falls
69  * diese Datei schon existiert</p>
70  *
71  * <p>HTTP POST fuer einen Ordner legt einen neuen Ordner an wenn er noch nicht
72  * existiert oder erzeugt einen HTTP-Fehler 422</p>
73  *
74  * <p>HTTP DELETE loescht die Liste der Dateien und Ordner im Body</p>
75  *
76  * <p>HTTP PUT ?copyFrom=pfad kopiert die Liste der Datei- oder Ordnernamen im Body
77  * der Anfrage vom Pfad in 'copyFrom' zum Pfad dieser Anfrage. Jede Datei, die
78  * im Ziel bereits existiert, bekommt im Ziel einen neuen Namen mit einer
79  * laufenden Nummer. Bei Ordnern, die im Ziel bereits existieren, bekommt der
80  * betreffende Ordner im Ziel zunaechst einen neuen Namen mit einer laufenden
81  * Nummer, dann wird der Quellordner ans Ziel kopiert.</p>
82  *
83  * <p>HTTP PUT ?moveFrom=pfad verschiebt die Liste der Datei- oder Ordnernamen im
84  * Body der Anfrage vom Pfad in 'moveFrom' zum Pfad dieser Anfrage. Jede Datei,
85  * die im Ziel bereits existiert, bekommt im Ziel einen neuen Namen mit einer
86  * laufenden Nummer. Bei Ordnern, die im Ziel bereits existieren, bekommt der
87  * betreffende Ordner im Ziel zunaechst einen neuen Namen mit einer laufenden
88  * Nummer, dann wird der Quellordner ans Ziel kopiert.</p>
89  *
90  * <p>HTTP PUT mit ?duplicate legt eine Kopie der Datei an</p>
91  *
92  * <p>HTTP PUT mit '?renameTo=neuer Name' benennt die Datei oder den Ordner um,
93  * sofern der neue Name noch nicht vergeben ist</p>
94  *
95  * <p>HTTP PUT mit '?zip' packt den Ordner</p>
96  *
97  * <p>HTTP PUT mit '?unzip' entpackt eine Datei</p>
98  * 
99  * <p>Namenskonventionen:<br>
100  * Ein Pfad mit Schraegstrich ('/') am Ende bezeichnet einen Ordner<br>
101  * Ein Pfad ohne Schraegstrich ('/') am Ende bezeichnet eine Datei</p>
102  *
103  * @author Ulrich Hilger
104  * @version 1, 13. Mai 2021
105  */
106 public class FileManager extends FileHandler implements ThreadListener {
107
108   /* Der Logger fuer diesen ListFileHandler */
109   private static final Logger logger = Logger.getLogger(FileManager.class.getName());
110
111   /*
112   private static final String[] specialChars = {new String("\u00c4"), new String("\u00d6"),
113     new String("\u00dc"), new String("\u00e4"), new String("\u00f6"), new String("\u00fc"), new String("\u00df")};
114   */
115   
116   //public static final String UNWANTED_PATTERN = "[^a-zA-Z_0-9 ]";
117   /* HTTP Methoden */
118
119   public static final String UTF8 = "UTF-8";
120
121   public static final String STR_SLASH = "/";
122   public static final String STR_DOT = ".";
123   
124   public static final String P_COPY = "copyFrom";
125   public static final String P_MOVE = "moveFrom";
126   public static final String P_DUPLICATE = "duplicate";
127   public static final String P_RENAME = "renameTo";
128   public static final String P_ZIP = "zip";
129   public static final String P_UNZIP = "unzip";
130
131   public static final int OP_COPY = 1;
132   public static final int OP_MOVE = 2;
133   public static final int OP_DELETE = 3;
134   
135   public static final String ATTR_ROLE = "role";
136   
137   private final List waitingThreads;
138   private final int maxThreads;
139   private int threadCount;
140   //private String role;
141
142   //public FileManager(String absoluteDirectoryPathAndName, String role, String ctx) {
143   public FileManager() {
144     //super(absoluteDirectoryPathAndName, ctx);
145     //super(absoluteDirectoryPathAndName);
146     waitingThreads = new ArrayList();
147     maxThreads = 4;
148     threadCount = 0;
149     //this.role = role;
150   }
151
152   @Override
153   public void handle(HttpExchange e) throws IOException {
154     Authenticator a = e.getHttpContext().getAuthenticator();
155     if(a instanceof BearerAuthenticator) {
156       BearerAuthenticator auth = (BearerAuthenticator) a;
157       //Realm realm = auth.getRealm();
158       String userId = e.getPrincipal().getUsername();
159       if(auth.hasRole(userId, e.getHttpContext().getAttributes().get(ATTR_ROLE).toString())) {
160         String method = e.getRequestMethod();
161         logger.fine("method: " + method);
162         HttpHelper helper = new HttpHelper();
163         switch (method) {
164           case HttpHelper.HTTP_GET:
165             liste(e, helper);
166             break;
167           case HttpHelper.HTTP_PUT:
168             put(e, helper);
169             break;
170           case HttpHelper.HTTP_POST:
171             speichern(e, helper);
172             break;
173           case HttpHelper.HTTP_DELETE:
174             loeschen(e, helper);
175             break;
176         }
177       } else {
178         standardHeaderUndAntwort(e, SC_FORBIDDEN, "Fehlende Rolle.");
179       }
180     } else {
181       standardHeaderUndAntwort(e, SC_FORBIDDEN, "Fehlende Rolle.");
182     }
183   }
184
185   private void put(HttpExchange exchange, HttpHelper helper) throws IOException {
186     String query = exchange.getRequestURI().getQuery();
187     if (query != null) {
188       String[] params = query.split("=");
189       for (String param : params) {
190         logger.fine("param: " + param);
191       }
192       switch (params[0]) {
193         case P_COPY:
194           copyOrMove(exchange, params[1], helper.getFileName(exchange), OP_COPY);
195           break;
196         case P_MOVE:
197           copyOrMove(exchange, params[1], helper.getFileName(exchange), OP_MOVE);
198           break;
199         case P_DUPLICATE:
200           if(Boolean.parseBoolean(params[1])) {
201             String neuerDateiName = duplizieren(exchange, helper);
202             logger.fine("neuer Name: " + neuerDateiName);
203             standardHeaderUndAntwort(exchange, SC_OK, neuerDateiName);
204           }
205           break;
206         case P_RENAME:
207           String neuerDateiName = umbenennen(exchange, helper, params[1]);
208           logger.fine("neuer Name: " + neuerDateiName);
209           standardHeaderUndAntwort(exchange, SC_OK, neuerDateiName);
210           break;
211         case P_ZIP:
212           String path = exchange.getRequestURI().toString();
213           logger.fine(path);
214           String antwort = packFolder(helper.getFileName(exchange), path, exchange);
215           if(antwort.equalsIgnoreCase("ok")) {
216             standardHeaderUndAntwort(exchange, SC_OK, antwort);
217           } else {
218             standardHeaderUndAntwort(exchange, SC_UNPROCESSABLE_ENTITY, antwort);
219           }
220           break;
221         case P_UNZIP:
222           path = exchange.getRequestURI().toString();
223           logger.fine(path);
224           antwort = extractZipfile(helper.getFileName(exchange), path, exchange);
225           if(antwort.equalsIgnoreCase("ok")) {
226             standardHeaderUndAntwort(exchange, SC_OK, antwort);
227           } else {
228             standardHeaderUndAntwort(exchange, SC_UNPROCESSABLE_ENTITY, antwort);
229           }
230           break;
231       }
232     } else {
233       speichern(exchange, helper);
234     }
235   }
66173f 236   
U 237   public class DirList {
238     private String pfad;
239     private List<Datei> dateien;
240
241     public String getPfad() {
242       return pfad;
243     }
244
245     public void setPfad(String pfad) {
246       this.pfad = pfad;
247     }
248
249     public List<Datei> getDateien() {
250       return dateien;
251     }
252
253     public void setDateien(List<Datei> dateien) {
254       this.dateien = dateien;
255     }
256     
257     
258   }
7fdd7e 259
U 260   private void liste(HttpExchange e, HttpHelper helper) throws IOException {
261     String path = e.getRequestURI().toString();
262     logger.fine(path);
263     String fName = helper.getFileName(e);
66173f 264     String dirListPath = e.getHttpContext().getPath() + fName;
7fdd7e 265     if (path.endsWith(STR_SLASH)) {      
U 266       logger.fine("fName: " + fName);
267       File dir = new File(e.getHttpContext().getAttributes().get(FileHandler.ATTR_FILE_BASE).toString(), fName);
268       logger.fine("absPath: " + dir.getAbsolutePath());
269       File[] files = dir.listFiles(new ImageFileFilter());
270       if(files != null && files.length > 0) {
271         Arrays.sort(files);
272         ArrayList liste = new ArrayList();
273         for (File file : files) {
274           Datei datei = new Datei();
275           String dateiName = file.getName();
276           datei.setName(dateiName);
277           if (file.isDirectory()) {
278             datei.setTyp(Datei.TYP_ORDNER);
279           } else {
280             datei.setTyp(Datei.TYP_DATEI);
281           }
66173f 282           //datei.setPfad(e.getHttpContext().getPath() + fName);
7fdd7e 283           String lowerName = dateiName.toLowerCase();
U 284           if (lowerName.endsWith(ImageActor.JPEG)
285                   || lowerName.endsWith(ImageActor.JPG)
286                   || lowerName.endsWith(ImageActor.PNG)) {
287             datei.setBild(true);
288             String ext = dateiName.substring(dateiName.lastIndexOf(STR_DOT));
289             String ohneExt = dateiName.substring(0, dateiName.lastIndexOf(STR_DOT));
290             datei.setMiniurl(ohneExt + ImageActor.TN + ext);
291             buildImgSrc(file, datei, ohneExt, ext);
292           }
293           liste.add(datei);
294         }
295         while(threadCount > 0) {
296           try {
297             Thread.sleep(50);
298           } catch (InterruptedException ex) {
299             Logger.getLogger(FileManager.class.getName()).log(Level.SEVERE, null, ex);
300           }
301         }
302         if(liste.size() > 0) {
66173f 303           DirList list = new DirList();
U 304           list.setPfad(dirListPath);
305           list.setDateien(liste);
7fdd7e 306           Gson gson = new Gson();
66173f 307           //String json = gson.toJson(liste);
U 308           String json = gson.toJson(list);
7fdd7e 309           //byte[] bytes = json.getBytes();
U 310           //logger.fine("json: '" + json + "'");
311           HttpResponder r = new HttpResponder();
312           r.antwortSenden(e, SC_OK, json);
313         } else {
314           emptyListResponse(e);      
315         }
316       } else {
317         emptyListResponse(e);      
318       }
319     } else {
320       String lowerName = fName.toLowerCase();
321       if(lowerName.contains(ImageActor.B64)) {
322         ImageActor actor = new ImageActor();
323         String fromName = fName.replace(ImageActor.B64, "");
324         File fromFile = new File(e.getHttpContext().getAttributes().get(FileHandler.ATTR_FILE_BASE).toString(), fromName);
325         File toFile = new File(e.getHttpContext().getAttributes().get(FileHandler.ATTR_FILE_BASE).toString(), fName);
326         logger.fine("from " + fromFile.getAbsolutePath() + ", to " + toFile.getAbsolutePath());
327         if(!toFile.exists()) {
328           actor.b64Image(fromFile, toFile);
329         }
330         super.handle(e);
331       } else {
332         super.handle(e);
333       }
334     }
335   }
336   
337   //  data:[<mime type>][;charset=<Zeichensatz>][;base64],<Daten>
338   /*
339   [So. Juni 13 13:23:32 MESZ 2021] FEIN: 
340   file: /home/ulrich/helix-files/bild-test/10419903-14-2-1920-r.jpg, 
341   relname: bild-test/10419903-14-2-1920-r.jpg, ohneExt: 10419903-14-2-1920-r, ext: .jpg (de.uhilger.helix.FileManager buildImgSrc)
342
343   */
344   private void buildImgSrc(File file, Datei datei, String ohneExt, String ext) throws IOException {
345     //logger.fine("file: " + file.getAbsolutePath() + ", ohneExt: " + ohneExt + ", ext: " + ext);
346     File dir = file.getParentFile();
347     String newRelName = ohneExt + ImageActor.TN + ImageActor.B64 + ext;
348     File b64File = new File(dir, newRelName);
349     //logger.fine("b64File: " + b64File.getAbsolutePath());
350     if(!b64File.exists()) {
351       //BildErzeuger be = new BildErzeuger();
352       //be.bildErzeugen(dir, newRelName, BildErzeuger.TN, 120, b64File);
353       ImageThread it = new ImageThread(dir, newRelName, ImageActor.TN, 120, b64File, datei, ext);
354       it.addListener(this);
355       if(threadCount < maxThreads) {
356         ++threadCount;
357         //logger.fine("Thread started, threadCount: " + threadCount);
358         it.start();
359       } else {
360         waitingThreads.add(it);
361         //logger.fine("Thread added to wait queue.");
362       }
363     } else {
364       ImageActor be = new ImageActor();
365       be.setImgSrc(datei, ext, b64File);
366     }
367   }
368   
369   @Override
370   public void finished() {
371     --threadCount;
372     //logger.fine("Thread finished, threadCound now: " + threadCount);
373     if (threadCount < maxThreads) {
374       if (waitingThreads.size() > 0) {
375         Object o = waitingThreads.get(0);
376         if (o instanceof ImageThread) {
377           waitingThreads.remove(o);
378           ImageThread it = (ImageThread) o;
379           ++threadCount;
380           //logger.fine("Thread started from wait queue, threadCount now: " + threadCount);
381           it.start();
382         }
383       }
384     }
385   }  
386   
387   private void emptyListResponse(HttpExchange e) throws IOException {
388     HttpResponder r = new HttpResponder();
389     String json = "{}";
390     logger.log(Level.FINE, "json: ''{0}''", json);
391     r.antwortSenden(e, SC_OK, json);        
392   }
393
394   private void speichern(HttpExchange exchange, HttpHelper helper) throws IOException {
395     String fileName = helper.getFileName(exchange);
396     logger.info("fileName: " + fileName);
397
398     // file ist die Datei, um die es geht
399     File file = new File(exchange.getHttpContext().getAttributes().get(FileHandler.ATTR_FILE_BASE).toString(), fileName);
400
401     String method = exchange.getRequestMethod();
402     if (fileName.endsWith(STR_SLASH)) {
403       logger.info("neuer Ordner: " + file.getAbsolutePath());
404       // neuen Ordner erstellen oder ablehnen, wenn der Ordner schon existiert
405       if (method.equalsIgnoreCase(HttpHelper.HTTP_POST)) {
406         if (!file.exists()) {
407           file.mkdir();
408           standardHeaderUndAntwort(exchange, SC_OK, file.getAbsolutePath());
409         } else {
410           String antwort = "Ordner existiert bereits.";
411           standardHeaderUndAntwort(exchange, SC_UNPROCESSABLE_ENTITY, antwort);
412         }
413       } else {
414         String antwort = "PUT fuer neuen Ordner nicht erlaubt, bitte POST verwenden.";
415         standardHeaderUndAntwort(exchange, SC_METHOD_NOT_ALLOWED, antwort);        
416       }
417     } else {
418       logger.info("Datei speichern: " + file.getAbsolutePath());
419       // Datei speichern
420       if (method.equalsIgnoreCase(HttpHelper.HTTP_POST)) {
421         if (file.exists()) {
422           FileTransporter trans = new FileTransporter();
423           file = trans.getNewFileName(file);
424         }
425       } else if (method.equalsIgnoreCase(HttpHelper.HTTP_PUT)) {
426         if (file.exists()) {
427           /*
428             muss delete() sein?
429             pruefen: ueberschreibt der FileWriter den alteen Inhalt oder 
430             entsteht eine unerwuenschte Mischung aus altem und neuem 
431             Inhalt?
432            */
433           file.delete();
434         } else {
435           file.getParentFile().mkdirs();
436         }
437       }
438       // Request Body mit dem Dateiinhalt in einen String lesen
439       StringBuilder sb = new StringBuilder();
440       InputStream is = exchange.getRequestBody();
441       BufferedReader in = new BufferedReader(new InputStreamReader(is));
442       String line = in.readLine();
443       while (line != null) {
444         sb.append(line);
445         line = in.readLine();
446       }
447
448       // dekodieren
449       String content = sb.toString();
450       logger.fine(content);
451       String decoded = URLDecoder.decode(content, UTF8);
452       logger.fine(decoded);
453
454       // in Datei schreiben
455       byte[] bytes = decoded.getBytes();
456       file.createNewFile();
457       OutputStream os = new FileOutputStream(file);
458       os.write(bytes);
459       os.flush();
460       os.close();
461       is.close();
462
463       // Antwort senden
464       standardHeaderUndAntwort(exchange, SC_OK, file.getAbsolutePath());
465     }
466   }
467
468   private void copyOrMove(HttpExchange exchange, String quelle, String ziel, int op) throws IOException {
469     logger.fine("quelle: " + quelle + ", ziel: " + ziel);
470     String[] dateiNamen = dateiliste(exchange);
471     copyOrMoveFiles(quelle, ziel, dateiNamen, op, exchange);
472     standardHeaderUndAntwort(exchange, SC_OK, "Dateien verarbeitet.");
473   }
474
475   private String copyOrMoveFiles(String fromPath, String toPath, String[] fileNames, int operation, HttpExchange e) throws IOException {
476     String result = null;
477     File srcDir = new File(e.getHttpContext().getAttributes().get(FileHandler.ATTR_FILE_BASE).toString(), fromPath);
478     File targetDir = new File(e.getHttpContext().getAttributes().get(FileHandler.ATTR_FILE_BASE).toString(), toPath);
479     for (String fileName : fileNames) {
480       File srcFile = new File(srcDir, fileName);
481       logger.fine("srcFile: " + srcFile);
482       if (srcFile.isDirectory()) {
483         logger.fine("srcFile is directory.");
484         OrdnerBearbeiter bearbeiter = new OrdnerBearbeiter();
485         bearbeiter.setTargetDir(targetDir.toPath());
486         bearbeiter.setOperation(operation);
487         Files.walkFileTree(srcFile.toPath(), bearbeiter);
488       } else {
489         Path source = srcFile.toPath();
490         File destFile = targetDir.toPath().resolve(source.getFileName()).toFile();
491         if (destFile.exists()) {
492           FileTransporter trans = new FileTransporter();
493           destFile = trans.getNewFileName(destFile);
494         }
495         if (operation == OP_MOVE) {
496           String fname = srcFile.getName().toLowerCase();
497           if (fname.endsWith(ImageActor.JPEG)
498                   || fname.endsWith(ImageActor.JPG)
499                   || fname.endsWith(ImageActor.PNG)) {
500             moveImgFilesToDirectory(srcFile, srcDir, targetDir, false);
501           } else {
502             Files.move(source, destFile.toPath());
503           }
504         } else {
505           Files.copy(source, destFile.toPath());
506         }
507       }
508     }
509     return result;
510   }
511
512   private void loeschen(HttpExchange exchange, HttpHelper helper) throws IOException {
513     String[] dateiNamen = dateiliste(exchange);
514     String relPfad = helper.getFileName(exchange);
515     deleteFiles(relPfad, Arrays.asList(dateiNamen), exchange);
516     standardHeaderUndAntwort(exchange, SC_OK, "Dateien geloescht.");
517   }
518
519   private String[] dateiliste(HttpExchange exchange) throws IOException {
520     String body = new HttpHelper().bodyLesen(exchange);
521     logger.fine("dateien: " + body);
522     Gson gson = new Gson();
523     return gson.fromJson(body, String[].class);
524   }
525
526   public String duplizieren(HttpExchange exchange, HttpHelper helper) throws IOException {
527     String relPfad = helper.getFileName(exchange);
528     File srcFile = new File(exchange.getHttpContext().getAttributes().get(FileHandler.ATTR_FILE_BASE).toString(), relPfad);
529     String fnameext = srcFile.getName();
530     int dotpos = fnameext.lastIndexOf(STR_DOT);
531     String fname = fnameext.substring(0, dotpos);
532     String ext = fnameext.substring(dotpos);
533     File srcDir = srcFile.getParentFile();
534     File destFile = new File(srcDir, fname + "-Kopie" + ext);
535     int i = 1;
536     while (destFile.exists()) {
537       destFile = new File(srcDir, fname + "-Kopie-" + Integer.toString(++i) + ext);
538     }
539     Files.copy(srcFile.toPath(), destFile.toPath());
540     return destFile.getName();
541   }
542
543   public String umbenennen(HttpExchange exchange, HttpHelper helper, String neuerName) throws IOException {
544     File neueDatei;
545     String relPfad = helper.getFileName(exchange);
546     File file = new File(exchange.getHttpContext().getAttributes().get(FileHandler.ATTR_FILE_BASE).toString(), relPfad);
547     String fname = file.getName().toLowerCase();
548     if(fname.endsWith(ImageActor.JPEG) || fname.endsWith(ImageActor.JPG) || fname.endsWith(ImageActor.PNG)) {
549       neueDatei = renameImgFiles(file.getParentFile(), file, neuerName);  
550     } else {
551       neueDatei = new File(file.getParentFile(), neuerName);
552       file.renameTo(neueDatei);
553     }
554     return neueDatei.getName();
555   }
556   
557   public File renameImgFiles(File targetDir, File targetFile, String newName) throws IOException {
558     String alt;
559     String neu;
560     File neueDatei = targetFile;
561     
562     int newdotpos = newName.lastIndexOf(STR_DOT);
563     String newfname = newName.substring(0, newdotpos);
564     String newext = newName.substring(newdotpos);
565     logger.fine("newfname: " + newfname + ", newext: " + newext);
566     
567     String fnameext = targetFile.getName();
568     int dotpos = fnameext.lastIndexOf(STR_DOT);
569     String fname = fnameext.substring(0, dotpos);
570     String ext = fnameext.substring(dotpos);
571     logger.fine("fname: " + fname + ", ext: " + ext);
572     
573     DirectoryStream<Path> stream = Files.newDirectoryStream(targetDir.toPath(), fname + "*" + ext); //"*.{txt,doc,pdf,ppt}"
574     for (Path path : stream) {
575       logger.fine(path.getFileName().toString());
576       alt = path.getFileName().toString();
577       logger.fine("alt: " + alt);
578       if(alt.contains(ImageActor.TN)) {
579         neu = newfname + ImageActor.TN + newext;
580       } else if (alt.contains(ImageActor.KL)) {
581         neu = newfname + ImageActor.KL + newext;
582       } else if(alt.contains(ImageActor.GR)) {
583         neu = newfname + ImageActor.GR + newext;
584       } else if(alt.contains(ImageActor.MT)) {
585         neu = newfname + ImageActor.MT + newext;
586       } else if(alt.contains(ImageActor.SM)) {
587         neu = newfname + ImageActor.SM + newext;
588       } else {
589         neu = newName;
590       }
591       neueDatei = new File(targetDir, neu);
592       path.toFile().renameTo(neueDatei);              
593     }
594     stream.close();
595     return neueDatei;
596   }
597   
598   
599   private String deleteFiles(String relPath, List<String> fileNames, HttpExchange e) {
600     String result = null;
601     try {
602       logger.fine(fileNames.toString());
603       if (!relPath.startsWith(STR_DOT)) {
604         File targetDir = new File(e.getHttpContext().getAttributes().get(FileHandler.ATTR_FILE_BASE).toString(), relPath); // getTargetDir(relPath);
605         logger.fine("targetDir: " + targetDir);
606         for (String fileName : fileNames) {
607           File targetFile = new File(targetDir, fileName);
608           logger.fine(targetFile.getAbsolutePath());
609           if (targetFile.isDirectory()) {
610             OrdnerBearbeiter bearbeiter = new OrdnerBearbeiter();
611             bearbeiter.setOperation(OP_DELETE);
612             Files.walkFileTree(targetFile.toPath(), bearbeiter);
613           } else {
614             /*
615                 Wenn targetFile mit jpg, jpeg oder png endet, 
616                 muss eine Unterfunktion eine Liste aller Dateien bilden, 
617                 die so heissen, also z.B. alle [Dateiname]*.jpg
618              */
619             String fname = targetFile.getName().toLowerCase();
620             if (fname.endsWith(ImageActor.JPEG)
621                     || fname.endsWith(ImageActor.JPG)
622                     || fname.endsWith(ImageActor.PNG)) {
623               deleteImgFiles(targetDir, targetFile);
624             } else {
625               targetFile.delete();
626             }
627           }
628         }
629         result = "deleted";
630       }
631     } catch (Throwable ex) {
632       logger.log(Level.SEVERE, ex.getLocalizedMessage(), ex);
633     }
634     return result;
635   }
636
637   private void deleteImgFiles(File targetDir, File targetFile) throws IOException {
638     String fnameext = targetFile.getName();
639     int dotpos = fnameext.lastIndexOf(STR_DOT);
640     String fname = fnameext.substring(0, dotpos);
641     String ext = fnameext.substring(dotpos);
642     logger.fine("fname: " + fname + ", ext: " + ext);
643     DirectoryStream<Path> stream = Files.newDirectoryStream(targetDir.toPath(), fname + "*" + ext); //"*.{txt,doc,pdf,ppt}"
644     for (Path path : stream) {
645       logger.fine(path.getFileName().toString());
646       Files.delete(path);
647     }
648     stream.close();
649   }
650
651   private void moveImgFilesToDirectory(File srcFile, File srcDir, File targetDir, boolean createDestDir) throws IOException {
652     String fnameext = srcFile.getName();
653     int dotpos = fnameext.lastIndexOf(STR_DOT);
654     String fname = fnameext.substring(0, dotpos);
655     String ext = fnameext.substring(dotpos);
656     logger.fine("fname: " + fname + ", ext: " + ext);
657     Path targetPath = targetDir.toPath();
658     DirectoryStream<Path> stream = Files.newDirectoryStream(srcDir.toPath(), fname + "*" + ext); //"*.{txt,doc,pdf,ppt}"
659     for (Path path : stream) {
660       logger.fine(path.getFileName().toString());
661       //Files.delete(path);
662       Files.move(path, targetPath.resolve(path.getFileName()));
663     }
664     stream.close();
665   }
666   
667   private void standardHeaderUndAntwort(HttpExchange exchange, int status, String antwort) throws IOException {
668     Headers resHeaders = exchange.getResponseHeaders();
669     resHeaders.add(CONTENT_TYPE, HttpHelper.CT_TEXT_HTML);
670     new HttpResponder().antwortSenden(exchange, status, antwort);
671   }  
672   
673   /* --------- ZIP entpacken ---------------- */
674   
675   public String extractZipfile(String fName, String relPath, HttpExchange e) {  
676     logger.fine("fName: " + fName + ", relPath: " + relPath);
677     String result = null;
678     if (!relPath.startsWith(".")) {    
679       try {
680         //File targetDir = new File(fileBase, relPath);
681         //File targetDir = getTargetDir(relPath);
682         File archive = new File(e.getHttpContext().getAttributes().get(FileHandler.ATTR_FILE_BASE).toString(), fName);
683         if(extract(archive)) {
684           result = "ok";
685         } else {
686           result = "error while extracting";
687         }
688       } catch(Exception ex) {
689         result = ex.getLocalizedMessage();
690         logger.log(Level.SEVERE, ex.getLocalizedMessage(), ex);
691       }
692     } else {
693       result = "Falsche relative Pfadangabe.";
694     }
695     return result;
696   }
697   
698   /**
699      * extract a given ZIP archive to the folder respective archive resides in
700      * @param archive  the archive to extract
701      * @throws Exception
702      */
703     private boolean extract(File archive) throws Exception {
704         ZipFile zipfile = new ZipFile(archive);
705         Enumeration en = zipfile.entries();
706         while(en.hasMoreElements()) {
707             ZipEntry zipentry = (ZipEntry) en.nextElement();
708             unzip(zipfile, zipentry, archive.getParent());
709         }
710         zipfile.close();
711         return true;
712     }
713
714     /**
715      * unzip a given entry of a given zip file to a given location
716      * @param zipfile  the zip file to read an entry from
717      * @param zipentry  the zip entry to read
718      * @param destPath  the path to the destination location for the extracted content
719      * @throws IOException
720      */
721     private void unzip(ZipFile zipfile, ZipEntry zipentry, String destPath) throws IOException {
722         byte buf[] = new byte[1024];
723         InputStream is = zipfile.getInputStream(zipentry);
724         String outFileName = destPath + File.separator + zipentry.getName();
725         File file = new File(outFileName);
726         if(!zipentry.isDirectory()) {
727             file.getParentFile().mkdirs();
728             if(!file.exists())
729                 file.createNewFile();
730             FileOutputStream fos = new FileOutputStream(file);
731             int i = is.read(buf, 0, 1024);
732             while(i > -1) {
733                 fos.write(buf, 0, i);
734                 i = is.read(buf, 0, 1024);
735             }
736             fos.close();
737             is.close();
738         } else {
739             file.mkdirs();
740         }
741     }
742
743   /* --------------- Ordner packen ----------------- */
744
745   /**
746    * Einen Ordner packen.
747    * 
748    * Als Ziel wird eine neue Datei mit Dateiendung '.zip' erzeugt, die so 
749    * heisst wie der Ordner, der gapckt werden soll. Die Datei mit 
750    * dem gepackten Ordnerinhalt wird in dem Ordner angelegt, der den zu 
751    * packenden Ordner enthaelt.
752    * 
753    * @param fName  Name des zu packenden Ordners
754    * @param relPath  relativer Pfad zum Ordner, der gepackt werden soll  
755    * @return die Meldung mit dem Ergebnis. Wenn die Meldung nicht "ok" lautet
756    * wurde die ZIP-Datei nicht erzeugt und die Meldung nennt den Grund.
757    */
758   public String packFolder(String fName, String relPath, HttpExchange e) {
759     if (!relPath.startsWith(".")) {    
760       try {        
761         //String fName = getFileName(e);
762         logger.fine("fName: " + fName);
763         if (fName.endsWith(STR_SLASH)) {
764           File dir = new File(e.getHttpContext().getAttributes().get(FileHandler.ATTR_FILE_BASE).toString(), fName);
765           if(dir.isDirectory()) {
766             logger.fine("absPath: " + dir.getAbsolutePath());
767             File parentDir = dir.getParentFile();
768             StringBuilder fname = new StringBuilder();
769             fname.append(dir.getName());
770             fname.append(".zip");
771             File archiveFile = new File(parentDir, fname.toString());
772             pack(dir.getAbsolutePath(), archiveFile.getAbsolutePath());
773             return "ok";
774           } else {
775             return "kein Ordner";
776           }
777         } else {
778           return "kein Ordner";
779         }
780       } catch(Exception ex) {
781         String result = ex.getLocalizedMessage();
782         logger.log(Level.SEVERE, result, ex);
783         return result;
784       }
785     } else {
786       return "Falsche relative Pfadangabe";
787     }
788   }
789   
790     /**
791      * pack the contents of a given folder into a new ZIP compressed archive
792      * @param folder  absolute path and name of the folder to pack
793      * @param archive  absolute path and name of the archive to create from the given files
794      * @throws Exception
795      */
796     private boolean pack(String folder, String archive) throws Exception {
797         File file = new File(archive);
798         FileOutputStream fos = new FileOutputStream(file);
799         CheckedOutputStream checksum = new CheckedOutputStream(fos, new Adler32());
800         ZipOutputStream zos = new ZipOutputStream(checksum);
801         pack(zos, folder, "");
802         zos.flush();
803         zos.finish();
804         zos.close();
805         fos.flush();
806         fos.close();
807         return true;
808     }
809
810     /**
811      * go through the given file structure recursively
812      * @param zipFile  the ZIP file to write to
813      * @param srcDir  the directory to pack during this cycle
814      * @param subDir  the subdirectory to append to names of file entries inside the archive
815      * @throws IOException
816      */
817     private void pack(ZipOutputStream zipFile, String srcDir, String subDir) throws IOException {
818         File[] files = new File(srcDir).listFiles();
819         for(int i = 0; i < files.length; i++) {
820             if(files[i].isDirectory()) {
821                 pack(zipFile, files[i].getAbsolutePath(), subDir + File.separator + files[i].getName());
822             }
823             else {
824                 packFile(zipFile, subDir, files[i]);
825             }
826         }
827     }
828
829     /**
830      * pack a given file
831      * @param zipFile  the ZIP archive to pack to
832      * @param dir  the directory name to append to name of file entry inside archive
833      * @param file  the file to pack
834      * @throws IOException
835      */
836     private void packFile(ZipOutputStream zipFile, String dir, File file) throws IOException
837     {
838         FileInputStream fileinputstream = new FileInputStream(file);
839         byte buf[] = new byte[fileinputstream.available()];
840         fileinputstream.read(buf);
841         String dirWithSlashes = dir.replace('\\', '/');
842         //System.out.println("zipping " + dirWithSlashes + "/" + file.getName());
843         ZipEntry ze = new ZipEntry(dirWithSlashes + "/" + file.getName());
844         ze.setMethod(ZipEntry.DEFLATED);
845         zipFile.putNextEntry(ze);
846         zipFile.write(buf, 0, buf.length);
847         zipFile.closeEntry();
848         fileinputstream.close();
849     }
850
851     
852   
853   
854 }