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 }
157