001/* 002 * Copyright 2002-2018 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.codec; 018 019import java.util.Collections; 020import java.util.HashMap; 021import java.util.Map; 022 023import org.apache.commons.logging.Log; 024 025import org.springframework.lang.Nullable; 026 027/** 028 * Constants and convenience methods for working with hints. 029 * 030 * @author Rossen Stoyanchev 031 * @since 5.1 032 * @see ResourceRegionEncoder#BOUNDARY_STRING_HINT 033 */ 034public abstract class Hints { 035 036 /** 037 * Name of hint exposing a prefix to use for correlating log messages. 038 */ 039 public static final String LOG_PREFIX_HINT = Log.class.getName() + ".PREFIX"; 040 041 /** 042 * Name of boolean hint whether to avoid logging data either because it's 043 * potentially sensitive, or because it has been logged by a composite 044 * encoder, e.g. for multipart requests. 045 */ 046 public static final String SUPPRESS_LOGGING_HINT = Log.class.getName() + ".SUPPRESS_LOGGING"; 047 048 049 /** 050 * Create a map wit a single hint via {@link Collections#singletonMap}. 051 * @param hintName the hint name 052 * @param value the hint value 053 * @return the created map 054 */ 055 public static Map<String, Object> from(String hintName, Object value) { 056 return Collections.singletonMap(hintName, value); 057 } 058 059 /** 060 * Return an empty map of hints via {@link Collections#emptyMap()}. 061 * @return the empty map 062 */ 063 public static Map<String, Object> none() { 064 return Collections.emptyMap(); 065 } 066 067 /** 068 * Obtain the value for a required hint. 069 * @param hints the hints map 070 * @param hintName the required hint name 071 * @param <T> the hint type to cast to 072 * @return the hint value 073 * @throws IllegalArgumentException if the hint is not found 074 */ 075 @SuppressWarnings("unchecked") 076 public static <T> T getRequiredHint(@Nullable Map<String, Object> hints, String hintName) { 077 if (hints == null) { 078 throw new IllegalArgumentException("No hints map for required hint '" + hintName + "'"); 079 } 080 T hint = (T) hints.get(hintName); 081 if (hint == null) { 082 throw new IllegalArgumentException("Hints map must contain the hint '" + hintName + "'"); 083 } 084 return hint; 085 } 086 087 /** 088 * Obtain the hint {@link #LOG_PREFIX_HINT}, if present, or an empty String. 089 * @param hints the hints passed to the encode method 090 * @return the log prefix 091 */ 092 public static String getLogPrefix(@Nullable Map<String, Object> hints) { 093 return (hints != null ? (String) hints.getOrDefault(LOG_PREFIX_HINT, "") : ""); 094 } 095 096 /** 097 * Whether to suppress logging based on the hint {@link #SUPPRESS_LOGGING_HINT}. 098 * @param hints the hints map 099 * @return whether logging of data is allowed 100 */ 101 public static boolean isLoggingSuppressed(@Nullable Map<String, Object> hints) { 102 return (hints != null && (boolean) hints.getOrDefault(SUPPRESS_LOGGING_HINT, false)); 103 } 104 105 /** 106 * Merge two maps of hints, creating and copying into a new map if both have 107 * values, or returning the non-empty map, or an empty map if both are empty. 108 * @param hints1 1st map of hints 109 * @param hints2 2nd map of hints 110 * @return a single map with hints from both 111 */ 112 public static Map<String, Object> merge(Map<String, Object> hints1, Map<String, Object> hints2) { 113 if (hints1.isEmpty() && hints2.isEmpty()) { 114 return Collections.emptyMap(); 115 } 116 else if (hints2.isEmpty()) { 117 return hints1; 118 } 119 else if (hints1.isEmpty()) { 120 return hints2; 121 } 122 else { 123 Map<String, Object> result = new HashMap<>(hints1.size() + hints2.size()); 124 result.putAll(hints1); 125 result.putAll(hints2); 126 return result; 127 } 128 } 129 130 /** 131 * Merge a single hint into a map of hints, possibly creating and copying 132 * all hints into a new map, or otherwise if the map of hints is empty, 133 * creating a new single entry map. 134 * @param hints a map of hints to be merge 135 * @param hintName the hint name to merge 136 * @param hintValue the hint value to merge 137 * @return a single map with all hints 138 */ 139 public static Map<String, Object> merge(Map<String, Object> hints, String hintName, Object hintValue) { 140 if (hints.isEmpty()) { 141 return Collections.singletonMap(hintName, hintValue); 142 } 143 else { 144 Map<String, Object> result = new HashMap<>(hints.size() + 1); 145 result.putAll(hints); 146 result.put(hintName, hintValue); 147 return result; 148 } 149 } 150 151}