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