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