001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache license, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the license for the specific language governing permissions and
015 * limitations under the license.
016 */
017package org.apache.logging.log4j.message;
018
019import java.io.Serializable;
020
021import org.apache.logging.log4j.util.PerformanceSensitive;
022
023/**
024 * Implementation of the {@link MessageFactory} interface that avoids allocating temporary objects where possible.
025 * Message instances are cached in a ThreadLocal and reused when a new message is requested within the same thread.
026 * @see ParameterizedMessageFactory
027 * @see ReusableSimpleMessage
028 * @see ReusableObjectMessage
029 * @see ReusableParameterizedMessage
030 * @since 2.6
031 */
032@PerformanceSensitive("allocation")
033public final class ReusableMessageFactory implements MessageFactory2, Serializable {
034
035    /**
036     * Instance of ReusableMessageFactory..
037     */
038    public static final ReusableMessageFactory INSTANCE = new ReusableMessageFactory();
039
040    private static final long serialVersionUID = -8970940216592525651L;
041    private static ThreadLocal<ReusableParameterizedMessage> threadLocalParameterized = new ThreadLocal<>();
042    private static ThreadLocal<ReusableSimpleMessage> threadLocalSimpleMessage = new ThreadLocal<>();
043    private static ThreadLocal<ReusableObjectMessage> threadLocalObjectMessage = new ThreadLocal<>();
044
045    /**
046     * Constructs a message factory.
047     */
048    public ReusableMessageFactory() {
049        super();
050    }
051
052    private static ReusableParameterizedMessage getParameterized() {
053        ReusableParameterizedMessage result = threadLocalParameterized.get();
054        if (result == null) {
055            result = new ReusableParameterizedMessage();
056            threadLocalParameterized.set(result);
057        }
058        return result.reserved ? new ReusableParameterizedMessage().reserve() : result.reserve();
059    }
060
061    private static ReusableSimpleMessage getSimple() {
062        ReusableSimpleMessage result = threadLocalSimpleMessage.get();
063        if (result == null) {
064            result = new ReusableSimpleMessage();
065            threadLocalSimpleMessage.set(result);
066        }
067        return result;
068    }
069
070    private static ReusableObjectMessage getObject() {
071        ReusableObjectMessage result = threadLocalObjectMessage.get();
072        if (result == null) {
073            result = new ReusableObjectMessage();
074            threadLocalObjectMessage.set(result);
075        }
076        return result;
077    }
078
079    /**
080     * Switches the {@code reserved} flag off if the specified message is a ReusableParameterizedMessage,
081     * otherwise does nothing. This flag is used internally to verify that a reusable message is no longer in use and
082     * can be reused.
083     * @param message the message to make available again
084     * @since 2.7
085     */
086    public static void release(final Message message) { // LOG4J2-1583
087        if (message instanceof ReusableParameterizedMessage) {
088            ((ReusableParameterizedMessage) message).reserved = false;
089        }
090    }
091
092    @Override
093    public Message newMessage(final CharSequence charSequence) {
094        final ReusableSimpleMessage result = getSimple();
095        result.set(charSequence);
096        return result;
097    }
098
099    /**
100     * Creates {@link ReusableParameterizedMessage} instances.
101     *
102     * @param message The message pattern.
103     * @param params The message parameters.
104     * @return The Message.
105     *
106     * @see MessageFactory#newMessage(String, Object...)
107     */
108    @Override
109    public Message newMessage(final String message, final Object... params) {
110        return getParameterized().set(message, params);
111    }
112
113    @Override
114    public Message newMessage(final String message, final Object p0) {
115        return getParameterized().set(message, p0);
116    }
117
118    @Override
119    public Message newMessage(final String message, final Object p0, final Object p1) {
120        return getParameterized().set(message, p0, p1);
121    }
122
123    @Override
124    public Message newMessage(final String message, final Object p0, final Object p1, final Object p2) {
125        return getParameterized().set(message, p0, p1, p2);
126    }
127
128    @Override
129    public Message newMessage(final String message, final Object p0, final Object p1, final Object p2,
130            final Object p3) {
131        return getParameterized().set(message, p0, p1, p2, p3);
132    }
133
134    @Override
135    public Message newMessage(final String message, final Object p0, final Object p1, final Object p2, final Object p3,
136            final Object p4) {
137        return getParameterized().set(message, p0, p1, p2, p3, p4);
138    }
139
140    @Override
141    public Message newMessage(final String message, final Object p0, final Object p1, final Object p2, final Object p3,
142            final Object p4, final Object p5) {
143        return getParameterized().set(message, p0, p1, p2, p3, p4, p5);
144    }
145
146    @Override
147    public Message newMessage(final String message, final Object p0, final Object p1, final Object p2, final Object p3,
148            final Object p4, final Object p5, final Object p6) {
149        return getParameterized().set(message, p0, p1, p2, p3, p4, p5, p6);
150    }
151
152    @Override
153    public Message newMessage(final String message, final Object p0, final Object p1, final Object p2, final Object p3,
154            final Object p4, final Object p5, final Object p6, final Object p7) {
155        return getParameterized().set(message, p0, p1, p2, p3, p4, p5, p6, p7);
156    }
157
158    @Override
159    public Message newMessage(final String message, final Object p0, final Object p1, final Object p2, final Object p3,
160            final Object p4, final Object p5, final Object p6, final Object p7, final Object p8) {
161        return getParameterized().set(message, p0, p1, p2, p3, p4, p5, p6, p7, p8);
162    }
163
164    @Override
165    public Message newMessage(final String message, final Object p0, final Object p1, final Object p2, final Object p3,
166            final Object p4, final Object p5, final Object p6, final Object p7, final Object p8, final Object p9) {
167        return getParameterized().set(message, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9);
168    }
169
170    /**
171     * Creates {@link ReusableSimpleMessage} instances.
172     *
173     * @param message The message String.
174     * @return The Message.
175     *
176     * @see MessageFactory#newMessage(String)
177     */
178    @Override
179    public Message newMessage(final String message) {
180        final ReusableSimpleMessage result = getSimple();
181        result.set(message);
182        return result;
183    }
184
185
186    /**
187     * Creates {@link ReusableObjectMessage} instances.
188     *
189     * @param message The message Object.
190     * @return The Message.
191     *
192     * @see MessageFactory#newMessage(Object)
193     */
194    @Override
195    public Message newMessage(final Object message) {
196        final ReusableObjectMessage result = getObject();
197        result.set(message);
198        return result;
199    }
200}