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