View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements. See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache license, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License. You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the license for the specific language governing permissions and
15   * limitations under the license.
16   */
17  package org.apache.logging.log4j.core.layout;
18  
19  import org.apache.logging.log4j.core.util.Constants;
20  import org.apache.logging.log4j.status.StatusLogger;
21  
22  import java.nio.CharBuffer;
23  import java.nio.charset.Charset;
24  import java.nio.charset.CharsetEncoder;
25  import java.nio.charset.CodingErrorAction;
26  import java.util.Objects;
27  
28  /**
29   * Encoder for StringBuilders that locks on the ByteBufferDestination.
30   */
31  public class LockingStringBuilderEncoder implements Encoder<StringBuilder> {
32  
33      private final Charset charset;
34      private final CharsetEncoder charsetEncoder;
35      private final CharBuffer cachedCharBuffer;
36  
37      public LockingStringBuilderEncoder(final Charset charset) {
38          this(charset, Constants.ENCODER_CHAR_BUFFER_SIZE);
39      }
40  
41      public LockingStringBuilderEncoder(final Charset charset, final int charBufferSize) {
42          this.charset = Objects.requireNonNull(charset, "charset");
43          this.charsetEncoder = charset.newEncoder().onMalformedInput(CodingErrorAction.REPLACE)
44                  .onUnmappableCharacter(CodingErrorAction.REPLACE);
45          this.cachedCharBuffer = CharBuffer.wrap(new char[charBufferSize]);
46      }
47  
48      private CharBuffer getCharBuffer() {
49          return cachedCharBuffer;
50      }
51  
52      @Override
53      public void encode(final StringBuilder source, final ByteBufferDestination destination) {
54          try {
55              // This synchronized is needed to be able to call destination.getByteBuffer()
56              synchronized (destination) {
57                  TextEncoderHelper.encodeText(charsetEncoder, cachedCharBuffer, destination.getByteBuffer(), source,
58                      destination);
59              }
60          } catch (final Exception ex) {
61              logEncodeTextException(ex, source, destination);
62              TextEncoderHelper.encodeTextFallBack(charset, source, destination);
63          }
64  
65      }
66  
67      private void logEncodeTextException(final Exception ex, final StringBuilder text,
68                                          final ByteBufferDestination destination) {
69          StatusLogger.getLogger().error("Recovering from LockingStringBuilderEncoder.encode('{}') error", text, ex);
70      }
71  }