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