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.getObject(CoreConstants.PATTERN_RULE_REGISTRY);
64              if (contextMap != null) {
65                  effectiveMap.putAll(contextMap);
66              }
67          }
68          // set the most specific map last
69          effectiveMap.putAll(instanceConverterMap);
70          return effectiveMap;
71      }
72  
73      public void start() {
74          if (pattern == null || pattern.length() == 0) {
75              addError("Empty or null pattern.");
76              return;
77          }
78          try {
79              Parser<E> p = new Parser<E>(pattern);
80              if (getContext() != null) {
81                  p.setContext(getContext());
82              }
83              Node t = p.parse();
84              this.head = p.compile(t, getEffectiveConverterMap());
85              if (postCompileProcessor != null) {
86                  postCompileProcessor.process(context, head);
87              }
88              ConverterUtil.setContextForConverters(getContext(), head);
89              ConverterUtil.startConverters(this.head);
90              super.start();
91          } catch (ScanException sce) {
92              StatusManager sm = getContext().getStatusManager();
93              sm.add(new ErrorStatus("Failed to parse pattern \"" + getPattern() + "\".", this, sce));
94          }
95      }
96  
97      public void setPostCompileProcessor(PostCompileProcessor<E> postCompileProcessor) {
98          this.postCompileProcessor = postCompileProcessor;
99      }
100 
101     /**
102      *
103      * @param head
104      * @deprecated  Use {@link ConverterUtil#setContextForConverters} instead. This method will
105      *  be removed in future releases.
106      */
107     protected void setContextForConverters(Converter<E> head) {
108         ConverterUtil.setContextForConverters(getContext(), head);
109     }
110 
111     protected String writeLoopOnConverters(E event) {
112         StringBuilder strBuilder = new StringBuilder(INTIAL_STRING_BUILDER_SIZE);
113         Converter<E> c = head;
114         while (c != null) {
115             c.write(strBuilder, event);
116             c = c.getNext();
117         }
118         return strBuilder.toString();
119     }
120 
121     public String getPattern() {
122         return pattern;
123     }
124 
125     public void setPattern(String pattern) {
126         this.pattern = pattern;
127     }
128 
129     public String toString() {
130         return this.getClass().getName() + "(\"" + getPattern() + "\")";
131     }
132 
133     public Map<String, String> getInstanceConverterMap() {
134         return instanceConverterMap;
135     }
136 
137     protected String getPresentationHeaderPrefix() {
138         return CoreConstants.EMPTY_STRING;
139     }
140 
141     public boolean isOutputPatternAsHeader() {
142         return outputPatternAsHeader;
143     }
144 
145     public void setOutputPatternAsHeader(boolean outputPatternAsHeader) {
146         this.outputPatternAsHeader = outputPatternAsHeader;
147     }
148 
149     @Override
150     public String getPresentationHeader() {
151         if (outputPatternAsHeader)
152             return getPresentationHeaderPrefix() + pattern;
153         else
154             return super.getPresentationHeader();
155     }
156 }