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.pattern;
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 ch.qos.logback.core.LayoutBase;
22  import ch.qos.logback.core.pattern.parser.Node;
23  import ch.qos.logback.core.pattern.parser.Parser;
24  import ch.qos.logback.core.spi.ScanException;
25  import ch.qos.logback.core.status.ErrorStatus;
26  import ch.qos.logback.core.status.StatusManager;
27  
28  abstract public class PatternLayoutBase<E> extends LayoutBase<E> {
29  
30      static final int INTIAL_STRING_BUILDER_SIZE = 256;
31      Converter<E> head;
32      String pattern;
33      protected PostCompileProcessor<E> postCompileProcessor;
34  
35      Map<String, String> instanceConverterMap = new HashMap<String, String>();
36      protected boolean outputPatternAsHeader = false;
37  
38      /**
39       * Concrete implementations of this class are responsible for elaborating the
40       * mapping between pattern words and converters.
41       * 
42       * @return A map associating pattern words to the names of converter classes
43       */
44      abstract public Map<String, String> getDefaultConverterMap();
45  
46      /**
47       * Returns a map where the default converter map is merged with the map
48       * contained in the context.
49       */
50      public Map<String, String> getEffectiveConverterMap() {
51          Map<String, String> effectiveMap = new HashMap<String, String>();
52  
53          // add the least specific map fist
54          Map<String, String> defaultMap = getDefaultConverterMap();
55          if (defaultMap != null) {
56              effectiveMap.putAll(defaultMap);
57          }
58  
59          // contextMap is more specific than the default map
60          Context context = getContext();
61          if (context != null) {
62              @SuppressWarnings("unchecked")
63              Map<String, String> contextMap = (Map<String, String>) context
64                      .getObject(CoreConstants.PATTERN_RULE_REGISTRY);
65              if (contextMap != null) {
66                  effectiveMap.putAll(contextMap);
67              }
68          }
69          // set the most specific map last
70          effectiveMap.putAll(instanceConverterMap);
71          return effectiveMap;
72      }
73  
74      public void start() {
75          if (pattern == null || pattern.length() == 0) {
76              addError("Empty or null pattern.");
77              return;
78          }
79          try {
80              Parser<E> p = new Parser<E>(pattern);
81              if (getContext() != null) {
82                  p.setContext(getContext());
83              }
84              Node t = p.parse();
85              this.head = p.compile(t, getEffectiveConverterMap());
86              if (postCompileProcessor != null) {
87                  postCompileProcessor.process(context, head);
88              }
89              ConverterUtil.setContextForConverters(getContext(), head);
90              ConverterUtil.startConverters(this.head);
91              super.start();
92          } catch (ScanException sce) {
93              StatusManager sm = getContext().getStatusManager();
94              sm.add(new ErrorStatus("Failed to parse pattern \"" + getPattern() + "\".", this, sce));
95          }
96      }
97  
98      public void setPostCompileProcessor(PostCompileProcessor<E> postCompileProcessor) {
99          this.postCompileProcessor = postCompileProcessor;
100     }
101 
102     /**
103      *
104      * @param head
105      * @deprecated Use {@link ConverterUtil#setContextForConverters} instead. This
106      *             method will be removed in future releases.
107      */
108     protected void setContextForConverters(Converter<E> head) {
109         ConverterUtil.setContextForConverters(getContext(), head);
110     }
111 
112     protected String writeLoopOnConverters(E event) {
113         StringBuilder strBuilder = new StringBuilder(INTIAL_STRING_BUILDER_SIZE);
114         Converter<E> c = head;
115         while (c != null) {
116             c.write(strBuilder, event);
117             c = c.getNext();
118         }
119         return strBuilder.toString();
120     }
121 
122     public String getPattern() {
123         return pattern;
124     }
125 
126     public void setPattern(String pattern) {
127         this.pattern = pattern;
128     }
129 
130     public String toString() {
131         return this.getClass().getName() + "(\"" + getPattern() + "\")";
132     }
133 
134     public Map<String, String> getInstanceConverterMap() {
135         return instanceConverterMap;
136     }
137 
138     protected String getPresentationHeaderPrefix() {
139         return CoreConstants.EMPTY_STRING;
140     }
141 
142     public boolean isOutputPatternAsHeader() {
143         return outputPatternAsHeader;
144     }
145 
146     public void setOutputPatternAsHeader(boolean outputPatternAsHeader) {
147         this.outputPatternAsHeader = outputPatternAsHeader;
148     }
149 
150     @Override
151     public String getPresentationHeader() {
152         if (outputPatternAsHeader)
153             return getPresentationHeaderPrefix() + pattern;
154         else
155             return super.getPresentationHeader();
156     }
157 }