package org.eluder.logback.ext.core;
/*
* #[license]
* logback-ext-core
* %%
* Copyright (C) 2014 - 2015 Tapio Rautonen
* %%
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
* %[license]
*/
import ch.qos.logback.core.Context;
import ch.qos.logback.core.Layout;
import ch.qos.logback.core.UnsynchronizedAppenderBase;
import ch.qos.logback.core.encoder.Encoder;
import ch.qos.logback.core.encoder.LayoutWrappingEncoder;
import ch.qos.logback.core.spi.DeferredProcessingAware;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.concurrent.locks.ReentrantLock;
import static java.lang.String.format;
public abstract class EncodingStringAppender<E extends DeferredProcessingAware, P> extends UnsynchronizedAppenderBase<E> {
protected final ReentrantLock lock = new ReentrantLock(true);
private Charset charset = Charset.forName("UTF-8");
private boolean binary = false;
private Encoder<E> encoder;
private PayloadConverter<P> converter;
public final void setCharset(Charset charset) {
if (encoder instanceof LayoutWrappingEncoder) {
((LayoutWrappingEncoder<?>) encoder).setCharset(charset);
} else if (encoder instanceof CharacterEncoder) {
((CharacterEncoder<?>) encoder).setCharset(charset);
}
this.charset = charset;
}
public final void setBinary(boolean binary) {
if (binary) {
addInfo(format("Appender '%s' is set to binary mode, events are converted to Base64 strings", getName()));
}
this.binary = binary;
}
public final void setEncoder(Encoder<E> encoder) {
this.encoder = encoder;
setContext(context);
setCharset(charset);
}
public final void setLayout(Layout<E> layout) {
LayoutWrappingEncoder<E> enc = new LayoutWrappingEncoder<>();
enc.setLayout(layout);
setEncoder(enc);
}
public final void setConverter(PayloadConverter<P> converter) {
this.converter = converter;
}
@Override
public void setContext(Context context) {
if (encoder != null) {
encoder.setContext(context);
}
super.setContext(context);
}
protected final Charset getCharset() {
return charset;
}
protected final boolean isBinary() {
return binary;
}
protected final Encoder<E> getEncoder() {
return encoder;
}
@Override
public void start() {
if (encoder == null) {
addError(format("Encoder not set for appender '%s'", getName()));
return;
}
if (converter == null) {
addError(format("Converter not set for appender '%s'", getName()));
return;
}
lock.lock();
try {
encoder.start();
super.start();
} finally {
lock.unlock();
}
}
@Override
public void stop() {
lock.lock();
try {
super.stop();
if (encoder != null) {
encoder.stop();
}
} finally {
lock.unlock();
}
}
@Override
protected void append(E event) {
ByteArrayOutputStream stream = new ByteArrayOutputStream();
encode(event, stream);
doHandle(event, convert(stream.toByteArray()));
}
private void encode(E event, ByteArrayOutputStream stream) {
lock.lock();
try {
encoderInit(stream);
try {
doEncode(event);
} finally {
encoderClose();
}
} finally {
lock.unlock();
}
}
protected abstract void handle(E event, P encoded) throws Exception;
protected P convert(byte[] payload) {
return converter.convert(payload);
}
protected void doHandle(E event, P encoded) {
try {
if (encoded != null) {
handle(event, encoded);
}
} catch (Exception ex) {
this.started = false;
addError(format("Failed to handle logging event for '%s'", getName()), ex);
}
}
protected void doEncode(E event) {
try {
encoder.doEncode(event);
} catch (IOException ex) {
this.started = false;
addError(format("Failed to encode logging event for appender '%s'", getName()), ex);
}
}
protected void encoderInit(ByteArrayOutputStream stream) {
try {
encoder.init(stream);
} catch (IOException ex) {
this.started = false;
addError(format("Failed to initialize encoder for appender '%s'", getName()), ex);
}
}
protected void encoderClose() {
try {
encoder.close();
} catch (Exception ex) {
this.started = false;
addError(format("Failed to close encoder for appender '%s'", getName()), ex);
}
}
}