001/* 002 * Copyright 2002-2019 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.core.log; 018 019import java.util.function.Supplier; 020 021import org.springframework.lang.Nullable; 022import org.springframework.util.Assert; 023 024/** 025 * A simple log message type for use with Commons Logging, allowing 026 * for convenient lazy resolution of a given {@link Supplier} instance 027 * (typically bound to a Java 8 lambda expression) or a printf-style 028 * format string ({@link String#format}) in its {@link #toString()}. 029 * 030 * @author Juergen Hoeller 031 * @since 5.2 032 * @see #of(Supplier) 033 * @see #format(String, Object) 034 * @see #format(String, Object...) 035 * @see org.apache.commons.logging.Log#fatal(Object) 036 * @see org.apache.commons.logging.Log#error(Object) 037 * @see org.apache.commons.logging.Log#warn(Object) 038 * @see org.apache.commons.logging.Log#info(Object) 039 * @see org.apache.commons.logging.Log#debug(Object) 040 * @see org.apache.commons.logging.Log#trace(Object) 041 */ 042public abstract class LogMessage implements CharSequence { 043 044 @Nullable 045 private String result; 046 047 048 @Override 049 public int length() { 050 return toString().length(); 051 } 052 053 @Override 054 public char charAt(int index) { 055 return toString().charAt(index); 056 } 057 058 @Override 059 public CharSequence subSequence(int start, int end) { 060 return toString().subSequence(start, end); 061 } 062 063 /** 064 * This will be called by the logging provider, potentially once 065 * per log target (therefore locally caching the result here). 066 */ 067 @Override 068 public String toString() { 069 if (this.result == null) { 070 this.result = buildString(); 071 } 072 return this.result; 073 } 074 075 abstract String buildString(); 076 077 078 /** 079 * Build a lazily resolving message from the given supplier. 080 * @param supplier the supplier (typically bound to a Java 8 lambda expression) 081 * @see #toString() 082 */ 083 public static LogMessage of(Supplier<? extends CharSequence> supplier) { 084 return new SupplierMessage(supplier); 085 } 086 087 /** 088 * Build a lazily formatted message from the given format string and argument. 089 * @param format the format string (following {@link String#format} rules) 090 * @param arg1 the argument 091 * @see String#format(String, Object...) 092 */ 093 public static LogMessage format(String format, Object arg1) { 094 return new FormatMessage1(format, arg1); 095 } 096 097 /** 098 * Build a lazily formatted message from the given format string and arguments. 099 * @param format the format string (following {@link String#format} rules) 100 * @param arg1 the first argument 101 * @param arg2 the second argument 102 * @see String#format(String, Object...) 103 */ 104 public static LogMessage format(String format, Object arg1, Object arg2) { 105 return new FormatMessage2(format, arg1, arg2); 106 } 107 108 /** 109 * Build a lazily formatted message from the given format string and arguments. 110 * @param format the format string (following {@link String#format} rules) 111 * @param arg1 the first argument 112 * @param arg2 the second argument 113 * @param arg3 the third argument 114 * @see String#format(String, Object...) 115 */ 116 public static LogMessage format(String format, Object arg1, Object arg2, Object arg3) { 117 return new FormatMessage3(format, arg1, arg2, arg3); 118 } 119 120 /** 121 * Build a lazily formatted message from the given format string and arguments. 122 * @param format the format string (following {@link String#format} rules) 123 * @param arg1 the first argument 124 * @param arg2 the second argument 125 * @param arg3 the third argument 126 * @param arg4 the fourth argument 127 * @see String#format(String, Object...) 128 */ 129 public static LogMessage format(String format, Object arg1, Object arg2, Object arg3, Object arg4) { 130 return new FormatMessage4(format, arg1, arg2, arg3, arg4); 131 } 132 133 /** 134 * Build a lazily formatted message from the given format string and varargs. 135 * @param format the format string (following {@link String#format} rules) 136 * @param args the varargs array (costly, prefer individual arguments) 137 * @see String#format(String, Object...) 138 */ 139 public static LogMessage format(String format, Object... args) { 140 return new FormatMessageX(format, args); 141 } 142 143 144 private static final class SupplierMessage extends LogMessage { 145 146 private Supplier<? extends CharSequence> supplier; 147 148 SupplierMessage(Supplier<? extends CharSequence> supplier) { 149 Assert.notNull(supplier, "Supplier must not be null"); 150 this.supplier = supplier; 151 } 152 153 @Override 154 String buildString() { 155 return this.supplier.get().toString(); 156 } 157 } 158 159 160 private static abstract class FormatMessage extends LogMessage { 161 162 protected final String format; 163 164 FormatMessage(String format) { 165 Assert.notNull(format, "Format must not be null"); 166 this.format = format; 167 } 168 } 169 170 171 private static final class FormatMessage1 extends FormatMessage { 172 173 private final Object arg1; 174 175 FormatMessage1(String format, Object arg1) { 176 super(format); 177 this.arg1 = arg1; 178 } 179 180 @Override 181 protected String buildString() { 182 return String.format(this.format, this.arg1); 183 } 184 } 185 186 187 private static final class FormatMessage2 extends FormatMessage { 188 189 private final Object arg1; 190 191 private final Object arg2; 192 193 FormatMessage2(String format, Object arg1, Object arg2) { 194 super(format); 195 this.arg1 = arg1; 196 this.arg2 = arg2; 197 } 198 199 @Override 200 String buildString() { 201 return String.format(this.format, this.arg1, this.arg2); 202 } 203 } 204 205 206 private static final class FormatMessage3 extends FormatMessage { 207 208 private final Object arg1; 209 210 private final Object arg2; 211 212 private final Object arg3; 213 214 FormatMessage3(String format, Object arg1, Object arg2, Object arg3) { 215 super(format); 216 this.arg1 = arg1; 217 this.arg2 = arg2; 218 this.arg3 = arg3; 219 } 220 221 @Override 222 String buildString() { 223 return String.format(this.format, this.arg1, this.arg2, this.arg3); 224 } 225 } 226 227 228 private static final class FormatMessage4 extends FormatMessage { 229 230 private final Object arg1; 231 232 private final Object arg2; 233 234 private final Object arg3; 235 236 private final Object arg4; 237 238 FormatMessage4(String format, Object arg1, Object arg2, Object arg3, Object arg4) { 239 super(format); 240 this.arg1 = arg1; 241 this.arg2 = arg2; 242 this.arg3 = arg3; 243 this.arg4 = arg4; 244 } 245 246 @Override 247 String buildString() { 248 return String.format(this.format, this.arg1, this.arg2, this.arg3, this.arg4); 249 } 250 } 251 252 253 private static final class FormatMessageX extends FormatMessage { 254 255 private final Object[] args; 256 257 FormatMessageX(String format, Object... args) { 258 super(format); 259 this.args = args; 260 } 261 262 @Override 263 String buildString() { 264 return String.format(this.format, this.args); 265 } 266 } 267 268}