View Javadoc
1   /**
2    * Logback: the reliable, generic, fast and flexible logging framework.
3    * Copyright (C) 1999-2015, 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.spi.ScanException;
28  
29  /**
30   * This class is a base class for HTMLLayout classes part of other logback
31   * 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      * Returns a map where the default converter map is merged with the map
102      * contained in the context.
103      */
104     public Map<String, String> getEffectiveConverterMap() {
105         Map<String, String> effectiveMap = new HashMap<String, String>();
106 
107         // add the least specific map fist
108         Map<String, String> defaultMap = getDefaultConverterMap();
109         if (defaultMap != null) {
110             effectiveMap.putAll(defaultMap);
111         }
112 
113         // contextMap is more specific than the default map
114         Context context = getContext();
115         if (context != null) {
116             @SuppressWarnings("unchecked")
117             Map<String, String> contextMap = (Map<String, String>) context
118                     .getObject(CoreConstants.PATTERN_RULE_REGISTRY);
119             if (contextMap != null) {
120                 effectiveMap.putAll(contextMap);
121             }
122         }
123         return effectiveMap;
124     }
125 
126     /**
127      * The <b>Title </b> option takes a String value. This option sets the document
128      * title of the generated HTML document.
129      * 
130      * <p>
131      * Defaults to 'Logback Log Messages'.
132      */
133     public void setTitle(String title) {
134         this.title = title;
135     }
136 
137     /**
138      * Returns the current value of the <b>Title </b> option.
139      */
140     public String getTitle() {
141         return title;
142     }
143 
144     /**
145      * Returns the content type output by this layout, i.e "text/html".
146      */
147     @Override
148     public String getContentType() {
149         return "text/html";
150     }
151 
152     /**
153      * Returns appropriate HTML headers.
154      */
155     @Override
156     public String getFileHeader() {
157         StringBuilder sbuf = new StringBuilder();
158         sbuf.append("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"");
159         sbuf.append(" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">");
160         sbuf.append(LINE_SEPARATOR);
161         sbuf.append("<html>");
162         sbuf.append(LINE_SEPARATOR);
163         sbuf.append("  <head>");
164         sbuf.append(LINE_SEPARATOR);
165         sbuf.append("    <title>");
166         sbuf.append(title);
167         sbuf.append("</title>");
168         sbuf.append(LINE_SEPARATOR);
169 
170         cssBuilder.addCss(sbuf);
171 
172         sbuf.append(LINE_SEPARATOR);
173         sbuf.append("  </head>");
174         sbuf.append(LINE_SEPARATOR);
175         sbuf.append("<body>");
176         sbuf.append(LINE_SEPARATOR);
177 
178         return sbuf.toString();
179     }
180 
181     public String getPresentationHeader() {
182         StringBuilder sbuf = new StringBuilder();
183         sbuf.append("<hr/>");
184         sbuf.append(LINE_SEPARATOR);
185         sbuf.append("<p>Log session start time ");
186         sbuf.append(new java.util.Date());
187         sbuf.append("</p><p></p>");
188         sbuf.append(LINE_SEPARATOR);
189         sbuf.append(LINE_SEPARATOR);
190         sbuf.append("<table cellspacing=\"0\">");
191         sbuf.append(LINE_SEPARATOR);
192 
193         buildHeaderRowForTable(sbuf);
194 
195         return sbuf.toString();
196     }
197 
198     private void buildHeaderRowForTable(StringBuilder sbuf) {
199         Converter<E> c = head;
200         String name;
201         sbuf.append("<tr class=\"header\">");
202         sbuf.append(LINE_SEPARATOR);
203         while (c != null) {
204             name = computeConverterName(c);
205             if (name == null) {
206                 c = c.getNext();
207                 continue;
208             }
209             sbuf.append("<td class=\"");
210             sbuf.append(computeConverterName(c));
211             sbuf.append("\">");
212             sbuf.append(computeConverterName(c));
213             sbuf.append("</td>");
214             sbuf.append(LINE_SEPARATOR);
215             c = c.getNext();
216         }
217         sbuf.append("</tr>");
218         sbuf.append(LINE_SEPARATOR);
219     }
220 
221     public String getPresentationFooter() {
222         StringBuilder sbuf = new StringBuilder();
223         sbuf.append("</table>");
224         return sbuf.toString();
225     }
226 
227     /**
228      * Returns the appropriate HTML footers.
229      */
230     @Override
231     public String getFileFooter() {
232         StringBuilder sbuf = new StringBuilder();
233         sbuf.append(LINE_SEPARATOR);
234         sbuf.append("</body></html>");
235         return sbuf.toString();
236     }
237 
238     protected void startNewTableIfLimitReached(StringBuilder sbuf) {
239         if (this.counter >= CoreConstants.TABLE_ROW_LIMIT) {
240             counter = 0;
241             sbuf.append("</table>");
242             sbuf.append(LINE_SEPARATOR);
243             sbuf.append("<p></p>");
244             sbuf.append("<table cellspacing=\"0\">");
245             sbuf.append(LINE_SEPARATOR);
246             buildHeaderRowForTable(sbuf);
247         }
248     }
249 
250     protected String computeConverterName(Converter<E> c) {
251         String className = c.getClass().getSimpleName();
252         int index = className.indexOf("Converter");
253         if (index == -1) {
254             return className;
255         } else {
256             return className.substring(0, index);
257         }
258     }
259 
260 }