View Javadoc

1   /**
2    * Logback: the generic, reliable, fast and flexible logging framework.
3    * 
4    * Copyright (C) 2000-2008, QOS.ch
5    * 
6    * This library is free software, you can redistribute it and/or modify it under
7    * the terms of the GNU Lesser General Public License as published by the Free
8    * Software Foundation.
9    */
10  package ch.qos.logback.core.html;
11  
12  import java.util.HashMap;
13  import java.util.Map;
14  
15  import ch.qos.logback.core.Context;
16  import ch.qos.logback.core.CoreConstants;
17  import static ch.qos.logback.core.CoreConstants.LINE_SEPARATOR;
18  import ch.qos.logback.core.LayoutBase;
19  import ch.qos.logback.core.pattern.Converter;
20  import ch.qos.logback.core.pattern.ConverterUtil;
21  import ch.qos.logback.core.pattern.parser.Node;
22  import ch.qos.logback.core.pattern.parser.Parser;
23  import ch.qos.logback.core.pattern.parser.ScanException;
24  
25  /**
26   * This class is a base class for HTMLLayout classes part of
27   * other logback modules such as logback-classic and logback-access.
28   * 
29   *
30   * @author Sébastien Pennec
31   */
32  public abstract class HTMLLayoutBase<E> extends LayoutBase<E> {
33  
34    protected String pattern;
35  
36    protected Converter<E> head;
37  
38    protected String title = "Logback Log Messages";
39  
40    //It is the responsibility of derived classes to set
41    //this variable in their constructor to a default value.
42    protected CssBuilder cssBuilder;
43  
44     // counter keeping track of the rows output
45    protected long counter = 0;
46    
47    /**
48     * Set the <b>ConversionPattern </b> option. This is the string which controls
49     * formatting and consists of a mix of literal content and conversion
50     * specifiers.
51     */
52    public void setPattern(String conversionPattern) {
53      pattern = conversionPattern;
54    }
55  
56    /**
57     * Returns the value of the <b>ConversionPattern </b> option.
58     */
59    public String getPattern() {
60      return pattern;
61    }
62  
63    public CssBuilder getCssBuilder() {
64      return cssBuilder;
65    }
66  
67    public void setCssBuilder(CssBuilder cssBuilder) {
68      this.cssBuilder = cssBuilder;
69    }
70  
71    /**
72     * Parses the pattern and creates the Converter linked list.
73     */
74    @Override
75    public void start() {
76      int errorCount = 0;
77      
78      try {
79        Parser<E> p = new Parser<E>(pattern);
80        p.setContext(getContext());
81        Node t = p.parse();
82        this.head = p.compile(t, getEffectiveConverterMap());
83        ConverterUtil.startConverters(this.head);
84      } catch (ScanException ex) {
85        addError("Incorrect pattern found", ex);
86        errorCount++;
87      }
88  
89      if (errorCount == 0) {
90        super.started = true;
91      }
92    }
93    
94    protected abstract Map<String, String> getDefaultConverterMap();
95  
96    
97    /**
98     * Returns a map where the default converter map is merged with the map
99     * contained in the context.
100    */
101   public Map<String, String> getEffectiveConverterMap() {
102     Map<String, String> effectiveMap = new HashMap<String, String>();
103 
104     // add the least specific map fist
105     Map<String, String> defaultMap = getDefaultConverterMap();
106     if (defaultMap != null) {
107       effectiveMap.putAll(defaultMap);
108     }
109 
110     // contextMap is more specific than the default map
111     Context context = getContext();
112     if (context != null) {
113       @SuppressWarnings("unchecked")
114       Map<String, String> contextMap = (Map<String, String>) context
115           .getObject(CoreConstants.PATTERN_RULE_REGISTRY);
116       if (contextMap != null) {
117         effectiveMap.putAll(contextMap);
118       }
119     }
120     return effectiveMap;
121   }
122   
123   /**
124    * The <b>Title </b> option takes a String value. This option sets the
125    * document title of the generated HTML document.
126    * 
127    * <p>
128    * Defaults to 'Logback Log Messages'.
129    */
130   public void setTitle(String title) {
131     this.title = title;
132   }
133 
134   /**
135    * Returns the current value of the <b>Title </b> option.
136    */
137   public String getTitle() {
138     return title;
139   }
140 
141   /**
142    * Returns the content type output by this layout, i.e "text/html".
143    */
144   @Override
145   public String getContentType() {
146     return "text/html";
147   }
148 
149   /**
150    * Returns appropriate HTML headers.
151    */
152   @Override
153   public String getFileHeader() {
154     StringBuilder sbuf = new StringBuilder();
155     sbuf.append("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"");
156     sbuf.append(" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">");
157     sbuf.append(LINE_SEPARATOR);
158     sbuf.append("<html>");
159     sbuf.append(LINE_SEPARATOR);
160     sbuf.append("  <head>");
161     sbuf.append(LINE_SEPARATOR);
162     sbuf.append("    <title>");
163     sbuf.append(title);
164     sbuf.append("</title>");
165     sbuf.append(LINE_SEPARATOR);
166     
167     cssBuilder.addCss(sbuf);
168 //    if (cssBuilder == null) {
169 //      DefaultCssBuilder.addDefaultCSS(sbuf);
170 //    } else {
171 //      cssBuilder.addExternalCSS(sbuf);
172 //    }
173     sbuf.append(LINE_SEPARATOR);
174     sbuf.append("  </head>");
175     sbuf.append(LINE_SEPARATOR);
176     sbuf.append("<body>");
177     sbuf.append(LINE_SEPARATOR);
178 
179     return sbuf.toString();
180   }
181   
182   public String getPresentationHeader() {
183     StringBuilder sbuf = new StringBuilder();
184     sbuf.append("<hr/>");
185     sbuf.append(LINE_SEPARATOR);
186     sbuf.append("<p>Log session start time ");
187     sbuf.append(new java.util.Date());
188     sbuf.append("</p><p></p>");
189     sbuf.append(LINE_SEPARATOR);
190     sbuf.append(LINE_SEPARATOR);
191     sbuf.append("<table cellspacing=\"0\">");
192     sbuf.append(LINE_SEPARATOR);
193 
194     buildHeaderRowForTable(sbuf);
195     
196     return sbuf.toString();
197   }
198 
199 
200   private void buildHeaderRowForTable(StringBuilder sbuf) {
201     Converter c = head;
202     String name;
203     sbuf.append("<tr class=\"header\">");
204     sbuf.append(LINE_SEPARATOR);
205     while (c != null) {
206       name = computeConverterName(c);
207       if (name == null) {
208         c = c.getNext();
209         continue;
210       }
211       sbuf.append("<td class=\"");
212       sbuf.append(computeConverterName(c));
213       sbuf.append("\">");
214       sbuf.append(computeConverterName(c));
215       sbuf.append("</td>");
216       sbuf.append(LINE_SEPARATOR);
217       c = c.getNext();
218     }
219     sbuf.append("</tr>");
220     sbuf.append(LINE_SEPARATOR);
221   }
222   
223   public String getPresentationFooter() {
224     StringBuilder sbuf = new StringBuilder();
225     sbuf.append("</table>");
226     return sbuf.toString();    
227   }
228 
229   /**
230    * Returns the appropriate HTML footers.
231    */
232   @Override
233   public String getFileFooter() {
234     StringBuilder sbuf = new StringBuilder();
235     sbuf.append(LINE_SEPARATOR);
236     sbuf.append("</body></html>");
237     return sbuf.toString();
238   }
239   
240   protected void startNewTableIfLimitReached(StringBuilder sbuf) {
241     if (this.counter >= CoreConstants.TABLE_ROW_LIMIT) {
242       counter = 0;
243       sbuf.append("</table>");
244       sbuf.append(LINE_SEPARATOR);
245       sbuf.append("<p></p>");
246       sbuf.append("<table cellspacing=\"0\">");
247       sbuf.append(LINE_SEPARATOR);
248       buildHeaderRowForTable(sbuf);
249     }
250   }
251 
252   protected String computeConverterName(Converter c) {
253     String className = c.getClass().getSimpleName();
254     int index = className.indexOf("Converter");
255     if (index == -1) {
256       return className;
257     } else {
258       return className.substring(0, index);
259     }
260   }
261 
262 }