From e310858ad75d8d8664b696c825d9a77b3282cebf Mon Sep 17 00:00:00 2001 From: rfoltyns Date: Wed, 10 Feb 2021 18:18:15 +0000 Subject: [PATCH] SingleThreadJsonFactory extracted to org.appenders.st:appenders-jackson-st:1.0 (#56) * In order to avoid package-related issues in OSGi environments, custom Jackson FasterXML JsonFactory was extracted to separate module --- log4j2-elasticsearch-core/README.md | 2 +- log4j2-elasticsearch-core/pom.xml | 4 + .../DataOutputAsStreamDelegate.java | 62 ---- .../elasticsearch/JacksonJsonLayout.java | 6 +- .../JsonWriteContextAccessor.java | 51 --- .../elasticsearch/OutputStreamDelegate.java | 65 ---- .../elasticsearch/ReusableIOContext.java | 48 --- .../ReusableUTF8JsonGenerator.java | 100 ------ .../SingleThreadJsonFactory.java | 202 ------------ .../SingleThreadJsonFactoryProvider.java | 12 + .../json/ReusableUTF8JsonGeneratorTest.java | 279 ---------------- .../DataOutputAsStreamDelegateTest.java | 99 ------ .../elasticsearch/JacksonJsonLayoutTest.java | 1 + .../JsonWriteContextAccessorTest.java | 68 ---- .../OutputStreamDelegateTest.java | 114 ------- .../elasticsearch/ReusableIOContextTest.java | 58 ---- .../SingleThreadJsonFactoryProviderTest.java | 24 ++ .../SingleThreadJsonFactoryTest.java | 298 ------------------ pom.xml | 6 + 19 files changed, 51 insertions(+), 1448 deletions(-) delete mode 100644 log4j2-elasticsearch-core/src/main/java/org/appenders/log4j2/elasticsearch/DataOutputAsStreamDelegate.java delete mode 100644 log4j2-elasticsearch-core/src/main/java/org/appenders/log4j2/elasticsearch/JsonWriteContextAccessor.java delete mode 100644 log4j2-elasticsearch-core/src/main/java/org/appenders/log4j2/elasticsearch/OutputStreamDelegate.java delete mode 100644 log4j2-elasticsearch-core/src/main/java/org/appenders/log4j2/elasticsearch/ReusableIOContext.java delete mode 100644 log4j2-elasticsearch-core/src/main/java/org/appenders/log4j2/elasticsearch/ReusableUTF8JsonGenerator.java delete mode 100644 log4j2-elasticsearch-core/src/main/java/org/appenders/log4j2/elasticsearch/SingleThreadJsonFactory.java create mode 100644 log4j2-elasticsearch-core/src/main/java/org/appenders/log4j2/elasticsearch/SingleThreadJsonFactoryProvider.java delete mode 100644 log4j2-elasticsearch-core/src/test/java/com/fasterxml/jackson/core/json/ReusableUTF8JsonGeneratorTest.java delete mode 100644 log4j2-elasticsearch-core/src/test/java/org/appenders/log4j2/elasticsearch/DataOutputAsStreamDelegateTest.java delete mode 100644 log4j2-elasticsearch-core/src/test/java/org/appenders/log4j2/elasticsearch/JsonWriteContextAccessorTest.java delete mode 100644 log4j2-elasticsearch-core/src/test/java/org/appenders/log4j2/elasticsearch/OutputStreamDelegateTest.java delete mode 100644 log4j2-elasticsearch-core/src/test/java/org/appenders/log4j2/elasticsearch/ReusableIOContextTest.java create mode 100644 log4j2-elasticsearch-core/src/test/java/org/appenders/log4j2/elasticsearch/SingleThreadJsonFactoryProviderTest.java delete mode 100644 log4j2-elasticsearch-core/src/test/java/org/appenders/log4j2/elasticsearch/SingleThreadJsonFactoryTest.java diff --git a/log4j2-elasticsearch-core/README.md b/log4j2-elasticsearch-core/README.md index 9fa46531..d3de77c2 100644 --- a/log4j2-elasticsearch-core/README.md +++ b/log4j2-elasticsearch-core/README.md @@ -260,7 +260,7 @@ Furthermore, [ItemSource API](#itemsource-api) allows to use pooled [ByteByfItem Config property | Type | Required | Default | Description ------------ | ------------- | ------------- | ------------- | ------------- afterburner | Attribute | no | false | if `true`, `com.fasterxml.jackson.module:jackson-module-afterburner` will be used to optimize (de)serialization. Since this dependency is in `provided` scope by default, it MUST be declared explicitly. -singleThread | Attribute | no | false | Use ONLY with `AsyncLogger`. If `true`, `com.fasterxml.jackson.core.JsonFactory` will be replaced with [SingleThreadJsonFactory](https://github.com/rfoltyns/log4j2-elasticsearch/blob/master/log4j2-elasticsearch-core/src/main/java/org/appenders/log4j2/elasticsearch/SingleThreadJsonFactory.java) for `LogEvent` serialization. Offers slightly better serialization throughput. +singleThread | Attribute | no | false | Use ONLY with `AsyncLogger`. If `true`, `com.fasterxml.jackson.core.JsonFactory` will be replaced with [SingleThreadJsonFactory](https://github.com/appenders/appenders-jackson-st/blob/main/src/main/java/org/appenders/st/jackson/SingleThreadJsonFactory.java) for `LogEvent` serialization. Offers slightly better serialization throughput. mixins | Element(s) | no | None | Array of `JacksonMixIn` elements. Can be used to override default serialization of LogEvent, Message and related objects virtualProperties (since 1.4) | Element(s) | no | None | Array of `VirtualProperty` elements. Similar to `KeyValuePair`, can be used to define properties resolvable on the fly, not available in LogEvent(s). virtualPropertiesFilter (since 1.4.3) | Element(s) | no | None | Array of `VirtualPropertyFilter` elements, can be used to include/exclude `VirtualProperty` dynamically. diff --git a/log4j2-elasticsearch-core/pom.xml b/log4j2-elasticsearch-core/pom.xml index bc0af21b..c2c67273 100644 --- a/log4j2-elasticsearch-core/pom.xml +++ b/log4j2-elasticsearch-core/pom.xml @@ -12,6 +12,10 @@ Log4j Appenders pushing logs in batches to Elasticsearch clusters + + org.appenders.st + appenders-jackson-st + org.apache.logging.log4j log4j-core diff --git a/log4j2-elasticsearch-core/src/main/java/org/appenders/log4j2/elasticsearch/DataOutputAsStreamDelegate.java b/log4j2-elasticsearch-core/src/main/java/org/appenders/log4j2/elasticsearch/DataOutputAsStreamDelegate.java deleted file mode 100644 index 1d20608a..00000000 --- a/log4j2-elasticsearch-core/src/main/java/org/appenders/log4j2/elasticsearch/DataOutputAsStreamDelegate.java +++ /dev/null @@ -1,62 +0,0 @@ -package org.appenders.log4j2.elasticsearch; - -/*- - * #%L - * log4j2-elasticsearch - * %% - * Copyright (C) 2020 Rafal Foltynski - * %% - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * #L% - */ - -import com.fasterxml.jackson.core.io.DataOutputAsStream; -import org.jetbrains.annotations.NotNull; - -import java.io.DataOutput; -import java.io.IOException; - -public class DataOutputAsStreamDelegate extends DataOutputAsStream { - - private DataOutput delegate; - - public DataOutputAsStreamDelegate(DataOutput dataOutput) { - super(dataOutput); - this.delegate = dataOutput; - } - - /* visible for testing */ - DataOutput getDelegate() { - return delegate; - } - - public void setDelegate(DataOutput delegate) { - this.delegate = delegate; - } - - @Override - public void write(int b) throws IOException { - delegate.write(b); - } - - @Override - public void write(@NotNull byte[] b) throws IOException { - delegate.write(b); - } - - @Override - public void write(@NotNull byte[] b, int off, int len) throws IOException { - delegate.write(b, off, len); - } - -} diff --git a/log4j2-elasticsearch-core/src/main/java/org/appenders/log4j2/elasticsearch/JacksonJsonLayout.java b/log4j2-elasticsearch-core/src/main/java/org/appenders/log4j2/elasticsearch/JacksonJsonLayout.java index f94444f3..f87c65d2 100644 --- a/log4j2-elasticsearch-core/src/main/java/org/appenders/log4j2/elasticsearch/JacksonJsonLayout.java +++ b/log4j2-elasticsearch-core/src/main/java/org/appenders/log4j2/elasticsearch/JacksonJsonLayout.java @@ -241,7 +241,7 @@ protected ObjectMapper createDefaultObjectMapper() { protected JsonFactory createJsonFactory() { if (singleThread) { - return new SingleThreadJsonFactory(); + return new SingleThreadJsonFactoryProvider().create(); } return new JsonFactory(); } @@ -307,12 +307,12 @@ public Builder withAfterburner(boolean useAfterburner) { } /** - * Allows to configure {@link SingleThreadJsonFactory} + * Allows to configure {@code org.appenders.st.jackson.SingleThreadJsonFactory} * * NOTE: Use ONLY when {@link JacksonJsonLayout#serialize(LogEvent)}/{@link JacksonJsonLayout#serialize(Message)} * are called exclusively by a one thread at a time, e.g. with AsyncLogger * - * @param singleThread if true, {@link SingleThreadJsonFactory} will be used to create serializers, + * @param singleThread if true, {@code org.appenders.st.jackson.SingleThreadJsonFactory} will be used to create serializers, * otherwise {@code com.fasterxml.jackson.core.JsonFactory} will be used * @return this */ diff --git a/log4j2-elasticsearch-core/src/main/java/org/appenders/log4j2/elasticsearch/JsonWriteContextAccessor.java b/log4j2-elasticsearch-core/src/main/java/org/appenders/log4j2/elasticsearch/JsonWriteContextAccessor.java deleted file mode 100644 index ce07835c..00000000 --- a/log4j2-elasticsearch-core/src/main/java/org/appenders/log4j2/elasticsearch/JsonWriteContextAccessor.java +++ /dev/null @@ -1,51 +0,0 @@ -package org.appenders.log4j2.elasticsearch; - -/*- - * #%L - * log4j2-elasticsearch - * %% - * Copyright (C) 2020 Rafal Foltynski - * %% - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * #L% - */ - -import com.fasterxml.jackson.core.json.JsonWriteContext; - -import static com.fasterxml.jackson.core.JsonStreamContext.TYPE_ROOT; - -/** - * Helper class to allow {@code com.fasterxml.jackson.core.json.JsonWriteContext} state access. - */ -public class JsonWriteContextAccessor { - - public JsonWriteContext reset(JsonWriteContext ctx) { - - if (ctx.getParent() == null) { - return ctx.reset(TYPE_ROOT); - } - - // Write context may be left unclosed, so.. - JsonWriteContext parent = ctx.getParent(); - while (parent.getParent() != null) { - parent = parent.getParent(); - } - - return parent.reset(TYPE_ROOT); - } - - /* visible for testing */ - boolean inRoot(JsonWriteContext ctxAfterReset) { - return ctxAfterReset.inRoot(); - } -} diff --git a/log4j2-elasticsearch-core/src/main/java/org/appenders/log4j2/elasticsearch/OutputStreamDelegate.java b/log4j2-elasticsearch-core/src/main/java/org/appenders/log4j2/elasticsearch/OutputStreamDelegate.java deleted file mode 100644 index 30679fd4..00000000 --- a/log4j2-elasticsearch-core/src/main/java/org/appenders/log4j2/elasticsearch/OutputStreamDelegate.java +++ /dev/null @@ -1,65 +0,0 @@ -package org.appenders.log4j2.elasticsearch; - -/*- - * #%L - * log4j2-elasticsearch - * %% - * Copyright (C) 2020 Rafal Foltynski - * %% - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * #L% - */ - -import org.jetbrains.annotations.NotNull; - -import java.io.IOException; -import java.io.OutputStream; - -public class OutputStreamDelegate extends OutputStream { - - private OutputStream delegate; - - public OutputStreamDelegate(OutputStream outputStream) { - this.delegate = outputStream; - } - - /* visible for testing */ - OutputStream getDelegate() { - return delegate; - } - - public void setDelegate(OutputStream delegate) { - this.delegate = delegate; - } - - @Override - public void write(int b) throws IOException { - delegate.write(b); - } - - @Override - public void write(@NotNull byte[] b) throws IOException { - delegate.write(b); - } - - @Override - public void write(@NotNull byte[] b, int off, int len) throws IOException { - delegate.write(b, off, len); - } - - @Override - public void close() throws IOException { - delegate.close(); - } - -} diff --git a/log4j2-elasticsearch-core/src/main/java/org/appenders/log4j2/elasticsearch/ReusableIOContext.java b/log4j2-elasticsearch-core/src/main/java/org/appenders/log4j2/elasticsearch/ReusableIOContext.java deleted file mode 100644 index e799063a..00000000 --- a/log4j2-elasticsearch-core/src/main/java/org/appenders/log4j2/elasticsearch/ReusableIOContext.java +++ /dev/null @@ -1,48 +0,0 @@ -package org.appenders.log4j2.elasticsearch; - -/*- - * #%L - * log4j2-elasticsearch - * %% - * Copyright (C) 2020 Rafal Foltynski - * %% - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * #L% - */ - -import com.fasterxml.jackson.core.JsonEncoding; -import com.fasterxml.jackson.core.io.IOContext; -import com.fasterxml.jackson.core.util.BufferRecycler; - -import java.io.OutputStream; - -public class ReusableIOContext extends IOContext { - - private OutputStream sourceRefReplacement; - - public ReusableIOContext(BufferRecycler br, OutputStream sourceRef, boolean managedResource) { - super(br, sourceRef, managedResource); - setEncoding(JsonEncoding.UTF8); // Not supported otherwise - this.sourceRefReplacement = sourceRef; - } - - @Override - public Object getSourceReference() { - return this.sourceRefReplacement; - } - - public void setSourceReference(OutputStream replacement) { - this.sourceRefReplacement = replacement; - } - -} diff --git a/log4j2-elasticsearch-core/src/main/java/org/appenders/log4j2/elasticsearch/ReusableUTF8JsonGenerator.java b/log4j2-elasticsearch-core/src/main/java/org/appenders/log4j2/elasticsearch/ReusableUTF8JsonGenerator.java deleted file mode 100644 index 58f36ddb..00000000 --- a/log4j2-elasticsearch-core/src/main/java/org/appenders/log4j2/elasticsearch/ReusableUTF8JsonGenerator.java +++ /dev/null @@ -1,100 +0,0 @@ -package org.appenders.log4j2.elasticsearch; - -/*- - * #%L - * log4j2-elasticsearch - * %% - * Copyright (C) 2020 Rafal Foltynski - * %% - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * #L% - */ - -import com.fasterxml.jackson.core.JsonStreamContext; -import com.fasterxml.jackson.core.ObjectCodec; -import com.fasterxml.jackson.core.io.IOContext; -import com.fasterxml.jackson.core.json.UTF8JsonGenerator; - -import java.io.IOException; -import java.io.OutputStream; - -/** - * Instances of this class can be used again after {@link #close()} - */ -public class ReusableUTF8JsonGenerator extends UTF8JsonGenerator { - - private final JsonWriteContextAccessor jsonWriteCtxAccess; - - public ReusableUTF8JsonGenerator( - IOContext ctxt, - int generatorFeatures, - ObjectCodec objectCodec, - OutputStream outputStream, - char _quoteChar, - JsonWriteContextAccessor jsonWriteCtxAccess) { - super(ctxt, generatorFeatures, objectCodec, outputStream, _quoteChar); - this.jsonWriteCtxAccess = jsonWriteCtxAccess; - } - - /** - * Resets for new write. - *
- * Does NOT release buffers. - *
- *

{@code com.fasterxml.jackson.core.JsonGenerator.Feature.AUTO_CLOSE_JSON_CONTENT} supported

- *

{@code com.fasterxml.jackson.core.JsonGenerator.Feature.AUTO_CLOSE_TARGET} supported

- *

{@code com.fasterxml.jackson.core.JsonGenerator.Feature.FLUSH_PASSED_TO_STREAM} supported

- */ - @Override - public void close() throws IOException { - - // rfoltyns: Not closing actually. _closed still false here - - // rfoltyns: _releaseBuffers() never called -> _outputBuffer never null - if (isEnabled(Feature.AUTO_CLOSE_JSON_CONTENT)) { - while (true) { - JsonStreamContext ctxt = getOutputContext(); - if (ctxt.inArray()) { - writeEndArray(); - } else if (ctxt.inObject()) { - writeEndObject(); - } else { - break; - } - } - } - _flushBuffer(); - _outputTail = 0; - - // rfoltyns: _outputStream never null here - if (isEnabled(Feature.AUTO_CLOSE_TARGET)) { - _outputStream.close(); - } else if (isEnabled(Feature.FLUSH_PASSED_TO_STREAM)) { - _outputStream.flush(); - } - - // rfoltyns: Don't release buffers, reusing whole instance here - - } - - /** - * Allows to reset underlying {@code _writeContext} before serializing new object. - * - * @return this - */ - public ReusableUTF8JsonGenerator reset() { - _writeContext = jsonWriteCtxAccess.reset(_writeContext); - return this; - } - -} diff --git a/log4j2-elasticsearch-core/src/main/java/org/appenders/log4j2/elasticsearch/SingleThreadJsonFactory.java b/log4j2-elasticsearch-core/src/main/java/org/appenders/log4j2/elasticsearch/SingleThreadJsonFactory.java deleted file mode 100644 index e37ec172..00000000 --- a/log4j2-elasticsearch-core/src/main/java/org/appenders/log4j2/elasticsearch/SingleThreadJsonFactory.java +++ /dev/null @@ -1,202 +0,0 @@ -package org.appenders.log4j2.elasticsearch; - -/*- - * #%L - * log4j2-elasticsearch - * %% - * Copyright (C) 2020 Rafal Foltynski - * %% - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * #L% - */ - -import com.fasterxml.jackson.core.JsonEncoding; -import com.fasterxml.jackson.core.JsonFactory; -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.core.ObjectCodec; -import com.fasterxml.jackson.core.io.CharacterEscapes; -import com.fasterxml.jackson.core.io.IOContext; -import com.fasterxml.jackson.core.util.DefaultPrettyPrinter; - -import java.io.DataOutput; -import java.io.File; -import java.io.IOException; -import java.io.OutputStream; -import java.io.UnsupportedEncodingException; -import java.io.Writer; - -/** - * Instances of this class are NOT thread safe! - *
- * Instances of {@code com.fasterxml.jackson.core.JsonGenerator} based - * writers created by this class are NOT tread safe! - *
- * Allows to reuse ONE(!) {@code com.fasterxml.jackson.core.JsonGenerator} - * for every {@link #_createUTF8Generator(OutputStream, IOContext)} call - * by replacing several relevant components with one-per-factory counterparts. - *
- * Unless accessed exclusively by a single thread at once, - * concurrent calls to writers based on this factory - * will eventually lead to serialization errors as - * instances of {@code com.fasterxml.jackson.core.io.IOContext} and - * {@code com.fasterxml.jackson.core.json.JsonWriteContext} are shared. - */ -public class SingleThreadJsonFactory extends JsonFactory { - - protected final DataOutputAsStreamDelegate dataOutputDelegate = new DataOutputAsStreamDelegate(null); - protected final OutputStreamDelegate outputStreamDelegate = new OutputStreamDelegate(dataOutputDelegate); - protected final JsonWriteContextAccessor writeCtxAccessor = new JsonWriteContextAccessor(); - protected final ReusableIOContext ioContext = new ReusableIOContext(_getBufferRecycler(), outputStreamDelegate, false); - protected final ReusableUTF8JsonGenerator jsonGenerator = singleThreadUTF8JsonGenerator(ioContext); - - /** - * Creates default, ready-to-use instance - */ - public SingleThreadJsonFactory() { - super(); - } - - /** - * Used by {@link #copy()}. - *
- * Copies only inherited fields. - * - * @param factory source factory - * @param codec codec to use with new factory - */ - public SingleThreadJsonFactory(SingleThreadJsonFactory factory, ObjectCodec codec) { - super(factory, codec); - } - - /** - * Not supported - * - * @param w irrelevant - * @return throws - * @throws UnsupportedOperationException {@code java.io.UnsupportedEncodingException} is always thrown here - */ - @Override - public JsonGenerator createGenerator(Writer w) { - throw new UnsupportedOperationException("Writer not supported. Use OutputStream"); - } - - /** - * Not supported - * - * @param f irrelevant - * @param enc irrelevant - * @return throws - * @throws UnsupportedOperationException {@code java.io.UnsupportedEncodingException} is always thrown here - */ - @Override - public JsonGenerator createGenerator(File f, JsonEncoding enc) { - throw new UnsupportedOperationException("File not supported. Use OutputStream"); - } - - /** - * Returns current {@code com.fasterxml.jackson.core.JsonGenerator} instance with new target. - * Supports UTF-8 only. - * - * @param out new {@code java.io.OutputStream} to write to - * @param enc MUST be UTF-8 - * @return write-ready {@code com.fasterxml.jackson.core.JsonGenerator} - * @throws IOException if {@code enc} is not UTF-8 - */ - @Override - public JsonGenerator createGenerator(OutputStream out, JsonEncoding enc) throws IOException { - - if (enc != JsonEncoding.UTF8) { - throw new UnsupportedEncodingException("Encoding not supported: " + enc.getJavaName()); - } - - return _createUTF8Generator(_decorate(out, ioContext), ioContext); - - } - - /** - * Replaces target of {@link #dataOutputDelegate} with new {@link java.io.DataOutput} - * - * @param out new {@code java.io.DataOutput} - * @return {@link #dataOutputDelegate} with new target - */ - @Override - protected OutputStream _createDataOutputWrapper(DataOutput out) { - dataOutputDelegate.setDelegate(out); - return dataOutputDelegate; - } - - /** - * Returns current {@code com.fasterxml.jackson.core.JsonGenerator} instance with new target - * - * @param out new {@code java.io.OutputStream} to write to - * @param ctxt omitted, reusing {@link #ioContext} - * @return write-ready {@code com.fasterxml.jackson.core.JsonGenerator} - * - */ - @Override - protected JsonGenerator _createUTF8Generator(OutputStream out, IOContext ctxt) { - outputStreamDelegate.setDelegate(out); - ioContext.setSourceReference(out); - return jsonGenerator.reset(); - } - - @Override - public final JsonFactory setCharacterEscapes(CharacterEscapes esc) { - - if (esc != null) { - super.setCharacterEscapes(esc); - jsonGenerator.setCharacterEscapes(getCharacterEscapes()); - } - - return this; - } - - /** - * Since it may allocate {@code com.fasterxml.jackson.core.SerializableString}, configure only once. - * - * @param sep new separator - * @return this - */ - @Override - public JsonFactory setRootValueSeparator(String sep) { - - if (!DefaultPrettyPrinter.DEFAULT_ROOT_VALUE_SEPARATOR.getValue().equals(sep)) { - super.setRootValueSeparator(sep); - jsonGenerator.setRootValueSeparator(_rootValueSeparator); - } - - return this; - } - - /** - * {@inheritDoc} - */ - @Override - public SingleThreadJsonFactory copy() - { - _checkInvalidCopy(SingleThreadJsonFactory.class); - return new SingleThreadJsonFactory(this, null); - } - - private ReusableUTF8JsonGenerator singleThreadUTF8JsonGenerator(IOContext ctxt) { - return new ReusableUTF8JsonGenerator( - ctxt, - _generatorFeatures, - _objectCodec, // FIXME: add ObjectCodecDelegate - outputStreamDelegate, - _quoteChar, - writeCtxAccessor - ); - } - -} diff --git a/log4j2-elasticsearch-core/src/main/java/org/appenders/log4j2/elasticsearch/SingleThreadJsonFactoryProvider.java b/log4j2-elasticsearch-core/src/main/java/org/appenders/log4j2/elasticsearch/SingleThreadJsonFactoryProvider.java new file mode 100644 index 00000000..7bb7bc84 --- /dev/null +++ b/log4j2-elasticsearch-core/src/main/java/org/appenders/log4j2/elasticsearch/SingleThreadJsonFactoryProvider.java @@ -0,0 +1,12 @@ +package org.appenders.log4j2.elasticsearch; + +import com.fasterxml.jackson.core.JsonFactory; +import org.appenders.st.jackson.SingleThreadJsonFactory; + +public final class SingleThreadJsonFactoryProvider { + + public JsonFactory create() { + return new SingleThreadJsonFactory(); + } + +} diff --git a/log4j2-elasticsearch-core/src/test/java/com/fasterxml/jackson/core/json/ReusableUTF8JsonGeneratorTest.java b/log4j2-elasticsearch-core/src/test/java/com/fasterxml/jackson/core/json/ReusableUTF8JsonGeneratorTest.java deleted file mode 100644 index bd0e66b9..00000000 --- a/log4j2-elasticsearch-core/src/test/java/com/fasterxml/jackson/core/json/ReusableUTF8JsonGeneratorTest.java +++ /dev/null @@ -1,279 +0,0 @@ -package com.fasterxml.jackson.core.json; - -/*- - * #%L - * log4j2-elasticsearch - * %% - * Copyright (C) 2020 Rafal Foltynski - * %% - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * #L% - */ - -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.core.util.BufferRecycler; -import com.fasterxml.jackson.databind.ObjectMapper; -import org.appenders.log4j2.elasticsearch.JsonWriteContextAccessor; -import org.appenders.log4j2.elasticsearch.OutputStreamDelegate; -import org.appenders.log4j2.elasticsearch.ReusableIOContext; -import org.appenders.log4j2.elasticsearch.ReusableUTF8JsonGenerator; -import org.junit.Test; - -import java.io.IOException; -import java.io.OutputStream; - -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.atLeastOnce; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -public class ReusableUTF8JsonGeneratorTest { - - @Test - public void canReuseAfterCloseAndReset() throws IOException { - - // given - OutputStream os1 = mock(OutputStream.class); - OutputStream os2 = mock(OutputStream.class); - - OutputStreamDelegate delegate = spy(new OutputStreamDelegate(os1)); - - ReusableIOContext ctx = createDefaultTestIOContext(delegate); - - ReusableUTF8JsonGenerator gen = createDefaultTestUTF8JsonGenerator(delegate, ctx); - - gen.writeStartObject(); - gen.writeEndObject(); - - int expectedLength1 = gen._outputTail; - - // when - gen.close(); // writes into the buffer - - delegate.setDelegate(os2); - ctx.setSourceReference(os2); - gen.reset(); - - gen.writeStartObject(); - gen.writeEndObject(); - - int expectedLength2 = gen._outputTail; - - gen.close(); // writes into the buffer - - // then - verify(os1, times(1)).write(eq(gen._outputBuffer), eq(0), eq(expectedLength1)); - verify(os2, times(1)).write(eq(gen._outputBuffer), eq(0), eq(expectedLength2)); - - verify(delegate, atLeastOnce()).write(eq(gen._outputBuffer), eq(0), eq(expectedLength1)); - - } - - @Test - public void resetDelegatesToJsonWriteContextAccessor() { - - // given - OutputStreamDelegate outputStreamDelegate = createDefaultTestOutputStreamDelegate(); - ReusableIOContext ctx = createDefaultTestIOContext(outputStreamDelegate); - JsonWriteContextAccessor ctxAccess = spy(new JsonWriteContextAccessor()); - - ReusableUTF8JsonGenerator jsonGenerator = createDefaultTestUTF8JsonGenerator(outputStreamDelegate, ctx, ctxAccess); - - // when - jsonGenerator.reset(); - - // then - verify(ctxAccess).reset(any(JsonWriteContext.class)); - - } - - @Test - public void closeClosesJsonContentIfEnabled() throws IOException { - - // given - OutputStreamDelegate outputStreamDelegate = createDefaultTestOutputStreamDelegate(); - ReusableIOContext ctx = createDefaultTestIOContext(outputStreamDelegate); - JsonWriteContextAccessor ctxAccess = spy(new JsonWriteContextAccessor()); - - ReusableUTF8JsonGenerator jsonGenerator = - spy(createDefaultTestUTF8JsonGenerator(outputStreamDelegate, ctx, ctxAccess)); - - jsonGenerator.configure(JsonGenerator.Feature.AUTO_CLOSE_JSON_CONTENT, true); - - assertTrue(jsonGenerator.getOutputContext().inRoot()); - jsonGenerator.writeStartArray(); - assertTrue(jsonGenerator.getOutputContext().inArray()); - jsonGenerator.writeStartObject(); - assertTrue(jsonGenerator.getOutputContext().inObject()); - - // when - jsonGenerator.close(); - - // then - assertTrue(jsonGenerator.getOutputContext().inRoot()); - assertFalse(jsonGenerator.getOutputContext().inArray()); - assertFalse(jsonGenerator.getOutputContext().inObject()); - - } - - @Test - public void closeDoesNotCloseJsonContentIfNotEnabled() throws IOException { - - // given - OutputStreamDelegate outputStreamDelegate = createDefaultTestOutputStreamDelegate(); - ReusableIOContext ctx = createDefaultTestIOContext(outputStreamDelegate); - JsonWriteContextAccessor ctxAccess = spy(new JsonWriteContextAccessor()); - - ReusableUTF8JsonGenerator jsonGenerator = - spy(createDefaultTestUTF8JsonGenerator(outputStreamDelegate, ctx, ctxAccess)); - - jsonGenerator.configure(JsonGenerator.Feature.AUTO_CLOSE_JSON_CONTENT, false); - - assertTrue(jsonGenerator.getOutputContext().inRoot()); - jsonGenerator.writeStartArray(); - assertTrue(jsonGenerator.getOutputContext().inArray()); - jsonGenerator.writeStartObject(); - assertTrue(jsonGenerator.getOutputContext().inObject()); - - // when - jsonGenerator.close(); - - // then - assertFalse(jsonGenerator.getOutputContext().inRoot()); - assertFalse(jsonGenerator.getOutputContext().inArray()); - assertTrue(jsonGenerator.getOutputContext().inObject()); - - } - - @Test - public void closeCloseTargetIfEnabled() throws IOException { - - // given - OutputStreamDelegate outputStreamDelegate = mock(OutputStreamDelegate.class); - ReusableUTF8JsonGenerator jsonGenerator = createDefaultTestUTF8JsonGenerator(outputStreamDelegate); - jsonGenerator.configure(JsonGenerator.Feature.AUTO_CLOSE_TARGET, true); - - // when - jsonGenerator.close(); - - // then - verify(outputStreamDelegate).close(); - - } - - @Test - public void closeDoesNotCloseTargetIfNotEnabled() throws IOException { - - // given - OutputStreamDelegate outputStreamDelegate = mock(OutputStreamDelegate.class); - ReusableUTF8JsonGenerator jsonGenerator = createDefaultTestUTF8JsonGenerator(outputStreamDelegate); - jsonGenerator.configure(JsonGenerator.Feature.AUTO_CLOSE_TARGET, false); - - // when - jsonGenerator.close(); - - // then - verify(outputStreamDelegate, never()).close(); - - } - - @Test - public void closeFlushesTargetIfEnabled() throws IOException { - - // given - OutputStreamDelegate outputStreamDelegate = mock(OutputStreamDelegate.class); - ReusableUTF8JsonGenerator jsonGenerator = createDefaultTestUTF8JsonGenerator(outputStreamDelegate); - jsonGenerator.configure(JsonGenerator.Feature.AUTO_CLOSE_TARGET, false); - jsonGenerator.configure(JsonGenerator.Feature.FLUSH_PASSED_TO_STREAM, true); - - // when - jsonGenerator.close(); - - // then - verify(outputStreamDelegate).flush(); - - } - - @Test - public void closeDoesNotFlushTargetIfNotEnabled() throws IOException { - - // given - OutputStreamDelegate outputStreamDelegate = mock(OutputStreamDelegate.class); - ReusableUTF8JsonGenerator jsonGenerator = createDefaultTestUTF8JsonGenerator(outputStreamDelegate); - jsonGenerator.configure(JsonGenerator.Feature.AUTO_CLOSE_TARGET, false); - jsonGenerator.configure(JsonGenerator.Feature.FLUSH_PASSED_TO_STREAM, false); - - // when - jsonGenerator.close(); - - // then - verify(outputStreamDelegate, never()).flush(); - - } - - public static OutputStreamDelegate createDefaultTestOutputStreamDelegate() { - return new OutputStreamDelegate(mock(OutputStream.class)); - } - - public static ReusableIOContext createDefaultTestIOContext(OutputStream delegate) { - BufferRecycler recycler = new BufferRecycler(); - return new ReusableIOContext(recycler, delegate, false); - } - - public static ReusableUTF8JsonGenerator createDefaultTestUTF8JsonGenerator(OutputStreamDelegate outputStreamDelegate) { - return createDefaultTestUTF8JsonGenerator( - outputStreamDelegate, - createDefaultTestIOContext(outputStreamDelegate), - new JsonWriteContextAccessor()); - } - - public static ReusableUTF8JsonGenerator createDefaultTestUTF8JsonGenerator( - OutputStreamDelegate outputStreamDelegate, - ReusableIOContext ctx) { - return createDefaultTestUTF8JsonGenerator(outputStreamDelegate, ctx, new JsonWriteContextAccessor()); - } - - public static ReusableUTF8JsonGenerator createDefaultTestUTF8JsonGenerator( - OutputStreamDelegate outputStreamDelegate, - ReusableIOContext ctx, - JsonWriteContextAccessor jsonWriteCtxAccess) { - return createDefaultTestUTF8JsonGenerator( - outputStreamDelegate, - ctx, - JsonGenerator.Feature.collectDefaults(), - jsonWriteCtxAccess); - } - - public static ReusableUTF8JsonGenerator createDefaultTestUTF8JsonGenerator( - OutputStream delegate, - ReusableIOContext ctx, - int features, - JsonWriteContextAccessor jsonWriteCtxAccess) { - - return new ReusableUTF8JsonGenerator( - ctx, - features, - new ObjectMapper(), - delegate, - '"', - jsonWriteCtxAccess); - - } - -} diff --git a/log4j2-elasticsearch-core/src/test/java/org/appenders/log4j2/elasticsearch/DataOutputAsStreamDelegateTest.java b/log4j2-elasticsearch-core/src/test/java/org/appenders/log4j2/elasticsearch/DataOutputAsStreamDelegateTest.java deleted file mode 100644 index 3a52073e..00000000 --- a/log4j2-elasticsearch-core/src/test/java/org/appenders/log4j2/elasticsearch/DataOutputAsStreamDelegateTest.java +++ /dev/null @@ -1,99 +0,0 @@ -package org.appenders.log4j2.elasticsearch; - -/*- - * #%L - * log4j2-elasticsearch - * %% - * Copyright (C) 2020 Rafal Foltynski - * %% - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * #L% - */ - -import org.junit.Test; - -import java.io.DataOutput; -import java.io.IOException; - -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; - -public class DataOutputAsStreamDelegateTest { - - @Test - public void canReplaceDelegate() throws IOException { - - // given - DataOutput dataOutput1 = mock(DataOutput.class); - DataOutputAsStreamDelegate dataOutputDelegate = new DataOutputAsStreamDelegate(dataOutput1); - dataOutputDelegate.write(1); - - // when - DataOutput dataOutput2 = mock(DataOutput.class); - dataOutputDelegate.setDelegate(dataOutput2); - dataOutputDelegate.write(1); - - // then - verify(dataOutput1).write(1); - verify(dataOutput2).write(1); - - } - - @Test - public void writeIntDelegates() throws IOException { - - // given - DataOutput dataOutput1 = mock(DataOutput.class); - DataOutputAsStreamDelegate dataOutputDelegate = new DataOutputAsStreamDelegate(dataOutput1); - - // when - dataOutputDelegate.write(1); - - // then - verify(dataOutput1).write(1); - - } - - @Test - public void writeBytesDelegate() throws IOException { - - // given - DataOutput dataOutput1 = mock(DataOutput.class); - DataOutputAsStreamDelegate dataOutputDelegate = new DataOutputAsStreamDelegate(dataOutput1); - - // when - byte[] bytes = {1}; - dataOutputDelegate.write(bytes); - - // then - verify(dataOutput1).write(bytes); - - } - - @Test - public void writeBytesWithOffsetDelegates() throws IOException { - - // given - DataOutput dataOutput1 = mock(DataOutput.class); - DataOutputAsStreamDelegate dataOutputDelegate = new DataOutputAsStreamDelegate(dataOutput1); - - // when - byte[] bytes = {1}; - dataOutputDelegate.write(bytes, 2, bytes.length); - - // then - verify(dataOutput1).write(bytes, 2, bytes.length); - - } - -} diff --git a/log4j2-elasticsearch-core/src/test/java/org/appenders/log4j2/elasticsearch/JacksonJsonLayoutTest.java b/log4j2-elasticsearch-core/src/test/java/org/appenders/log4j2/elasticsearch/JacksonJsonLayoutTest.java index a573dad6..7b392139 100644 --- a/log4j2-elasticsearch-core/src/test/java/org/appenders/log4j2/elasticsearch/JacksonJsonLayoutTest.java +++ b/log4j2-elasticsearch-core/src/test/java/org/appenders/log4j2/elasticsearch/JacksonJsonLayoutTest.java @@ -37,6 +37,7 @@ import org.apache.logging.log4j.core.jackson.LogEventJacksonJsonMixIn; import org.apache.logging.log4j.message.Message; import org.appenders.log4j2.elasticsearch.mock.LifecycleTestHelper; +import org.appenders.st.jackson.SingleThreadJsonFactory; import org.hamcrest.CoreMatchers; import org.junit.Assert; import org.junit.Rule; diff --git a/log4j2-elasticsearch-core/src/test/java/org/appenders/log4j2/elasticsearch/JsonWriteContextAccessorTest.java b/log4j2-elasticsearch-core/src/test/java/org/appenders/log4j2/elasticsearch/JsonWriteContextAccessorTest.java deleted file mode 100644 index 1e98fde3..00000000 --- a/log4j2-elasticsearch-core/src/test/java/org/appenders/log4j2/elasticsearch/JsonWriteContextAccessorTest.java +++ /dev/null @@ -1,68 +0,0 @@ -package org.appenders.log4j2.elasticsearch; - -/*- - * #%L - * log4j2-elasticsearch - * %% - * Copyright (C) 2020 Rafal Foltynski - * %% - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * #L% - */ - -import com.fasterxml.jackson.core.json.JsonWriteContext; -import org.junit.Test; - -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertTrue; - -public class JsonWriteContextAccessorTest { - - @Test - public void resetResetsCurrentContextImmediatelyIfContextHasNoParent() { - - // given - JsonWriteContextAccessor ctxAccess = new JsonWriteContextAccessor(); - JsonWriteContext context = JsonWriteContext.createRootContext(null); - - // when - JsonWriteContext ctxAfterReset = ctxAccess.reset(context); - - // then - assertSame(context, ctxAfterReset); - assertTrue(ctxAccess.inRoot(ctxAfterReset)); - - } - - @Test - public void resetResetsAndReturnsRootContextIfContextHasParent() { - - // given - JsonWriteContextAccessor ctxAccess = new JsonWriteContextAccessor(); - JsonWriteContext grandpaContext = JsonWriteContext.createRootContext(null); - JsonWriteContext parentContext = grandpaContext.createChildObjectContext(); - JsonWriteContext childContext = parentContext.createChildObjectContext(); - - assertFalse(ctxAccess.inRoot(childContext)); - - // when - JsonWriteContext ctxAfterReset = ctxAccess.reset(childContext); - - // then - assertSame(grandpaContext, ctxAfterReset); - assertTrue(ctxAccess.inRoot(ctxAfterReset)); - - } - -} \ No newline at end of file diff --git a/log4j2-elasticsearch-core/src/test/java/org/appenders/log4j2/elasticsearch/OutputStreamDelegateTest.java b/log4j2-elasticsearch-core/src/test/java/org/appenders/log4j2/elasticsearch/OutputStreamDelegateTest.java deleted file mode 100644 index 845bc92e..00000000 --- a/log4j2-elasticsearch-core/src/test/java/org/appenders/log4j2/elasticsearch/OutputStreamDelegateTest.java +++ /dev/null @@ -1,114 +0,0 @@ -package org.appenders.log4j2.elasticsearch; - -/*- - * #%L - * log4j2-elasticsearch - * %% - * Copyright (C) 2020 Rafal Foltynski - * %% - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * #L% - */ - -import org.junit.Test; - -import java.io.IOException; -import java.io.OutputStream; - -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; - -public class OutputStreamDelegateTest { - - @Test - public void canReplaceDelegate() throws IOException { - - // given - OutputStream os1 = mock(OutputStream.class); - OutputStreamDelegate outputStreamDelegate = new OutputStreamDelegate(os1); - outputStreamDelegate.write(1); - - // when - OutputStream os2 = mock(OutputStream.class); - outputStreamDelegate.setDelegate(os2); - outputStreamDelegate.write(1); - - // then - verify(os1).write(1); - verify(os2).write(1); - - } - - @Test - public void writeIntDelegates() throws IOException { - - // given - OutputStream os1 = mock(OutputStream.class); - OutputStreamDelegate outputStreamDelegate = new OutputStreamDelegate(os1); - - // when - outputStreamDelegate.write(1); - - // then - verify(os1).write(1); - - } - - @Test - public void writeBytesDelegate() throws IOException { - - // given - OutputStream os1 = mock(OutputStream.class); - OutputStreamDelegate outputStreamDelegate = new OutputStreamDelegate(os1); - - // when - byte[] bytes = {1}; - outputStreamDelegate.write(bytes); - - // then - verify(os1).write(bytes); - - } - - @Test - public void writeBytesWithOffsetDelegates() throws IOException { - - // given - OutputStream os1 = mock(OutputStream.class); - OutputStreamDelegate outputStreamDelegate = new OutputStreamDelegate(os1); - - // when - byte[] bytes = {1}; - outputStreamDelegate.write(bytes, 2, bytes.length); - - // then - verify(os1).write(bytes, 2, bytes.length); - - } - - @Test - public void closeDelegates() throws IOException { - - // given - OutputStream os1 = mock(OutputStream.class); - OutputStreamDelegate outputStreamDelegate = new OutputStreamDelegate(os1); - - // when - outputStreamDelegate.close(); - - // then - verify(os1).close(); - - } - -} diff --git a/log4j2-elasticsearch-core/src/test/java/org/appenders/log4j2/elasticsearch/ReusableIOContextTest.java b/log4j2-elasticsearch-core/src/test/java/org/appenders/log4j2/elasticsearch/ReusableIOContextTest.java deleted file mode 100644 index db9bc185..00000000 --- a/log4j2-elasticsearch-core/src/test/java/org/appenders/log4j2/elasticsearch/ReusableIOContextTest.java +++ /dev/null @@ -1,58 +0,0 @@ -package org.appenders.log4j2.elasticsearch; - -/*- - * #%L - * log4j2-elasticsearch - * %% - * Copyright (C) 2020 Rafal Foltynski - * %% - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * #L% - */ - -import com.fasterxml.jackson.core.util.BufferRecycler; -import org.jetbrains.annotations.NotNull; -import org.junit.Test; - -import java.io.ByteArrayOutputStream; -import java.io.OutputStream; - -import static org.junit.Assert.assertSame; - -public class ReusableIOContextTest { - - @Test - public void canReassignIOContextSourceReference() { - - // then - OutputStream initialSourceRef = new ByteArrayOutputStream(); - ReusableIOContext ctx = createDefaultTestIOContext(initialSourceRef); - - OutputStream expectedSourceRef = new ByteArrayOutputStream(); - - // when - ctx.setSourceReference(expectedSourceRef); - - // then - Object result = ctx.getSourceReference(); - assertSame(expectedSourceRef, result); - - } - - @NotNull - public ReusableIOContext createDefaultTestIOContext(OutputStream initialSourceRef) { - return new ReusableIOContext( - new BufferRecycler(), initialSourceRef, false); - } - -} diff --git a/log4j2-elasticsearch-core/src/test/java/org/appenders/log4j2/elasticsearch/SingleThreadJsonFactoryProviderTest.java b/log4j2-elasticsearch-core/src/test/java/org/appenders/log4j2/elasticsearch/SingleThreadJsonFactoryProviderTest.java new file mode 100644 index 00000000..8ef08a46 --- /dev/null +++ b/log4j2-elasticsearch-core/src/test/java/org/appenders/log4j2/elasticsearch/SingleThreadJsonFactoryProviderTest.java @@ -0,0 +1,24 @@ +package org.appenders.log4j2.elasticsearch; + +import com.fasterxml.jackson.core.JsonFactory; +import org.appenders.st.jackson.SingleThreadJsonFactory; +import org.junit.Assert; +import org.junit.Test; + +public class SingleThreadJsonFactoryProviderTest { + + @Test + public void createsSingleThreadJsonFactory() { + + // given + SingleThreadJsonFactoryProvider provider = new SingleThreadJsonFactoryProvider(); + + // when + JsonFactory jsonFactory = provider.create(); + + // then + Assert.assertTrue(jsonFactory instanceof SingleThreadJsonFactory); + + } + +} \ No newline at end of file diff --git a/log4j2-elasticsearch-core/src/test/java/org/appenders/log4j2/elasticsearch/SingleThreadJsonFactoryTest.java b/log4j2-elasticsearch-core/src/test/java/org/appenders/log4j2/elasticsearch/SingleThreadJsonFactoryTest.java deleted file mode 100644 index 85c3790d..00000000 --- a/log4j2-elasticsearch-core/src/test/java/org/appenders/log4j2/elasticsearch/SingleThreadJsonFactoryTest.java +++ /dev/null @@ -1,298 +0,0 @@ -package org.appenders.log4j2.elasticsearch; - -/*- - * #%L - * log4j2-elasticsearch - * %% - * Copyright (C) 2020 Rafal Foltynski - * %% - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * #L% - */ - -import com.fasterxml.jackson.core.JsonEncoding; -import com.fasterxml.jackson.core.JsonFactory; -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.core.JsonpCharacterEscapes; -import com.fasterxml.jackson.core.io.IOContext; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; - -import java.io.ByteArrayOutputStream; -import java.io.DataOutput; -import java.io.File; -import java.io.IOException; -import java.io.OutputStream; -import java.io.UnsupportedEncodingException; -import java.io.Writer; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNotSame; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.mock; - -public class SingleThreadJsonFactoryTest { - - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - @Test - public void createFileBasedGeneratorNotSupported() { - - // given - SingleThreadJsonFactory factory = new SingleThreadJsonFactory(); - - expectedException.expect(UnsupportedOperationException.class); - expectedException.expectMessage("File not supported. Use OutputStream"); - - // when - factory.createGenerator(mock(File.class), JsonEncoding.UTF8); - - } - - @Test - public void createGeneratorWithNonUtf8EncodingNotSupported() throws IOException { - - // given - SingleThreadJsonFactory factory = new SingleThreadJsonFactory(); - - expectedException.expect(UnsupportedEncodingException.class); - expectedException.expectMessage("Encoding not supported: " + JsonEncoding.UTF16_BE.getJavaName()); - - // when - factory.createGenerator(mock(OutputStream.class), JsonEncoding.UTF16_BE); - - } - - @Test - public void createWriterBasedGeneratorNotSupported() { - - // given - SingleThreadJsonFactory factory = new SingleThreadJsonFactory(); - - expectedException.expect(UnsupportedOperationException.class); - expectedException.expectMessage("Writer not supported. Use OutputStream"); - - // when - factory.createGenerator(mock(Writer.class)); - - } - - @Test - public void canCreateOutputStreamBasedGenerator() throws IOException { - - // given - SingleThreadJsonFactory factory = new SingleThreadJsonFactory(); - OutputStream os1 = mock(OutputStream.class); - - // when - JsonGenerator generator1 = factory.createGenerator(os1, JsonEncoding.UTF8); - - // then - assertNotNull(generator1); - - } - - @Test - public void createOutputStreamBasedGeneratorReplacesDelegateTarget() throws IOException { - - // given - SingleThreadJsonFactory factory = new SingleThreadJsonFactory(); - OutputStream os1 = mock(OutputStream.class); - - factory.createGenerator(os1, JsonEncoding.UTF8); - assertSame(factory.outputStreamDelegate.getDelegate(), os1); - - // when - OutputStream os2 = mock(OutputStream.class); - factory.createGenerator(os2, JsonEncoding.UTF8); - - // then - assertSame(factory.outputStreamDelegate.getDelegate(), os2); - - } - - @Test - public void createGeneratorCallsReturnSameInstanceEveryTime() throws IOException { - - // given - SingleThreadJsonFactory factory = new SingleThreadJsonFactory(); - - // when - JsonGenerator generator1 = factory.createGenerator(mock(OutputStream.class), JsonEncoding.UTF8); - JsonGenerator generator2 = factory.createGenerator(mock(OutputStream.class), JsonEncoding.UTF8); - - // then - assertNotNull(generator1); - assertSame(generator1, generator2); - - } - - @Test - public void createDataOutputWrapperCallsReplacesDelegateTarget() { - - // given - SingleThreadJsonFactory factory = new SingleThreadJsonFactory(); - - DataOutput dataOutput1 = mock(DataOutput.class); - factory._createDataOutputWrapper(dataOutput1); - assertSame(factory.dataOutputDelegate.getDelegate(), dataOutput1); - - // when - DataOutput dataOutput2 = mock(DataOutput.class); - factory._createDataOutputWrapper(dataOutput2); - - // then - assertSame(factory.dataOutputDelegate.getDelegate(), dataOutput2); - - } - - @Test - public void createDataOutputWrapperCallsReturnSameInstanceEveryTime() { - - // given - SingleThreadJsonFactory factory = new SingleThreadJsonFactory(); - - DataOutput dataOutput1 = mock(DataOutput.class); - OutputStream outputStream1 = factory._createDataOutputWrapper(dataOutput1); - - // when - DataOutput dataOutput2 = mock(DataOutput.class); - OutputStream outputStream2 = factory._createDataOutputWrapper(dataOutput2); - - // then - assertSame(outputStream1, outputStream2); - - } - - @Test - public void _createUTF8GeneratorResetsDelegatesAndGenerator() { - - // given - SingleThreadJsonFactory factory = new SingleThreadJsonFactory(); - OutputStream os1 = mock(OutputStream.class); - - // when - factory._createUTF8Generator(os1, mock(IOContext.class)); - - // then - assertSame(factory.outputStreamDelegate.getDelegate(), os1); - assertSame(factory.ioContext.getSourceReference(), os1); - - } - - @Test - public void canSetCharacterEscapesIfNotNull() throws IOException { - - // given - SingleThreadJsonFactory factory = new SingleThreadJsonFactory(); - - // when - factory.setCharacterEscapes(JsonpCharacterEscapes.instance()); - JsonGenerator generator = factory.createGenerator(mock(OutputStream.class), JsonEncoding.UTF8); - - // then - assertSame(JsonpCharacterEscapes.instance(), factory.getCharacterEscapes()); - assertSame(JsonpCharacterEscapes.instance(), generator.getCharacterEscapes()); - - } - - @Test - public void doesNotSetCharacterEscapesIfNull() throws IOException { - - // given - SingleThreadJsonFactory factory = new SingleThreadJsonFactory(); - - factory.setCharacterEscapes(JsonpCharacterEscapes.instance()); - JsonGenerator generator1 = factory.createGenerator(mock(OutputStream.class), JsonEncoding.UTF8); - - // when - factory.setCharacterEscapes(null); - JsonGenerator generator2 = factory.createGenerator(mock(OutputStream.class), JsonEncoding.UTF8); - - // then - assertSame(JsonpCharacterEscapes.instance(), factory.getCharacterEscapes()); - assertSame(JsonpCharacterEscapes.instance(), generator1.getCharacterEscapes()); - assertSame(JsonpCharacterEscapes.instance(), generator2.getCharacterEscapes()); - - } - - @Test - public void canSetRootValueSeparator() throws IOException { - - // given - SingleThreadJsonFactory factory = new SingleThreadJsonFactory(); - ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); - - // when - factory.setRootValueSeparator("#"); - - JsonGenerator generator = factory.createGenerator(outputStream, JsonEncoding.UTF8); - generator.writeStartObject(); - generator.writeStringField("field1", "value1"); - generator.writeEndObject(); - generator.close(); - - generator.writeStartObject(); - generator.writeStringField("field2", "value2"); - generator.writeEndObject(); - generator.close(); - - // then - assertTrue(outputStream.toString("UTF-8").contains("#")); - - } - - - @Test - public void doesNotSetSeparatorBackToDefaultRootValueSeparator() { - - // given - SingleThreadJsonFactory factory = new SingleThreadJsonFactory(); - factory.setRootValueSeparator("#"); - assertEquals("#", factory.getRootValueSeparator()); - - // when - factory.setRootValueSeparator(JsonFactory.DEFAULT_ROOT_VALUE_SEPARATOR.getValue()); - - // then - assertEquals("#", factory.getRootValueSeparator()); - - } - - @Test - public void copyDoesNotUseSourceSharedComponents() { - - // given - SingleThreadJsonFactory factory1 = new SingleThreadJsonFactory(); - factory1.dataOutputDelegate.setDelegate(mock(DataOutput.class)); - - // when - SingleThreadJsonFactory factory2 = factory1.copy(); - - // then - assertNotSame(factory1.outputStreamDelegate, factory2.outputStreamDelegate); - assertNotSame(factory1.outputStreamDelegate.getDelegate(), factory2.outputStreamDelegate.getDelegate()); - assertNotSame(factory1.dataOutputDelegate, factory2.dataOutputDelegate); - assertNotSame(factory1.dataOutputDelegate.getDelegate(), factory2.dataOutputDelegate.getDelegate()); - assertNotSame(factory1.ioContext, factory2.ioContext); - assertNotSame(factory1.ioContext.getSourceReference(), factory2.ioContext.getSourceReference()); - assertNotSame(factory1.jsonGenerator, factory2.jsonGenerator); - assertNotSame(factory1.writeCtxAccessor, factory2.writeCtxAccessor); - - } - -} diff --git a/pom.xml b/pom.xml index c79efe75..b8d5eb30 100644 --- a/pom.xml +++ b/pom.xml @@ -48,6 +48,7 @@ 1.8 1.8 1.8 + 1.0 2.13.3 0.8.3 2.12.0 @@ -92,6 +93,11 @@ + + org.appenders.st + appenders-jackson-st + ${org.appenders.st.jackson.version} + org.appenders.log4j log4j2-elasticsearch-core