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