View Javadoc

1   /**
2    * Logback: the reliable, generic, fast and flexible logging framework.
3    * Copyright (C) 1999-2011, QOS.ch. All rights reserved.
4    *
5    * This program and the accompanying materials are dual-licensed under
6    * either the terms of the Eclipse Public License v1.0 as published by
7    * the Eclipse Foundation
8    *
9    *   or (per the licensee's choosing)
10   *
11   * under the terms of the GNU Lesser General Public License version 2.1
12   * as published by the Free Software Foundation.
13   */
14  package ch.qos.logback.core.html;
15  
16  import java.util.HashMap;
17  import java.util.Map;
18  
19  import ch.qos.logback.core.Context;
20  import ch.qos.logback.core.CoreConstants;
21  import static ch.qos.logback.core.CoreConstants.LINE_SEPARATOR;
22  import ch.qos.logback.core.LayoutBase;
23  import ch.qos.logback.core.pattern.Converter;
24  import ch.qos.logback.core.pattern.ConverterUtil;
25  import ch.qos.logback.core.pattern.parser.Node;
26  import ch.qos.logback.core.pattern.parser.Parser;
27  import ch.qos.logback.core.pattern.parser.ScanException;
28  
29  /**
30   * This class is a base class for HTMLLayout classes part of
31   * other logback modules such as logback-classic and logback-access.
32   * 
33   *
34   * @author Sébastien Pennec
35   */
36  public abstract class HTMLLayoutBase<E> extends LayoutBase<E> {
37  
38    protected String pattern;
39  
40    protected Converter<E> head;
41  
42    protected String title = "Logback Log Messages";
43  
44    //It is the responsibility of derived classes to set
45    //this variable in their constructor to a default value.
46    protected CssBuilder cssBuilder;
47  
48     // counter keeping track of the rows output
49    protected long counter = 0;
50    
51    /**
52     * Set the <b>ConversionPattern </b> option. This is the string which controls
53     * formatting and consists of a mix of literal content and conversion
54     * specifiers.
55     */
56    public void setPattern(String conversionPattern) {
57      pattern = conversionPattern;
58    }
59  
60    /**
61     * Returns the value of the <b>ConversionPattern </b> option.
62     */
63    public String getPattern() {
64      return pattern;
65    }
66  
67    public CssBuilder getCssBuilder() {
68      return cssBuilder;
69    }
70  
71    public void setCssBuilder(CssBuilder cssBuilder) {
72      this.cssBuilder = cssBuilder;
73    }
74  
75    /**
76     * Parses the pattern and creates the Converter linked list.
77     */
78    @Override
79    public void start() {
80      int errorCount = 0;
81      
82      try {
83        Parser<E> p = new Parser<E>(pattern);
84        p.setContext(getContext());
85        Node t = p.parse();
86        this.head = p.compile(t, getEffectiveConverterMap());
87        ConverterUtil.startConverters(this.head);
88      } catch (ScanException ex) {
89        addError("Incorrect pattern found", ex);
90        errorCount++;
91      }
92  
93      if (errorCount == 0) {
94        super.started = true;
95      }
96    }
97    
98    protected abstract Map<String, String> getDefaultConverterMap();
99  
100   
101   /**
102    * Returns a map where the default converter map is merged with the map
103    * contained in the context.
104    */
105   public Map<String, String> getEffectiveConverterMap() {
106     Map<String, String> effectiveMap = new HashMap<String, String>();
107 
108     // add the least specific map fist
109     Map<String, String> defaultMap = getDefaultConverterMap();
110     if (defaultMap != null) {
111       effectiveMap.putAll(defaultMap);
112     }
113 
114     // contextMap is more specific than the default map
115     Context context = getContext();
116     if (context != null) {
117       @SuppressWarnings("unchecked")
118       Map<String, String> contextMap = (Map<String, String>) context
119           .getObject(CoreConstants.PATTERN_RULE_REGISTRY);
120       if (contextMap != null) {
121         effectiveMap.putAll(contextMap);
122       }
123     }
124     return effectiveMap;
125   }
126   
127   /**
128    * The <b>Title </b> option takes a String value. This option sets the
129    * document title of the generated HTML document.
130    * 
131    * <p>
132    * Defaults to 'Logback Log Messages'.
133    */
134   public void setTitle(String title) {
135     this.title = title;
136   }
137 
138   /**
139    * Returns the current value of the <b>Title </b> option.
140    */
141   public String getTitle() {
142     return title;
143   }
144 
145   /**
146    * Returns the content type output by this layout, i.e "text/html".
147    */
148   @Override
149   public String getContentType() {
150     return "text/html";
151   }
152 
153   /**
154    * Returns appropriate HTML headers.
155    */
156   @Override
157   public String getFileHeader() {
158     StringBuilder sbuf = new StringBuilder();
159     sbuf.append("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"");
160     sbuf.append(" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">");
161     sbuf.append(LINE_SEPARATOR);
162     sbuf.append("<html>");
163     sbuf.append(LINE_SEPARATOR);
164     sbuf.append("  <head>");
165     sbuf.append(LINE_SEPARATOR);
166     sbuf.append("    <title>");
167     sbuf.append(title);
168     sbuf.append("</title>");
169     sbuf.append(LINE_SEPARATOR);
170     
171     cssBuilder.addCss(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 }