001// *************************************************************************************************************************** 002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * 003// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * 004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * 005// * with the License. You may obtain a copy of the License at * 006// * * 007// * http://www.apache.org/licenses/LICENSE-2.0 * 008// * * 009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * 010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * 011// * specific language governing permissions and limitations under the License. * 012// *************************************************************************************************************************** 013package org.apache.juneau; 014 015import static org.apache.juneau.collections.JsonMap.*; 016import static org.apache.juneau.common.internal.StringUtils.*; 017import static java.util.Collections.*; 018 019import java.text.*; 020import java.util.*; 021import java.util.function.*; 022 023import org.apache.juneau.collections.*; 024import org.apache.juneau.internal.*; 025 026/** 027 * A one-time-use non-thread-safe object that's meant to be used once and then thrown away. 028 * 029 * <h5 class='section'>Notes:</h5><ul> 030 * <li class='warn'>This class is not typically thread safe. 031 * </ul> 032 * 033 * <h5 class='section'>See Also:</h5><ul> 034 * </ul> 035 */ 036public abstract class ContextSession { 037 038 //----------------------------------------------------------------------------------------------------------------- 039 // Builder 040 //----------------------------------------------------------------------------------------------------------------- 041 042 /** 043 * Builder class. 044 */ 045 @FluentSetters 046 public static abstract class Builder { 047 Context ctx; 048 JsonMap properties; 049 boolean unmodifiable; 050 Boolean debug; 051 052 /** 053 * Constructor. 054 * 055 * @param ctx The context creating this session. 056 */ 057 protected Builder(Context ctx) { 058 this.ctx = ctx; 059 debug = ctx.debug; 060 } 061 062 /** 063 * Build the object. 064 * 065 * @return The built object. 066 */ 067 public abstract ContextSession build(); 068 069 /** 070 * Debug mode. 071 * 072 * <p> 073 * Enables the following additional information during parsing: 074 * <ul> 075 * <li> When bean setters throws exceptions, the exception includes the object stack information in order to determine how that method was invoked. 076 * </ul> 077 * 078 * <p> 079 * If not specified, defaults to {@link Context.Builder#debug()}. 080 * 081 * <h5 class='section'>See Also:</h5><ul> 082 * <li class='ja'>{@link org.apache.juneau.annotation.BeanConfig#debug()} 083 * <li class='jm'>{@link org.apache.juneau.Context.Builder#debug()} 084 * 085 * @param value 086 * The new value for this property. 087 * <br>Can be <jk>null</jk>. Value will be ignored. 088 * @return This object. 089 */ 090 @FluentSetter 091 public Builder debug(Boolean value) { 092 if (value != null) 093 debug = value; 094 return this; 095 } 096 097 /** 098 * Create an unmodifiable session. 099 * 100 * <p> 101 * The created ContextSession object will be unmodifiable which makes it suitable for caching and reuse. 102 * 103 * @return This object. 104 */ 105 @FluentSetter 106 public Builder unmodifiable() { 107 unmodifiable = true; 108 return this; 109 } 110 111 /** 112 * Session properties. 113 * 114 * <p> 115 * Session properties are generic key-value pairs that can be passed through the session and made 116 * available to any customized serializers/parsers or swaps. 117 * 118 * @param value 119 * The new value for this property. 120 * <br>Can be <jk>null</jk>. 121 * @return This object. 122 */ 123 @FluentSetter 124 public Builder properties(Map<String,Object> value) { 125 properties = JsonMap.of(value); 126 return this; 127 } 128 129 /** 130 * Adds a property to this session. 131 * 132 * @param key The property key. 133 * @param value The property value. 134 * @return This object. 135 */ 136 @FluentSetter 137 public Builder property(String key, Object value) { 138 if (properties == null) 139 properties = JsonMap.create(); 140 if (value == null) { 141 properties.remove(key); 142 } else { 143 properties.put(key, value); 144 } 145 return this; 146 } 147 148 /** 149 * Applies a consumer to this builder if it's the specified type. 150 * 151 * @param <T> The expected type. 152 * @param type The expected type. 153 * @param apply The consumer to apply. 154 * @return This object. 155 */ 156 @FluentSetter 157 public <T> Builder apply(Class<T> type, Consumer<T> apply) { 158 if (type.isInstance(this)) 159 apply.accept(type.cast(this)); 160 return this; 161 } 162 163 // <FluentSetters> 164 165 // </FluentSetters> 166 } 167 168 //----------------------------------------------------------------------------------------------------------------- 169 // Instance 170 //----------------------------------------------------------------------------------------------------------------- 171 172 private final JsonMap properties; 173 private List<String> warnings; // Any warnings encountered. 174 175 private final Context ctx; 176 private final boolean debug; 177 private final boolean unmodifiable; 178 179 /** 180 * Default constructor. 181 * 182 * @param builder The builder for this object 183 */ 184 protected ContextSession(Builder builder) { 185 ctx = builder.ctx; 186 unmodifiable = builder.unmodifiable; 187 JsonMap sp = builder.properties == null ? JsonMap.EMPTY_MAP : builder.properties; 188 if (unmodifiable) 189 sp = sp.unmodifiable(); 190 properties = sp; 191 debug = builder.debug; 192 } 193 194 /** 195 * Returns the session properties on this session. 196 * 197 * @return The session properties on this session. Never <jk>null</jk>. 198 */ 199 public final JsonMap getSessionProperties() { 200 return properties; 201 } 202 203 /** 204 * Returns the context that created this session. 205 * 206 * @return The context that created this session. 207 */ 208 public Context getContext() { 209 return ctx; 210 } 211 212 /** 213 * Logs a warning message. 214 * 215 * @param msg The warning message. 216 * @param args Optional {@link MessageFormat}-style arguments. 217 */ 218 public void addWarning(String msg, Object... args) { 219 if (unmodifiable) 220 return; 221 if (warnings == null) 222 warnings = new LinkedList<>(); 223 warnings.add((warnings.size() + 1) + ": " + format(msg, args)); 224 } 225 226 /** 227 * Returns the warnings that occurred in this session. 228 * 229 * @return The warnings that occurred in this session, or <jk>null</jk> if no warnings occurred. 230 */ 231 public final List<String> getWarnings() { 232 return warnings == null ? emptyList() : warnings; 233 } 234 235 /** 236 * Throws a {@link BeanRuntimeException} if any warnings occurred in this session and debug is enabled. 237 */ 238 public void checkForWarnings() { 239 if (debug && ! getWarnings().isEmpty()) 240 throw new BeanRuntimeException("Warnings occurred in session: \n" + join(getWarnings(), "\n")); 241 } 242 243 //----------------------------------------------------------------------------------------------------------------- 244 // Configuration properties 245 //----------------------------------------------------------------------------------------------------------------- 246 247 /** 248 * Debug mode enabled. 249 * 250 * @see Context.Builder#debug() 251 * @return 252 * <jk>true</jk> if debug mode is enabled. 253 */ 254 public boolean isDebug() { 255 return debug; 256 } 257 258 //----------------------------------------------------------------------------------------------------------------- 259 // Other methods 260 //----------------------------------------------------------------------------------------------------------------- 261 262 /** 263 * Returns the properties on this bean as a map for debugging. 264 * 265 * @return The properties on this bean as a map for debugging. 266 */ 267 protected JsonMap properties() { 268 return filteredMap("debug", debug); 269 } 270 271 @Override /* Object */ 272 public String toString() { 273 return ObjectUtils.toPropertyMap(this).asReadableString(); 274 } 275}