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; 026 027import org.apache.logging.log4j.Logger; 028import 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 */ 036public 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}