    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     */
    017
    018    package org.apache.logging.log4j.message;
    019
    020    import java.io.IOException;
    021    import java.io.ObjectInputStream;
    022    import java.io.ObjectOutputStream;
    023    import java.text.MessageFormat;
    024    import java.util.Arrays;
    025    import java.util.IllegalFormatException;
    026
    027    import org.apache.logging.log4j.Logger;
    028    import org.apache.logging.log4j.status.StatusLogger;
    029
    030    /**
    031     * Handles messages that consist of a format string conforming to java.text.MessageFormat.
    032     *
    033     * @serial In version 2.1, due to a bug in the serialization format, the serialization format was changed along with
    034     * its {@code serialVersionUID} value.
    035     */
    036    public class MessageFormatMessage implements Message {
    037
    038        private static final Logger LOGGER = StatusLogger.getLogger();
    039
    040        private static final long serialVersionUID = 1L;
    041
    042        private static final int HASHVAL = 31;
    043
    044        private String messagePattern;
    045        private transient Object[] parameters;
    046        private String[] serializedParameters;
    047        private transient String formattedMessage;
    048        private transient Throwable throwable;
    049
    050        public MessageFormatMessage(final String messagePattern, final Object... parameters) {
    051            this.messagePattern = messagePattern;
    052            this.parameters = parameters;
    053            final int length = parameters == null ? 0 : parameters.length;
    054            if (length > 0 && parameters[length - 1] instanceof Throwable) {
    055                this.throwable = (Throwable) parameters[length - 1];
    056            }
    057        }
    058
    059        /**
    060         * Returns the formatted message.
    061         * @return the formatted message.
    062         */
    063        @Override
    064        public String getFormattedMessage() {
    065            if (formattedMessage == null) {
    066                formattedMessage = formatMessage(messagePattern, parameters);
    067            }
    068            return formattedMessage;
    069        }
    070
    071        /**
    072         * Returns the message pattern.
    073         * @return the message pattern.
    074         */
    075        @Override
    076        public String getFormat() {
    077            return messagePattern;
    078        }
    079
    080        /**
    081         * Returns the message parameters.
    082         * @return the message parameters.
    083         */
    084        @Override
    085        public Object[] getParameters() {
    086            if (parameters != null) {
    087                return parameters;
    088            }
    089            return serializedParameters;
    090        }
    091
    092        protected String formatMessage(final String msgPattern, final Object... args) {
    093            try {
    094                return MessageFormat.format(msgPattern, args);
    095            } catch (final IllegalFormatException ife) {
    096                LOGGER.error("Unable to format msg: " + msgPattern, ife);
    097                return msgPattern;
    098            }
    099        }
    100
    101        @Override
    102        public boolean equals(final Object o) {
    103            if (this == o) {
    104                return true;
    105            }
    106            if (o == null || getClass() != o.getClass()) {
    107                return false;
    108            }
    109
    110            final MessageFormatMessage that = (MessageFormatMessage) o;
    111
    112            if (messagePattern != null ? !messagePattern.equals(that.messagePattern) : that.messagePattern != null) {
    113                return false;
    114            }
    115            return Arrays.equals(serializedParameters, that.serializedParameters);
    116        }
    117
    118        @Override
    119        public int hashCode() {
    120            int result = messagePattern != null ? messagePattern.hashCode() : 0;
    121            result = HASHVAL * result + (serializedParameters != null ? Arrays.hashCode(serializedParameters) : 0);
    122            return result;
    123        }
    124
    125
    126        @Override
    127        public String toString() {
    128            return "StringFormatMessage[messagePattern=" + messagePattern + ", args=" +
    129                Arrays.toString(parameters) + ']';
    130        }
    131
    132        private void writeObject(final ObjectOutputStream out) throws IOException {
    133            getFormattedMessage();
    134            out.writeUTF(formattedMessage);
    135            out.writeUTF(messagePattern);
    136            final int length = parameters == null ? 0 : parameters.length;
    137            out.writeInt(length);
    138            serializedParameters = new String[length];
    139            if (length > 0) {
    140                for (int i = 0; i < length; i++) {
    141                    serializedParameters[i] = String.valueOf(parameters[i]);
    142                    out.writeUTF(serializedParameters[i]);
    143                }
    144            }
    145        }
    146
    147        private void readObject(final ObjectInputStream in) throws IOException {
    148            parameters = null;
    149            throwable = null;
    150            formattedMessage = in.readUTF();
    151            messagePattern = in.readUTF();
    152            final int length = in.readInt();
    153            serializedParameters = new String[length];
    154            for (int i = 0; i < length; ++i) {
    155                serializedParameters[i] = in.readUTF();
    156            }
    157        }
    158
    159        /**
    160         * Return the throwable passed to the Message.
    161         *
    162         * @return the Throwable.
    163         */
    164        @Override
    165        public Throwable getThrowable() {
    166            return throwable;
    167        }
    168    }