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 org.apache.logging.log4j.status.StatusLogger;
020
021/**
022 * Specialized {@link ParameterizedMessageFactory} that creates {@link SimpleMessage} objects that do not retain a
023 * reference to the parameter object.
024 * <p>
025 * Intended for use by the {@link StatusLogger}: this logger retains a queue of recently logged messages in memory,
026 * causing memory leaks in web applications. (LOG4J2-1176)
027 * </p>
028 * <p>
029 * This class is immutable.
030 * </p>
031 */
032public final class ParameterizedNoReferenceMessageFactory extends AbstractMessageFactory {
033    private static final long serialVersionUID = 5027639245636870500L;
034
035    /**
036     * Message implementation that only keeps a reference to the error text and the error (if any), not to the
037     * message parameters, in order to avoid memory leaks. This addresses LOG4J2-1368.
038     * @since 2.6
039     */
040    static class StatusMessage implements Message {
041        private final String formattedMessage;
042        private final Throwable throwable;
043
044        public StatusMessage(final String formattedMessage, final Throwable throwable) {
045            this.formattedMessage = formattedMessage;
046            this.throwable = throwable;
047        }
048
049        @Override
050        public String getFormattedMessage() {
051            return formattedMessage;
052        }
053
054        @Override
055        public String getFormat() {
056            return formattedMessage;
057        }
058
059        @Override
060        public Object[] getParameters() {
061            return null;
062        }
063
064        @Override
065        public Throwable getThrowable() {
066            return throwable;
067        }
068    }
069
070    /**
071     * Constructs a message factory with default flow strings.
072     */
073    public ParameterizedNoReferenceMessageFactory() {
074        super();
075    }
076
077    /**
078     * Instance of ParameterizedStatusMessageFactory.
079     */
080    public static final ParameterizedNoReferenceMessageFactory INSTANCE = new ParameterizedNoReferenceMessageFactory();
081
082    /**
083     * Creates {@link SimpleMessage} instances containing the formatted parameterized message string.
084     *
085     * @param message The message pattern.
086     * @param params The message parameters.
087     * @return The Message.
088     *
089     * @see MessageFactory#newMessage(String, Object...)
090     */
091    @Override
092    public Message newMessage(final String message, final Object... params) {
093        if (params == null) {
094            return new SimpleMessage(message);
095        }
096        final ParameterizedMessage msg = new ParameterizedMessage(message, params);
097        return new StatusMessage(msg.getFormattedMessage(), msg.getThrowable());
098    }
099}