Dateien verwalten mit Modul jdk.httpserver
ulrich
2021-07-04 7fdd7ef5017900baaf0ba3159f8d1dfe9a3a136e
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   }
236
237   private void liste(HttpExchange e, HttpHelper helper) throws IOException {
238     String path = e.getRequestURI().toString();
239     logger.fine(path);
240     String fName = helper.getFileName(e);
241     if (path.endsWith(STR_SLASH)) {      
242       logger.fine("fName: " + fName);
243       File dir = new File(e.getHttpContext().getAttributes().get(FileHandler.ATTR_FILE_BASE).toString(), fName);
244       logger.fine("absPath: " + dir.getAbsolutePath());
245       File[] files = dir.listFiles(new ImageFileFilter());
246       if(files != null && files.length > 0) {
247         Arrays.sort(files);
248         ArrayList liste = new ArrayList();
249         for (File file : files) {
250           Datei datei = new Datei();
251           String dateiName = file.getName();
252           datei.setName(dateiName);
253           if (file.isDirectory()) {
254             datei.setTyp(Datei.TYP_ORDNER);
255           } else {
256             datei.setTyp(Datei.TYP_DATEI);
257           }
258           datei.setPfad(e.getHttpContext().getPath() + fName);
259           String lowerName = dateiName.toLowerCase();
260           if (lowerName.endsWith(ImageActor.JPEG)
261                   || lowerName.endsWith(ImageActor.JPG)
262                   || lowerName.endsWith(ImageActor.PNG)) {
263             datei.setBild(true);
264             String ext = dateiName.substring(dateiName.lastIndexOf(STR_DOT));
265             String ohneExt = dateiName.substring(0, dateiName.lastIndexOf(STR_DOT));
266             datei.setMiniurl(ohneExt + ImageActor.TN + ext);
267             buildImgSrc(file, datei, ohneExt, ext);
268           }
269           liste.add(datei);
270         }
271         while(threadCount > 0) {
272           try {
273             Thread.sleep(50);
274           } catch (InterruptedException ex) {
275             Logger.getLogger(FileManager.class.getName()).log(Level.SEVERE, null, ex);
276           }
277         }
278         if(liste.size() > 0) {
279           Gson gson = new Gson();
280           String json = gson.toJson(liste);
281           //byte[] bytes = json.getBytes();
282           //logger.fine("json: '" + json + "'");
283           HttpResponder r = new HttpResponder();
284           r.antwortSenden(e, SC_OK, json);
285         } else {
286           emptyListResponse(e);      
287         }
288       } else {
289         emptyListResponse(e);      
290       }
291     } else {
292       String lowerName = fName.toLowerCase();
293       if(lowerName.contains(ImageActor.B64)) {
294         ImageActor actor = new ImageActor();
295         String fromName = fName.replace(ImageActor.B64, "");
296         File fromFile = new File(e.getHttpContext().getAttributes().get(FileHandler.ATTR_FILE_BASE).toString(), fromName);
297         File toFile = new File(e.getHttpContext().getAttributes().get(FileHandler.ATTR_FILE_BASE).toString(), fName);
298         logger.fine("from " + fromFile.getAbsolutePath() + ", to " + toFile.getAbsolutePath());
299         if(!toFile.exists()) {
300           actor.b64Image(fromFile, toFile);
301         }
302         super.handle(e);
303       } else {
304         super.handle(e);
305       }
306     }
307   }
308   
309   //  data:[<mime type>][;charset=<Zeichensatz>][;base64],<Daten>
310   /*
311   [So. Juni 13 13:23:32 MESZ 2021] FEIN: 
312   file: /home/ulrich/helix-files/bild-test/10419903-14-2-1920-r.jpg, 
313   relname: bild-test/10419903-14-2-1920-r.jpg, ohneExt: 10419903-14-2-1920-r, ext: .jpg (de.uhilger.helix.FileManager buildImgSrc)
314
315   */
316   private void buildImgSrc(File file, Datei datei, String ohneExt, String ext) throws IOException {
317     //logger.fine("file: " + file.getAbsolutePath() + ", ohneExt: " + ohneExt + ", ext: " + ext);
318     File dir = file.getParentFile();
319     String newRelName = ohneExt + ImageActor.TN + ImageActor.B64 + ext;
320     File b64File = new File(dir, newRelName);
321     //logger.fine("b64File: " + b64File.getAbsolutePath());
322     if(!b64File.exists()) {
323       //BildErzeuger be = new BildErzeuger();
324       //be.bildErzeugen(dir, newRelName, BildErzeuger.TN, 120, b64File);
325       ImageThread it = new ImageThread(dir, newRelName, ImageActor.TN, 120, b64File, datei, ext);
326       it.addListener(this);
327       if(threadCount < maxThreads) {
328         ++threadCount;
329         //logger.fine("Thread started, threadCount: " + threadCount);
330         it.start();
331       } else {
332         waitingThreads.add(it);
333         //logger.fine("Thread added to wait queue.");
334       }
335     } else {
336       ImageActor be = new ImageActor();
337       be.setImgSrc(datei, ext, b64File);
338     }
339   }
340   
341   @Override
342   public void finished() {
343     --threadCount;
344     //logger.fine("Thread finished, threadCound now: " + threadCount);
345     if (threadCount < maxThreads) {
346       if (waitingThreads.size() > 0) {
347         Object o = waitingThreads.get(0);
348         if (o instanceof ImageThread) {
349           waitingThreads.remove(o);
350           ImageThread it = (ImageThread) o;
351           ++threadCount;
352           //logger.fine("Thread started from wait queue, threadCount now: " + threadCount);
353           it.start();
354         }
355       }
356     }
357   }  
358   
359   private void emptyListResponse(HttpExchange e) throws IOException {
360     HttpResponder r = new HttpResponder();
361     String json = "{}";
362     logger.log(Level.FINE, "json: ''{0}''", json);
363     r.antwortSenden(e, SC_OK, json);        
364   }
365
366   private void speichern(HttpExchange exchange, HttpHelper helper) throws IOException {
367     String fileName = helper.getFileName(exchange);
368     logger.info("fileName: " + fileName);
369
370     // file ist die Datei, um die es geht
371     File file = new File(exchange.getHttpContext().getAttributes().get(FileHandler.ATTR_FILE_BASE).toString(), fileName);
372
373     String method = exchange.getRequestMethod();
374     if (fileName.endsWith(STR_SLASH)) {
375       logger.info("neuer Ordner: " + file.getAbsolutePath());
376       // neuen Ordner erstellen oder ablehnen, wenn der Ordner schon existiert
377       if (method.equalsIgnoreCase(HttpHelper.HTTP_POST)) {
378         if (!file.exists()) {
379           file.mkdir();
380           standardHeaderUndAntwort(exchange, SC_OK, file.getAbsolutePath());
381         } else {
382           String antwort = "Ordner existiert bereits.";
383           standardHeaderUndAntwort(exchange, SC_UNPROCESSABLE_ENTITY, antwort);
384         }
385       } else {
386         String antwort = "PUT fuer neuen Ordner nicht erlaubt, bitte POST verwenden.";
387         standardHeaderUndAntwort(exchange, SC_METHOD_NOT_ALLOWED, antwort);        
388       }
389     } else {
390       logger.info("Datei speichern: " + file.getAbsolutePath());
391       // Datei speichern
392       if (method.equalsIgnoreCase(HttpHelper.HTTP_POST)) {
393         if (file.exists()) {
394           FileTransporter trans = new FileTransporter();
395           file = trans.getNewFileName(file);
396         }
397       } else if (method.equalsIgnoreCase(HttpHelper.HTTP_PUT)) {
398         if (file.exists()) {
399           /*
400             muss delete() sein?
401             pruefen: ueberschreibt der FileWriter den alteen Inhalt oder 
402             entsteht eine unerwuenschte Mischung aus altem und neuem 
403             Inhalt?
404            */
405           file.delete();
406         } else {
407           file.getParentFile().mkdirs();
408         }
409       }
410       // Request Body mit dem Dateiinhalt in einen String lesen
411       StringBuilder sb = new StringBuilder();
412       InputStream is = exchange.getRequestBody();
413       BufferedReader in = new BufferedReader(new InputStreamReader(is));
414       String line = in.readLine();
415       while (line != null) {
416         sb.append(line);
417         line = in.readLine();
418       }
419
420       // dekodieren
421       String content = sb.toString();
422       logger.fine(content);
423       String decoded = URLDecoder.decode(content, UTF8);
424       logger.fine(decoded);
425
426       // in Datei schreiben
427       byte[] bytes = decoded.getBytes();
428       file.createNewFile();
429       OutputStream os = new FileOutputStream(file);
430       os.write(bytes);
431       os.flush();
432       os.close();
433       is.close();
434
435       // Antwort senden
436       standardHeaderUndAntwort(exchange, SC_OK, file.getAbsolutePath());
437     }
438   }
439
440   private void copyOrMove(HttpExchange exchange, String quelle, String ziel, int op) throws IOException {
441     logger.fine("quelle: " + quelle + ", ziel: " + ziel);
442     String[] dateiNamen = dateiliste(exchange);
443     copyOrMoveFiles(quelle, ziel, dateiNamen, op, exchange);
444     standardHeaderUndAntwort(exchange, SC_OK, "Dateien verarbeitet.");
445   }
446
447   private String copyOrMoveFiles(String fromPath, String toPath, String[] fileNames, int operation, HttpExchange e) throws IOException {
448     String result = null;
449     File srcDir = new File(e.getHttpContext().getAttributes().get(FileHandler.ATTR_FILE_BASE).toString(), fromPath);
450     File targetDir = new File(e.getHttpContext().getAttributes().get(FileHandler.ATTR_FILE_BASE).toString(), toPath);
451     for (String fileName : fileNames) {
452       File srcFile = new File(srcDir, fileName);
453       logger.fine("srcFile: " + srcFile);
454       if (srcFile.isDirectory()) {
455         logger.fine("srcFile is directory.");
456         OrdnerBearbeiter bearbeiter = new OrdnerBearbeiter();
457         bearbeiter.setTargetDir(targetDir.toPath());
458         bearbeiter.setOperation(operation);
459         Files.walkFileTree(srcFile.toPath(), bearbeiter);
460       } else {
461         Path source = srcFile.toPath();
462         File destFile = targetDir.toPath().resolve(source.getFileName()).toFile();
463         if (destFile.exists()) {
464           FileTransporter trans = new FileTransporter();
465           destFile = trans.getNewFileName(destFile);
466         }
467         if (operation == OP_MOVE) {
468           String fname = srcFile.getName().toLowerCase();
469           if (fname.endsWith(ImageActor.JPEG)
470                   || fname.endsWith(ImageActor.JPG)
471                   || fname.endsWith(ImageActor.PNG)) {
472             moveImgFilesToDirectory(srcFile, srcDir, targetDir, false);
473           } else {
474             Files.move(source, destFile.toPath());
475           }
476         } else {
477           Files.copy(source, destFile.toPath());
478         }
479       }
480     }
481     return result;
482   }
483
484   private void loeschen(HttpExchange exchange, HttpHelper helper) throws IOException {
485     String[] dateiNamen = dateiliste(exchange);
486     String relPfad = helper.getFileName(exchange);
487     deleteFiles(relPfad, Arrays.asList(dateiNamen), exchange);
488     standardHeaderUndAntwort(exchange, SC_OK, "Dateien geloescht.");
489   }
490
491   private String[] dateiliste(HttpExchange exchange) throws IOException {
492     String body = new HttpHelper().bodyLesen(exchange);
493     logger.fine("dateien: " + body);
494     Gson gson = new Gson();
495     return gson.fromJson(body, String[].class);
496   }
497
498   public String duplizieren(HttpExchange exchange, HttpHelper helper) throws IOException {
499     String relPfad = helper.getFileName(exchange);
500     File srcFile = new File(exchange.getHttpContext().getAttributes().get(FileHandler.ATTR_FILE_BASE).toString(), relPfad);
501     String fnameext = srcFile.getName();
502     int dotpos = fnameext.lastIndexOf(STR_DOT);
503     String fname = fnameext.substring(0, dotpos);
504     String ext = fnameext.substring(dotpos);
505     File srcDir = srcFile.getParentFile();
506     File destFile = new File(srcDir, fname + "-Kopie" + ext);
507     int i = 1;
508     while (destFile.exists()) {
509       destFile = new File(srcDir, fname + "-Kopie-" + Integer.toString(++i) + ext);
510     }
511     Files.copy(srcFile.toPath(), destFile.toPath());
512     return destFile.getName();
513   }
514
515   public String umbenennen(HttpExchange exchange, HttpHelper helper, String neuerName) throws IOException {
516     File neueDatei;
517     String relPfad = helper.getFileName(exchange);
518     File file = new File(exchange.getHttpContext().getAttributes().get(FileHandler.ATTR_FILE_BASE).toString(), relPfad);
519     String fname = file.getName().toLowerCase();
520     if(fname.endsWith(ImageActor.JPEG) || fname.endsWith(ImageActor.JPG) || fname.endsWith(ImageActor.PNG)) {
521       neueDatei = renameImgFiles(file.getParentFile(), file, neuerName);  
522     } else {
523       neueDatei = new File(file.getParentFile(), neuerName);
524       file.renameTo(neueDatei);
525     }
526     return neueDatei.getName();
527   }
528   
529   public File renameImgFiles(File targetDir, File targetFile, String newName) throws IOException {
530     String alt;
531     String neu;
532     File neueDatei = targetFile;
533     
534     int newdotpos = newName.lastIndexOf(STR_DOT);
535     String newfname = newName.substring(0, newdotpos);
536     String newext = newName.substring(newdotpos);
537     logger.fine("newfname: " + newfname + ", newext: " + newext);
538     
539     String fnameext = targetFile.getName();
540     int dotpos = fnameext.lastIndexOf(STR_DOT);
541     String fname = fnameext.substring(0, dotpos);
542     String ext = fnameext.substring(dotpos);
543     logger.fine("fname: " + fname + ", ext: " + ext);
544     
545     DirectoryStream<Path> stream = Files.newDirectoryStream(targetDir.toPath(), fname + "*" + ext); //"*.{txt,doc,pdf,ppt}"
546     for (Path path : stream) {
547       logger.fine(path.getFileName().toString());
548       alt = path.getFileName().toString();
549       logger.fine("alt: " + alt);
550       if(alt.contains(ImageActor.TN)) {
551         neu = newfname + ImageActor.TN + newext;
552       } else if (alt.contains(ImageActor.KL)) {
553         neu = newfname + ImageActor.KL + newext;
554       } else if(alt.contains(ImageActor.GR)) {
555         neu = newfname + ImageActor.GR + newext;
556       } else if(alt.contains(ImageActor.MT)) {
557         neu = newfname + ImageActor.MT + newext;
558       } else if(alt.contains(ImageActor.SM)) {
559         neu = newfname + ImageActor.SM + newext;
560       } else {
561         neu = newName;
562       }
563       neueDatei = new File(targetDir, neu);
564       path.toFile().renameTo(neueDatei);              
565     }
566     stream.close();
567     return neueDatei;
568   }
569   
570   
571   private String deleteFiles(String relPath, List<String> fileNames, HttpExchange e) {
572     String result = null;
573     try {
574       logger.fine(fileNames.toString());
575       if (!relPath.startsWith(STR_DOT)) {
576         File targetDir = new File(e.getHttpContext().getAttributes().get(FileHandler.ATTR_FILE_BASE).toString(), relPath); // getTargetDir(relPath);
577         logger.fine("targetDir: " + targetDir);
578         for (String fileName : fileNames) {
579           File targetFile = new File(targetDir, fileName);
580           logger.fine(targetFile.getAbsolutePath());
581           if (targetFile.isDirectory()) {
582             OrdnerBearbeiter bearbeiter = new OrdnerBearbeiter();
583             bearbeiter.setOperation(OP_DELETE);
584             Files.walkFileTree(targetFile.toPath(), bearbeiter);
585           } else {
586             /*
587                 Wenn targetFile mit jpg, jpeg oder png endet, 
588                 muss eine Unterfunktion eine Liste aller Dateien bilden, 
589                 die so heissen, also z.B. alle [Dateiname]*.jpg
590              */
591             String fname = targetFile.getName().toLowerCase();
592             if (fname.endsWith(ImageActor.JPEG)
593                     || fname.endsWith(ImageActor.JPG)
594                     || fname.endsWith(ImageActor.PNG)) {
595               deleteImgFiles(targetDir, targetFile);
596             } else {
597               targetFile.delete();
598             }
599           }
600         }
601         result = "deleted";
602       }
603     } catch (Throwable ex) {
604       logger.log(Level.SEVERE, ex.getLocalizedMessage(), ex);
605     }
606     return result;
607   }
608
609   private void deleteImgFiles(File targetDir, File targetFile) throws IOException {
610     String fnameext = targetFile.getName();
611     int dotpos = fnameext.lastIndexOf(STR_DOT);
612     String fname = fnameext.substring(0, dotpos);
613     String ext = fnameext.substring(dotpos);
614     logger.fine("fname: " + fname + ", ext: " + ext);
615     DirectoryStream<Path> stream = Files.newDirectoryStream(targetDir.toPath(), fname + "*" + ext); //"*.{txt,doc,pdf,ppt}"
616     for (Path path : stream) {
617       logger.fine(path.getFileName().toString());
618       Files.delete(path);
619     }
620     stream.close();
621   }
622
623   private void moveImgFilesToDirectory(File srcFile, File srcDir, File targetDir, boolean createDestDir) throws IOException {
624     String fnameext = srcFile.getName();
625     int dotpos = fnameext.lastIndexOf(STR_DOT);
626     String fname = fnameext.substring(0, dotpos);
627     String ext = fnameext.substring(dotpos);
628     logger.fine("fname: " + fname + ", ext: " + ext);
629     Path targetPath = targetDir.toPath();
630     DirectoryStream<Path> stream = Files.newDirectoryStream(srcDir.toPath(), fname + "*" + ext); //"*.{txt,doc,pdf,ppt}"
631     for (Path path : stream) {
632       logger.fine(path.getFileName().toString());
633       //Files.delete(path);
634       Files.move(path, targetPath.resolve(path.getFileName()));
635     }
636     stream.close();
637   }
638   
639   private void standardHeaderUndAntwort(HttpExchange exchange, int status, String antwort) throws IOException {
640     Headers resHeaders = exchange.getResponseHeaders();
641     resHeaders.add(CONTENT_TYPE, HttpHelper.CT_TEXT_HTML);
642     new HttpResponder().antwortSenden(exchange, status, antwort);
643   }  
644   
645   /* --------- ZIP entpacken ---------------- */
646   
647   public String extractZipfile(String fName, String relPath, HttpExchange e) {  
648     logger.fine("fName: " + fName + ", relPath: " + relPath);
649     String result = null;
650     if (!relPath.startsWith(".")) {    
651       try {
652         //File targetDir = new File(fileBase, relPath);
653         //File targetDir = getTargetDir(relPath);
654         File archive = new File(e.getHttpContext().getAttributes().get(FileHandler.ATTR_FILE_BASE).toString(), fName);
655         if(extract(archive)) {
656           result = "ok";
657         } else {
658           result = "error while extracting";
659         }
660       } catch(Exception ex) {
661         result = ex.getLocalizedMessage();
662         logger.log(Level.SEVERE, ex.getLocalizedMessage(), ex);
663       }
664     } else {
665       result = "Falsche relative Pfadangabe.";
666     }
667     return result;
668   }
669   
670   /**
671      * extract a given ZIP archive to the folder respective archive resides in
672      * @param archive  the archive to extract
673      * @throws Exception
674      */
675     private boolean extract(File archive) throws Exception {
676         ZipFile zipfile = new ZipFile(archive);
677         Enumeration en = zipfile.entries();
678         while(en.hasMoreElements()) {
679             ZipEntry zipentry = (ZipEntry) en.nextElement();
680             unzip(zipfile, zipentry, archive.getParent());
681         }
682         zipfile.close();
683         return true;
684     }
685
686     /**
687      * unzip a given entry of a given zip file to a given location
688      * @param zipfile  the zip file to read an entry from
689      * @param zipentry  the zip entry to read
690      * @param destPath  the path to the destination location for the extracted content
691      * @throws IOException
692      */
693     private void unzip(ZipFile zipfile, ZipEntry zipentry, String destPath) throws IOException {
694         byte buf[] = new byte[1024];
695         InputStream is = zipfile.getInputStream(zipentry);
696         String outFileName = destPath + File.separator + zipentry.getName();
697         File file = new File(outFileName);
698         if(!zipentry.isDirectory()) {
699             file.getParentFile().mkdirs();
700             if(!file.exists())
701                 file.createNewFile();
702             FileOutputStream fos = new FileOutputStream(file);
703             int i = is.read(buf, 0, 1024);
704             while(i > -1) {
705                 fos.write(buf, 0, i);
706                 i = is.read(buf, 0, 1024);
707             }
708             fos.close();
709             is.close();
710         } else {
711             file.mkdirs();
712         }
713     }
714
715   /* --------------- Ordner packen ----------------- */
716
717   /**
718    * Einen Ordner packen.
719    * 
720    * Als Ziel wird eine neue Datei mit Dateiendung '.zip' erzeugt, die so 
721    * heisst wie der Ordner, der gapckt werden soll. Die Datei mit 
722    * dem gepackten Ordnerinhalt wird in dem Ordner angelegt, der den zu 
723    * packenden Ordner enthaelt.
724    * 
725    * @param fName  Name des zu packenden Ordners
726    * @param relPath  relativer Pfad zum Ordner, der gepackt werden soll  
727    * @return die Meldung mit dem Ergebnis. Wenn die Meldung nicht "ok" lautet
728    * wurde die ZIP-Datei nicht erzeugt und die Meldung nennt den Grund.
729    */
730   public String packFolder(String fName, String relPath, HttpExchange e) {
731     if (!relPath.startsWith(".")) {    
732       try {        
733         //String fName = getFileName(e);
734         logger.fine("fName: " + fName);
735         if (fName.endsWith(STR_SLASH)) {
736           File dir = new File(e.getHttpContext().getAttributes().get(FileHandler.ATTR_FILE_BASE).toString(), fName);
737           if(dir.isDirectory()) {
738             logger.fine("absPath: " + dir.getAbsolutePath());
739             File parentDir = dir.getParentFile();
740             StringBuilder fname = new StringBuilder();
741             fname.append(dir.getName());
742             fname.append(".zip");
743             File archiveFile = new File(parentDir, fname.toString());
744             pack(dir.getAbsolutePath(), archiveFile.getAbsolutePath());
745             return "ok";
746           } else {
747             return "kein Ordner";
748           }
749         } else {
750           return "kein Ordner";
751         }
752       } catch(Exception ex) {
753         String result = ex.getLocalizedMessage();
754         logger.log(Level.SEVERE, result, ex);
755         return result;
756       }
757     } else {
758       return "Falsche relative Pfadangabe";
759     }
760   }
761   
762     /**
763      * pack the contents of a given folder into a new ZIP compressed archive
764      * @param folder  absolute path and name of the folder to pack
765      * @param archive  absolute path and name of the archive to create from the given files
766      * @throws Exception
767      */
768     private boolean pack(String folder, String archive) throws Exception {
769         File file = new File(archive);
770         FileOutputStream fos = new FileOutputStream(file);
771         CheckedOutputStream checksum = new CheckedOutputStream(fos, new Adler32());
772         ZipOutputStream zos = new ZipOutputStream(checksum);
773         pack(zos, folder, "");
774         zos.flush();
775         zos.finish();
776         zos.close();
777         fos.flush();
778         fos.close();
779         return true;
780     }
781
782     /**
783      * go through the given file structure recursively
784      * @param zipFile  the ZIP file to write to
785      * @param srcDir  the directory to pack during this cycle
786      * @param subDir  the subdirectory to append to names of file entries inside the archive
787      * @throws IOException
788      */
789     private void pack(ZipOutputStream zipFile, String srcDir, String subDir) throws IOException {
790         File[] files = new File(srcDir).listFiles();
791         for(int i = 0; i < files.length; i++) {
792             if(files[i].isDirectory()) {
793                 pack(zipFile, files[i].getAbsolutePath(), subDir + File.separator + files[i].getName());
794             }
795             else {
796                 packFile(zipFile, subDir, files[i]);
797             }
798         }
799     }
800
801     /**
802      * pack a given file
803      * @param zipFile  the ZIP archive to pack to
804      * @param dir  the directory name to append to name of file entry inside archive
805      * @param file  the file to pack
806      * @throws IOException
807      */
808     private void packFile(ZipOutputStream zipFile, String dir, File file) throws IOException
809     {
810         FileInputStream fileinputstream = new FileInputStream(file);
811         byte buf[] = new byte[fileinputstream.available()];
812         fileinputstream.read(buf);
813         String dirWithSlashes = dir.replace('\\', '/');
814         //System.out.println("zipping " + dirWithSlashes + "/" + file.getName());
815         ZipEntry ze = new ZipEntry(dirWithSlashes + "/" + file.getName());
816         ze.setMethod(ZipEntry.DEFLATED);
817         zipFile.putNextEntry(ze);
818         zipFile.write(buf, 0, buf.length);
819         zipFile.closeEntry();
820         fileinputstream.close();
821     }
822
823     
824   
825   
826 }