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.message;
18
19 import java.io.Serializable;
20
21 import org.apache.logging.log4j.util.PerformanceSensitive;
22
23 /**
24  * Implementation of the {@link MessageFactory} interface that avoids allocating temporary objects where possible.
25  * Message instances are cached in a ThreadLocal and reused when a new message is requested within the same thread.
26  * @see ParameterizedMessageFactory
27  * @see ReusableSimpleMessage
28  * @see ReusableObjectMessage
29  * @see ReusableParameterizedMessage
30  * @since 2.6
31  */

32 @PerformanceSensitive("allocation")
33 public final class ReusableMessageFactory implements MessageFactory2, Serializable {
34
35     /**
36      * Instance of ReusableMessageFactory..
37      */

38     public static final ReusableMessageFactory INSTANCE = new ReusableMessageFactory();
39
40     private static final long serialVersionUID = -8970940216592525651L;
41     private static ThreadLocal<ReusableParameterizedMessage> threadLocalParameterized = new ThreadLocal<>();
42     private static ThreadLocal<ReusableSimpleMessage> threadLocalSimpleMessage = new ThreadLocal<>();
43     private static ThreadLocal<ReusableObjectMessage> threadLocalObjectMessage = new ThreadLocal<>();
44
45     /**
46      * Constructs a message factory.
47      */

48     public ReusableMessageFactory() {
49     }
50
51     private static ReusableParameterizedMessage getParameterized() {
52         ReusableParameterizedMessage result = threadLocalParameterized.get();
53         if (result == null) {
54             result = new ReusableParameterizedMessage();
55             threadLocalParameterized.set(result);
56         }
57         return result.reserved ? new ReusableParameterizedMessage().reserve() : result.reserve();
58     }
59
60     private static ReusableSimpleMessage getSimple() {
61         ReusableSimpleMessage result = threadLocalSimpleMessage.get();
62         if (result == null) {
63             result = new ReusableSimpleMessage();
64             threadLocalSimpleMessage.set(result);
65         }
66         return result;
67     }
68
69     private static ReusableObjectMessage getObject() {
70         ReusableObjectMessage result = threadLocalObjectMessage.get();
71         if (result == null) {
72             result = new ReusableObjectMessage();
73             threadLocalObjectMessage.set(result);
74         }
75         return result;
76     }
77
78     /**
79      * Invokes {@link Clearable#clear()} when possible.
80      * This flag is used internally to verify that a reusable message is no longer in use and
81      * can be reused.
82      * @param message the message to make available again
83      * @since 2.7
84      */

85     public static void release(final Message message) { // LOG4J2-1583
86         if (message instanceof Clearable) {
87             ((Clearable) message).clear();
88         }
89     }
90
91     @Override
92     public Message newMessage(final CharSequence charSequence) {
93         final ReusableSimpleMessage result = getSimple();
94         result.set(charSequence);
95         return result;
96     }
97
98     /**
99      * 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 }
200