WebBox Klassenbibliothek
ulrich
2018-04-03 0b6a2bdf420c6fa90eaefade65690a1ab0319a0d
commit | author | age
c583a8 1
U 2 package de.uhilger.wbx.web;
3
0b6a2b 4 import de.uhilger.wbx.WbxUtils;
c583a8 5 import de.vogella.rss.model.Feed;
U 6 import de.vogella.rss.model.FeedMessage;
7 import java.io.File;
8 import java.io.FileReader;
9 import java.io.IOException;
10 import java.io.Reader;
11 import java.text.SimpleDateFormat;
12 import java.util.ArrayList;
13 import java.util.Calendar;
14 import java.util.Collections;
15 import java.util.Comparator;
16 import java.util.Date;
17 import java.util.GregorianCalendar;
18 import java.util.Iterator;
19 import java.util.List;
20 import java.util.Locale;
21 import java.util.logging.Level;
22 import java.util.logging.Logger;
23 import javax.servlet.ServletException;
24 import javax.servlet.ServletOutputStream;
25 import javax.servlet.http.HttpServlet;
26 import javax.servlet.http.HttpServletRequest;
27 import javax.servlet.http.HttpServletResponse;
28
29 /**
320c6e 30  * <p>Das FeedServlet erstellt Feeds von Ordnern der WebBox</p>
c583a8 31  * 
320c6e 32  * <p>Annahmen:</p>
U 33  * <ul>
34  * <li>Der JNDI-Parameter <code>wbxFileBase</code> enthaelt den absoluten Pfad 
35  * zur Dateiablage</li>
36  * <li>Der Parameter 'wbxPubDir' enthaelt den Namen des Ordners mit 
37  * oeffentlichen Inhalten und dieser Ordner liegt direkt unterhalb von 
38  * <code>wbxFileBase</code></li>
39  * <li>Der Ordner mit dem oeffentlichen Inhalt wird von Tomcat als Context 
40  * 1:1 ausgeliefert sodass bei einem URL wie 
41  * <code>http://example.com/[Context]/weitere/pfad/angaben/datei.html</code> 
42  * die Pfadangabe hinter <code>[Context]/</code> die Inhalte innerhalb von 
43  * <code>wbxFileBase/wbxPubDir</code> 1:1 wiedergibt.</li>
c583a8 44  * 
320c6e 45  * <p>Der JNDI-Parameter <code>wbxMaxFeedDepth</code> regelt, wie viele Ebenen der 
U 46  * Ordnerstruktur maximal nach Eintraegen durchsucht werden. Dabei haben die 
47  * tiefsten Ebenen Vorrang vor hoeher gelegenen Ebenen, d.h. Dateien auf 
48  * tieferen Ebenen werden vor Dateien auf hoeheren Ebenen in den Feed 
49  * aufgenommen.</p>
50  * 
51  * <p>Der JNDI-Parameter <code>wbxMaxFeedEntries</code> regelt, wie viele Beitraege 
52  * maximal im Feed erscheinen. Der Standardwert ist fuenf Beitraege, d.h., die 
53  * ersten fuenf gefundenen Beitraege werden chronologisch absteigend sortiert 
54  * nach ihrem letzten Aenderungsdatum ausgegeben.</p>
55  * 
56  * <p>Die Datei <code>CATALINA_BASE/conf/context.xml</code> muss also die 
57  * folgenden Eintraege enthalten:</p>
58  * <pre>
59  * <Environment name="wbxFileBase" type="java.lang.String" value="absoluter/pfad/zur/dateiablage" override="false" />
60  * <Environment name="wbxPubDir" type="java.lang.String" value="/www" override="false" />
61  * <Environment name="wbxFeedTitle" type="java.lang.String" value="Newsfeed" override="false" />
62  * <Environment name="wbxFeedSubtitle" type="java.lang.String" value="Text des Untertitels" override="false" />
63  * <Environment name="wbxFeedCopyright" type="java.lang.String" value="Text des Copyright-Hinweises" override="false" />
64  * <Environment name="wbxFeedDomain" type="java.lang.String" value="http://example.com" override="false" />
65  * <Environment name="wbxFeedAuthor" type="java.lang.String" value="Name des Autors" override="false" />
66  * </pre>
c583a8 67  */
U 68 public class FeedServlet extends HttpServlet {
69   
70   private static final Logger logger = Logger.getLogger(FeedServlet.class.getName());
71   
72   public static final String JNDI_CTX_NAME = "java:comp/env";
73   public static final String WBX_FILE_BASE = "wbxFileBase";
320c6e 74   public static final String WBX_PUB_DIR = "wbxPubDir";
c583a8 75   public static final String WBX_MAX_FEED_DEPTH = "wbxMaxFeedDepth";
U 76   public static final String WBX_MAX_FEED_ENTRIES = "wbxMaxFeedEntries";
320c6e 77   public static final String WBX_FEED_TITLE = "wbxFeedTitle";
U 78   public static final String WBX_FEED_SUBTITLE = "wbxFeedSubtitle";
79   public static final String WBX_FEED_COPYRIGHT = "wbxFeedCopyright";
80   public static final String WBX_FEED_DOMAIN = "wbxFeedDomain";
81   public static final String WBX_FEED_AUTHOR = "wbxFeedAuthor";
c583a8 82   
U 83   public static final int WBX_DEF_MAX_FEED_DEPTH = 3;
84   public static final int WBX_DEF_MAX_FEED_ENTRIES = 5;
0b6a2b 85     
c583a8 86   @Override
U 87   protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
88     ServletOutputStream out = response.getOutputStream();
89     response.setContentType("text/xml");
90     String url = request.getRequestURL().toString();
91     logger.fine("requestURL: " + url);
320c6e 92     String contextPath = request.getContextPath();
U 93     logger.fine("contextPath: " + contextPath);
94     String zielPfad = url.substring(url.indexOf(contextPath));
c583a8 95     logger.fine(zielPfad);
0b6a2b 96     WbxUtils wu = new WbxUtils();
U 97     String basis = wu.getJNDIParameter(WBX_FILE_BASE, WbxUtils.EMPTY_STRING);
320c6e 98     logger.fine("basis: " + basis);
U 99     StringBuffer pfad = new StringBuffer();
100     pfad.append(basis);
0b6a2b 101     pfad.append(zielPfad.replace(contextPath, wu.getJNDIParameter(WBX_PUB_DIR, WbxUtils.EMPTY_STRING)));
320c6e 102     logger.fine("pfad: " + pfad);
U 103     String dirStr = pfad.toString().substring(0, pfad.lastIndexOf("/"));
104     logger.fine("dirStr: " + dirStr);
105     File dir = new File(dirStr);
106     if (dir.isDirectory()) {
107       List beitraege = new ArrayList();
0b6a2b 108       int maxBeitraege = wu.getJNDIInt(WBX_MAX_FEED_ENTRIES, WBX_DEF_MAX_FEED_ENTRIES);
U 109       int maxTiefe = wu.getJNDIInt(WBX_MAX_FEED_DEPTH, WBX_DEF_MAX_FEED_DEPTH);
320c6e 110       collectFiles(dir, 0, beitraege, maxTiefe, maxBeitraege);
U 111       Iterator i = beitraege.iterator();
112       while (i.hasNext()) {
113         File f = (File) i.next();
114         logger.fine(f.getAbsolutePath() + " " + f.lastModified());
c583a8 115       }
0b6a2b 116       writeFeed(wu.getJNDIParameter(WBX_FEED_TITLE, WbxUtils.EMPTY_STRING), 
U 117               wu.getJNDIParameter(WBX_FEED_SUBTITLE, WbxUtils.EMPTY_STRING), out, beitraege, 
118               basis, pfad.toString(), contextPath, wu);
320c6e 119     } else {
U 120       logger.fine(dir.getAbsolutePath() + " ist kein Ordner.");
121     }
c583a8 122   }
U 123   
124   /**
125    * Diese Methode funktioniert nur, wenn entweder ein Ordner uebergeben 
126    * wird, der keine Unterordner enthaelt wie zum Beispiel der Ordner 'neu' 
127    * der Bildersammlung oder ein Ordner, dessen Unterordner 
128    * nach dem Schema Jahr, Monat benannt sind wie bei einem Journal, das 
129    * die Beitraege wie folgt enthaelt:
130    * Journal-Ordner
131    *   2018
132    *     12
133    *     11
134    *     10
135    *     usw.
136    *   2017
137    *     12
138    *     11
139    *     10
140    *     usw.
141    * 
142    * @param out
143    * @param dir
144    * @param tiefe
145    * @param dateizaehler 
146    */
147   private void collectFiles(File dir, int tiefe, List beitraege, int maxTiefe, int maxBeitraege) {
148     List dirs = new ArrayList();
149     List beitraegeHier = new ArrayList();
150     File[] files = dir.listFiles();
151     for(int i = 0; i < files.length; i++) {
152       if(files[i].isDirectory()) {
153         if(tiefe < maxTiefe) {
154           dirs.add(files[i]);
155         }
156       } else {
157         beitraegeHier.add(files[i]);
158       }
159     }
160       
161     if(dirs.size() > 0) {
162       // hier zuvor die Verzeichnissse absteigend nach Name sortieren      
163       Collections.sort(dirs, new Comparator<File>() {
164         @Override
165         public int compare(File o1, File o2) {
166           return o2.getName().compareTo(o1.getName());
167         }
168       });
169       
170       Iterator i = dirs.iterator();
171       while(i.hasNext() && beitraege.size() < maxBeitraege) {
172         collectFiles((File) i.next(), tiefe+1, beitraege, maxTiefe, maxBeitraege);
173       }
174     } 
175     if(beitraegeHier.size() > 0) {
176       // hier zuvor die Liste der Beitraege dieses Ordners nach lastModified absteigend sortieren
177       // dann die neuesten in beitraege aufnehmen, bis die maximale Zahl gesuchter 
178       // neuer Beitraege erreicht ist.
179       
180       Collections.sort(beitraegeHier, new Comparator<File>() {
181         @Override
182         public int compare(File o1, File o2) {
183           int ergebnis;
184           if(o1.lastModified() > o2.lastModified()) {
185             ergebnis = -1;
186           } else if(o2.lastModified() > o1.lastModified()) {
187             ergebnis = 1;
188           } else {
189             ergebnis = 0;
190           }
191           return ergebnis;
192         }
193       });
194       
195       Iterator i = beitraegeHier.iterator();
196       while(i.hasNext() && beitraege.size() < maxBeitraege) {
197         File bf = (File) i.next();
198         String nm = bf.getName().toLowerCase();
199         if(nm.endsWith(".htmi") || nm.endsWith(".html") || nm.endsWith(".htm") || 
200            nm.endsWith(".jpg") || nm.endsWith(".jpeg") || nm.endsWith(".png") || 
201            nm.endsWith(".txt")) {
202           beitraege.add(bf);
203         }
204       }
205       
206     }
207   }
208   
320c6e 209   public void writeFeed(String feedTitel, String beschr, ServletOutputStream s, 
0b6a2b 210           List beitraege, String basis, String pfad, String contextPath, WbxUtils wu) {
3e81ec 211     
U 212     long newest = -1;
0b6a2b 213     String copyright = wu.getJNDIParameter(WBX_FEED_COPYRIGHT, WbxUtils.EMPTY_STRING);
U 214     String domain = wu.getJNDIParameter(WBX_FEED_DOMAIN, WbxUtils.EMPTY_STRING);
c583a8 215     String title = feedTitel;
U 216     String description = beschr;
217     String language = "de";
320c6e 218     String link = domain;
3e81ec 219     
U 220     newest = ((File) beitraege.get(0)).lastModified();
221     
c583a8 222     Calendar cal = new GregorianCalendar();
3e81ec 223     cal.setTime(new Date(newest));
c583a8 224     Date creationDate = cal.getTime();
U 225     SimpleDateFormat date_format = new SimpleDateFormat(
226             "EEE', 'dd' 'MMM' 'yyyy' 'HH:mm:ss' 'Z", Locale.US);
227     String pubdate = date_format.format(creationDate);
228     Feed rssFeed = new Feed(title, link, description, language,
229             copyright, pubdate);
230
231     Iterator i = beitraege.iterator();
232     while (i.hasNext()) {
233       File f = (File) i.next();
234       FeedMessage feedEintrag = new FeedMessage();
235       feedEintrag.setTitle(f.getName());
236       //feedEintrag.setDescription("Beschreibung hier");
0b6a2b 237       feedEintrag.setAuthor(wu.getJNDIParameter(WBX_FEED_AUTHOR, WbxUtils.EMPTY_STRING));
c583a8 238
U 239       String urlStr = f.getAbsolutePath();
320c6e 240       urlStr = urlStr.replace(basis, domain);
0b6a2b 241       urlStr = urlStr.replace(wu.getJNDIParameter(WBX_PUB_DIR, WbxUtils.EMPTY_STRING), contextPath);
c583a8 242
U 243       logger.fine(urlStr);
244
245       feedEintrag.setGuid(urlStr);
246       feedEintrag.setLink(urlStr);
247       logger.fine(f.getName());
248       feedEintrag.setDescription(readFilePart(f, urlStr));
249       rssFeed.getMessages().add(feedEintrag);
250     }
251
252     FeedStreamWriter writer = new FeedStreamWriter(rssFeed, s);
253     try {
254       writer.write();
255     } catch (Exception e) {
256       logger.log(Level.SEVERE, e.getMessage(), e);
257     }
258   }
259   
260   private String readFilePart(File f, String urlStr) {
261     StringBuffer buf = new StringBuffer();
262     Reader reader = null;
263     try {
264       String fn = f.getName().toLowerCase();
265       if(fn.endsWith(".jpg") || fn.endsWith(".jpeg") || fn.endsWith(".png")) {
266         String noExt;
267         String ext;
268         int dotpos = urlStr.lastIndexOf('.');
269         if(dotpos > -1) {
270           noExt = urlStr.substring(0, dotpos);
271           ext = urlStr.substring(dotpos);
272         } else {
273           noExt = "";
274           ext = "";
275         }
276         buf.append("<a href='");
277         buf.append(urlStr);
278         buf.append("'><img src='");
279         buf.append(noExt);
280         buf.append("_kl");
281         buf.append(ext);
282         buf.append("'></a>");
283       } else {
284         reader = new FileReader(f);
285         char[] readBuffer = new char[1024];
286         int charsRead = reader.read(readBuffer);
287         buf.append(readBuffer);
288         reader.close();
289       }
290       return buf.toString();
291     } catch (Exception ex) {
292       logger.log(Level.SEVERE, null, ex);
293       return buf.toString();
294     }
295   }
296   
297 }