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