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