1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.logging.log4j.core.layout;
18
19 import java.io.IOException;
20 import java.io.ObjectInputStream;
21 import java.io.ObjectOutputStream;
22 import java.io.UnsupportedEncodingException;
23 import java.nio.charset.Charset;
24 import java.nio.charset.StandardCharsets;
25
26 import org.apache.logging.log4j.core.LogEvent;
27 import org.apache.logging.log4j.core.StringLayout;
28 import org.apache.logging.log4j.core.util.StringEncoder;
29
30
31
32
33
34
35
36
37
38
39
40 public abstract class AbstractStringLayout extends AbstractLayout<String> implements StringLayout {
41
42
43
44
45 protected static final int DEFAULT_STRING_BUILDER_SIZE = 1024;
46
47 private final static ThreadLocal<StringBuilder> threadLocal = new ThreadLocal<>();
48
49 private static final long serialVersionUID = 1L;
50
51
52
53
54
55 private transient Charset charset;
56 private final String charsetName;
57 private final boolean useCustomEncoding;
58
59 protected AbstractStringLayout(final Charset charset) {
60 this(charset, null, null);
61 }
62
63
64
65
66
67
68
69
70 protected AbstractStringLayout(final Charset charset, final byte[] header, final byte[] footer) {
71 super(header, footer);
72 this.charset = charset == null ? StandardCharsets.UTF_8 : charset;
73 this.charsetName = this.charset.name();
74 useCustomEncoding = isPreJava8()
75 && (StandardCharsets.ISO_8859_1.equals(charset) || StandardCharsets.US_ASCII.equals(charset));
76 }
77
78
79 private static boolean isPreJava8() {
80 final String version = System.getProperty("java.version");
81 final String[] parts = version.split("\\.");
82 try {
83 int major = Integer.parseInt(parts[1]);
84 return major < 8;
85 } catch (Exception ex) {
86 return true;
87 }
88 }
89
90 private void writeObject(final ObjectOutputStream out) throws IOException {
91 out.defaultWriteObject();
92 out.writeUTF(charset.name());
93 }
94
95 private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException {
96 in.defaultReadObject();
97 final String csName = in.readUTF();
98 charset = Charset.forName(csName);
99 }
100
101
102
103
104
105
106 protected StringBuilder getStringBuilder() {
107 StringBuilder result = threadLocal.get();
108 if (result == null) {
109 result = new StringBuilder(DEFAULT_STRING_BUILDER_SIZE);
110 threadLocal.set(result);
111 }
112 result.setLength(0);
113 return result;
114 }
115
116 protected byte[] getBytes(final String s) {
117 if (useCustomEncoding) {
118 return StringEncoder.encodeSingleByteChars(s);
119 }
120 try {
121 return s.getBytes(charsetName);
122 } catch (UnsupportedEncodingException e) {
123 return s.getBytes(charset);
124 }
125 }
126
127 @Override
128 public Charset getCharset() {
129 return charset;
130 }
131
132
133
134
135 @Override
136 public String getContentType() {
137 return "text/plain";
138 }
139
140
141
142
143
144
145
146 @Override
147 public byte[] toByteArray(final LogEvent event) {
148 return getBytes(toSerializable(event));
149 }
150
151 }