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    }
050
051    private static ReusableParameterizedMessage getParameterized() {
052        ReusableParameterizedMessage result = threadLocalParameterized.get();
053        if (result == null) {
054            result = new ReusableParameterizedMessage();
055            threadLocalParameterized.set(result);
056        }
057        return result.reserved ? new ReusableParameterizedMessage().reserve() : result.reserve();
058    }
059
060    private static ReusableSimpleMessage getSimple() {
061        ReusableSimpleMessage result = threadLocalSimpleMessage.get();
062        if (result == null) {
063            result = new ReusableSimpleMessage();
064            threadLocalSimpleMessage.set(result);
065        }
066        return result;
067    }
068
069    private static ReusableObjectMessage getObject() {
070        ReusableObjectMessage result = threadLocalObjectMessage.get();
071        if (result == null) {
072            result = new ReusableObjectMessage();
073            threadLocalObjectMessage.set(result);
074        }
075        return result;
076    }
077
078    /**
079     * Invokes {@link Clearable#clear()} when possible.
080     * This flag is used internally to verify that a reusable message is no longer in use and
081     * can be reused.
082     * @param message the message to make available again
083     * @since 2.7
084     */
085    public static void release(final Message message) { // LOG4J2-1583
086        if (message instanceof Clearable) {
087            ((Clearable) message).clear();
088        }
089    }
090
091    @Override
092    public Message newMessage(final CharSequence charSequence) {
093        final ReusableSimpleMessage result = getSimple();
094        result.set(charSequence);
095        return result;
096    }
097
098    /**
099     * Creates {@link ReusableParameterizedMessage} instances.
100     *
101     * @param message The message pattern.
102     * @param params The message parameters.
103     * @return The Message.
104     *
105     * @see MessageFactory#newMessage(String, Object...)
106     */
107    @Override
108    public Message newMessage(final String message, final Object... params) {
109        return getParameterized().set(message, params);
110    }
111
112    @Override
113    public Message newMessage(final String message, final Object p0) {
114        return getParameterized().set(message, p0);
115    }
116
117    @Override
118    public Message newMessage(final String message, final Object p0, final Object p1) {
119        return getParameterized().set(message, p0, p1);
120    }
121
122    @Override
123    public Message newMessage(final String message, final Object p0, final Object p1, final Object p2) {
124        return getParameterized().set(message, p0, p1, p2);
125    }
126
127    @Override
128    public Message newMessage(final String message, final Object p0, final Object p1, final Object p2,
129            final Object p3) {
130        return getParameterized().set(message, p0, p1, p2, p3);
131    }
132
133    @Override
134    public Message newMessage(final String message, final Object p0, final Object p1, final Object p2, final Object p3,
135            final Object p4) {
136        return getParameterized().set(message, p0, p1, p2, p3, p4);
137    }
138
139    @Override
140    public Message newMessage(final String message, final Object p0, final Object p1, final Object p2, final Object p3,
141            final Object p4, final Object p5) {
142        return getParameterized().set(message, p0, p1, p2, p3, p4, p5);
143    }
144
145    @Override
146    public Message newMessage(final String message, final Object p0, final Object p1, final Object p2, final Object p3,
147            final Object p4, final Object p5, final Object p6) {
148        return getParameterized().set(message, p0, p1, p2, p3, p4, p5, p6);
149    }
150
151    @Override
152    public Message newMessage(final String message, final Object p0, final Object p1, final Object p2, final Object p3,
153            final Object p4, final Object p5, final Object p6, final Object p7) {
154        return getParameterized().set(message, p0, p1, p2, p3, p4, p5, p6, p7);
155    }
156
157    @Override
158    public Message newMessage(final String message, final Object p0, final Object p1, final Object p2, final Object p3,
159            final Object p4, final Object p5, final Object p6, final Object p7, final Object p8) {
160        return getParameterized().set(message, p0, p1, p2, p3, p4, p5, p6, p7, p8);
161    }
162
163    @Override
164    public Message newMessage(final String message, final Object p0, final Object p1, final Object p2, final Object p3,
165            final Object p4, final Object p5, final Object p6, final Object p7, final Object p8, final Object p9) {
166        return getParameterized().set(message, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9);
167    }
168
169    /**
170     * Creates {@link ReusableSimpleMessage} instances.
171     *
172     * @param message The message String.
173     * @return The Message.
174     *
175     * @see MessageFactory#newMessage(String)
176     */
177    @Override
178    public Message newMessage(final String message) {
179        final ReusableSimpleMessage result = getSimple();
180        result.set(message);
181        return result;
182    }
183
184
185    /**
186     * Creates {@link ReusableObjectMessage} instances.
187     *
188     * @param message The message Object.
189     * @return The Message.
190     *
191     * @see MessageFactory#newMessage(Object)
192     */
193    @Override
194    public Message newMessage(final Object message) {
195        final ReusableObjectMessage result = getObject();
196        result.set(message);
197        return result;
198    }
199}