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 java.util.*; 016 017import org.apache.juneau.annotation.*; 018import org.apache.juneau.internal.*; 019import org.apache.juneau.json.*; 020import org.apache.juneau.serializer.*; 021 022/** 023 * A reusable stateless thread-safe read-only configuration, typically used for creating one-time use {@link Session} 024 * objects. 025 * 026 * <p> 027 * Contexts are created through the {@link ContextBuilder#build()} method (and subclasses of {@link ContextBuilder}). 028 * 029 * <p> 030 * Subclasses MUST implement the following constructor: 031 * 032 * <p class='bcode'> 033 * <jk>public</jk> T(PropertyStore); 034 * </p> 035 * 036 * <p> 037 * Besides that restriction, a context object can do anything you desire. 038 * <br>However, it MUST be thread-safe and all fields should be declared final to prevent modification. 039 * <br>It should NOT be used for storing temporary or state information. 040 * 041 * @see PropertyStore 042 */ 043public abstract class Context { 044 045 private final PropertyStore propertyStore; 046 private final int hashCode; 047 048 /** 049 * Constructor for this class. 050 * 051 * <p> 052 * Subclasses MUST implement the same public constructor. 053 * 054 * @param ps The read-only configuration for this context object. 055 */ 056 public Context(PropertyStore ps) { 057 this.propertyStore = ps == null ? PropertyStore.DEFAULT : ps; 058 this.hashCode = new HashCode().add(getClass().getName()).add(ps).get(); 059 } 060 061 /** 062 * Returns the raw property value with the specified name. 063 * 064 * @param key The property name. 065 * @return The property value, or <jk>null</jk> if it doesn't exist. 066 */ 067 public Object getProperty(String key) { 068 return propertyStore.getProperty(key); 069 } 070 071 /** 072 * Returns the property value with the specified name. 073 * 074 * @param key The property name. 075 * @param c The class to cast or convert the value to. 076 * @param def The default value. 077 * @return The property value, or the default value if it doesn't exist. 078 */ 079 public final <T> T getProperty(String key, Class<T> c, T def) { 080 return propertyStore.getProperty(key, c, def); 081 } 082 083 /** 084 * Shortcut for calling <code>getProperty(key, Boolean.<jk>class</jk>, def)</code>. 085 * 086 * @param key The property name. 087 * @param def The default value. 088 * @return The property value, or the default value if it doesn't exist. 089 */ 090 public final Boolean getBooleanProperty(String key, Boolean def) { 091 return getProperty(key, Boolean.class, def); 092 } 093 094 /** 095 * Shortcut for calling <code>getProperty(key, Integer.<jk>class</jk>, def)</code>. 096 * 097 * @param key The property name. 098 * @param def The default value. 099 * @return The property value, or the default value if it doesn't exist. 100 */ 101 public final Integer getIntegerProperty(String key, Integer def) { 102 return getProperty(key, Integer.class, def); 103 } 104 105 /** 106 * Shortcut for calling <code>getProperty(key, Long.<jk>class</jk>, def)</code>. 107 * 108 * @param key The property name. 109 * @param def The default value. 110 * @return The property value, or the default value if it doesn't exist. 111 */ 112 public final Long getLongProperty(String key, Long def) { 113 return getProperty(key, Long.class, def); 114 } 115 116 /** 117 * Shortcut for calling <code>getProperty(key, String.<jk>class</jk>, def)</code>. 118 * 119 * @param key The property name. 120 * @param def The default value. 121 * @return The property value, or the default value if it doesn't exist. 122 */ 123 public final String getStringProperty(String key, String def) { 124 return getProperty(key, String.class, def); 125 } 126 127 /** 128 * Returns the class property with the specified name. 129 * 130 * @param key The property name. 131 * @param type The class type of the property. 132 * @param def The default value. 133 * @return The property value, or the default value if it doesn't exist. 134 */ 135 public final <T> Class<? extends T> getClassProperty(String key, Class<T> type, Class<? extends T> def) { 136 return propertyStore.getClassProperty(key, type, def); 137 } 138 139 /** 140 * Returns the array property value with the specified name. 141 * 142 * @param key The property name. 143 * @param eType The class type of the elements in the property. 144 * @return The property value, or the default value if it doesn't exist. 145 */ 146 public final <T> T[] getArrayProperty(String key, Class<T> eType) { 147 return propertyStore.getArrayProperty(key, eType); 148 } 149 150 /** 151 * Returns the array property value with the specified name. 152 * 153 * @param key The property name. 154 * @param eType The class type of the elements in the property. 155 * @param def The default value. 156 * @return The property value, or the default value if it doesn't exist. 157 */ 158 public final <T> T[] getArrayProperty(String key, Class<T> eType, T[] def) { 159 return propertyStore.getArrayProperty(key, eType, def); 160 } 161 162 /** 163 * Returns the class array property with the specified name. 164 * 165 * @param key The property name. 166 * @return The property value, or an empty array if it doesn't exist. 167 */ 168 public final Class<?>[] getClassArrayProperty(String key) { 169 return propertyStore.getClassArrayProperty(key); 170 } 171 172 /** 173 * Returns the class array property with the specified name. 174 * 175 * @param key The property name. 176 * @param def The default value. 177 * @return The property value, or an empty array if it doesn't exist. 178 */ 179 public final Class<?>[] getClassArrayProperty(String key, Class<?>[] def) { 180 return propertyStore.getClassArrayProperty(key, def); 181 } 182 183 /** 184 * Returns the class array property with the specified name. 185 * 186 * @param key The property name. 187 * @param eType The class type of the elements in the property. 188 * @return The property value, or an empty array if it doesn't exist. 189 */ 190 public final <T> Class<T>[] getClassArrayProperty(String key, Class<T> eType) { 191 return propertyStore.getClassArrayProperty(key, eType); 192 } 193 194 /** 195 * Returns the set property with the specified name. 196 * 197 * @param key The property name. 198 * @param eType The class type of the elements in the property. 199 * @return The property value as an unmodifiable <code>LinkedHashSet</code>, or an empty set if it doesn't exist. 200 */ 201 public final <T> Set<T> getSetProperty(String key, Class<T> eType) { 202 return propertyStore.getSetProperty(key, eType); 203 } 204 205 /** 206 * Returns the set property with the specified name. 207 * 208 * @param key The property name. 209 * @param eType The class type of the elements in the property. 210 * @param def The default value if the property doesn't exist or is empty. 211 * @return The property value as an unmodifiable <code>LinkedHashSet</code>, or the default value if it doesn't exist or is empty. 212 */ 213 public final <T> Set<T> getSetProperty(String key, Class<T> eType, Set<T> def) { 214 return propertyStore.getSetProperty(key, eType, def); 215 } 216 217 /** 218 * Returns the class set property with the specified name. 219 * 220 * @param key The property name. 221 * @return The property value as an unmodifiable <code>LinkedHashSet</code>, or an empty set if it doesn't exist. 222 */ 223 public final Set<Class<?>> getClassSetProperty(String key) { 224 return propertyStore.getClassSetProperty(key); 225 } 226 227 /** 228 * Returns the class set property with the specified name. 229 * 230 * @param key The property name. 231 * @param eType The class type of the elements in the property. 232 * @return The property value as an unmodifiable <code>LinkedHashSet</code>, or an empty set if it doesn't exist. 233 */ 234 public final <T> Set<Class<T>> getClassSetProperty(String key, Class<T> eType) { 235 return propertyStore.getClassSetProperty(key, eType); 236 } 237 238 /** 239 * Returns the list property with the specified name. 240 * 241 * @param key The property name. 242 * @param eType The class type of the elements in the property. 243 * @return The property value as an unmodifiable <code>ArrayList</code>, or an empty list if it doesn't exist. 244 */ 245 public final <T> List<T> getListProperty(String key, Class<T> eType) { 246 return propertyStore.getListProperty(key, eType); 247 } 248 249 /** 250 * Returns the list property with the specified name. 251 * 252 * @param key The property name. 253 * @param eType The class type of the elements in the property. 254 * @param def The default value if the property doesn't exist or is empty. 255 * @return The property value as an unmodifiable <code>ArrayList</code>, or the default value if it doesn't exist or is empty. 256 */ 257 public final <T> List<T> getListProperty(String key, Class<T> eType, List<T> def) { 258 return propertyStore.getListProperty(key, eType, def); 259 } 260 261 /** 262 * Returns the class list property with the specified name. 263 * 264 * @param key The property name. 265 * @return The property value as an unmodifiable <code>ArrayList</code>, or an empty list if it doesn't exist. 266 */ 267 public final List<Class<?>> getClassListProperty(String key) { 268 return propertyStore.getClassListProperty(key); 269 } 270 271 /** 272 * Returns the class list property with the specified name. 273 * 274 * @param key The property name. 275 * @param eType The class type of the elements in the property. 276 * @return The property value as an unmodifiable <code>ArrayList</code>, or an empty list if it doesn't exist. 277 */ 278 public final <T> List<Class<T>> getClassListProperty(String key, Class<T> eType) { 279 return propertyStore.getClassListProperty(key, eType); 280 } 281 282 /** 283 * Returns the map property with the specified name. 284 * 285 * @param key The property name. 286 * @param eType The class type of the elements in the property. 287 * @return The property value as an unmodifiable <code>LinkedHashMap</code>, or an empty map if it doesn't exist. 288 */ 289 public final <T> Map<String,T> getMapProperty(String key, Class<T> eType) { 290 return propertyStore.getMapProperty(key, eType); 291 } 292 293 /** 294 * Returns the class map property with the specified name. 295 * 296 * @param key The property name. 297 * @return The property value as an unmodifiable <code>LinkedHashMap</code>, or an empty map if it doesn't exist. 298 */ 299 public final Map<String,Class<?>> getClassMapProperty(String key) { 300 return propertyStore.getClassMapProperty(key); 301 } 302 303 /** 304 * Returns the class map property with the specified name. 305 * 306 * @param key The property name. 307 * @param eType The class type of the elements in the property. 308 * @return The property value as an unmodifiable <code>LinkedHashMap</code>, or an empty map if it doesn't exist. 309 */ 310 public final <T> Map<String,Class<T>> getClassMapProperty(String key, Class<T> eType) { 311 return propertyStore.getClassMapProperty(key, eType); 312 } 313 314 /** 315 * Returns an instance of the specified class, string, or object property. 316 * 317 * <p> 318 * If instantiating a class, assumes the class has a no-arg constructor. 319 * Otherwise, throws a runtime exception. 320 * 321 * @param key The property name. 322 * @param type The class type of the property. 323 * @param def 324 * The default value if the property doesn't exist. 325 * <br>Can either be an instance of <code>T</code>, or a <code>Class<? <jk>extends</jk> T></code>, or <jk>null</jk>. 326 * @return A new property instance. 327 */ 328 public <T> T getInstanceProperty(String key, Class<T> type, Object def) { 329 return propertyStore.getInstanceProperty(key, type, def); 330 } 331 332 /** 333 * Returns an instance of the specified class, string, or object property. 334 * 335 * @param key The property name. 336 * @param type The class type of the property. 337 * @param def 338 * The default value if the property doesn't exist. 339 * <br>Can either be an instance of <code>T</code>, or a <code>Class<? <jk>extends</jk> T></code>. 340 * @param fuzzyArgs 341 * Use fuzzy constructor arg matching. 342 * <br>When <jk>true</jk>, constructor args can be in any order and extra args are ignored. 343 * <br>No-arg constructors are also used if no other constructors are found. 344 * @param args 345 * Arguments to pass to the constructor. 346 * Constructors matching the arguments are always used before no-arg constructors. 347 * @return A new property instance. 348 */ 349 public <T> T getInstanceProperty(String key, Class<T> type, Object def, boolean fuzzyArgs, Object...args) { 350 return propertyStore.getInstanceProperty(key, type, def, fuzzyArgs, args); 351 } 352 353 /** 354 * Returns an instance of the specified class, string, or object property. 355 * 356 * @param key The property name. 357 * @param outer The outer object if the class we're instantiating is an inner class. 358 * @param type The class type of the property. 359 * @param def 360 * The default value if the property doesn't exist. 361 * <br>Can either be an instance of <code>T</code>, or a <code>Class<? <jk>extends</jk> T></code>. 362 * @param fuzzyArgs 363 * Use fuzzy constructor arg matching. 364 * <br>When <jk>true</jk>, constructor args can be in any order and extra args are ignored. 365 * <br>No-arg constructors are also used if no other constructors are found. 366 * @param args 367 * Arguments to pass to the constructor. 368 * Constructors matching the arguments are always used before no-arg constructors. 369 * @return A new property instance. 370 */ 371 public <T> T getInstanceProperty(String key, Object outer, Class<T> type, Object def, boolean fuzzyArgs, Object...args) { 372 return propertyStore.getInstanceProperty(key, outer, type, def, fuzzyArgs, args); 373 } 374 375 /** 376 * Returns the specified property as an array of instantiated objects. 377 * 378 * @param key The property name. 379 * @param type The class type of the property. 380 * @param def The default object to return if the property doesn't exist. 381 * @return A new property instance. 382 */ 383 public <T> T[] getInstanceArrayProperty(String key, Class<T> type, T[] def) { 384 return propertyStore.getInstanceArrayProperty(key, type, def); 385 } 386 387 /** 388 * Returns the specified property as an array of instantiated objects. 389 * 390 * @param key The property name. 391 * @param type The class type of the property. 392 * @param def The default object to return if the property doesn't exist. 393 * @param fuzzyArgs 394 * Use fuzzy constructor arg matching. 395 * <br>When <jk>true</jk>, constructor args can be in any order and extra args are ignored. 396 * <br>No-arg constructors are also used if no other constructors are found. 397 * @param args 398 * Arguments to pass to the constructor. 399 * Constructors matching the arguments are always used before no-arg constructors. 400 * @return A new property instance. 401 */ 402 public <T> T[] getInstanceArrayProperty(String key, Class<T> type, T[] def, boolean fuzzyArgs, Object...args) { 403 return propertyStore.getInstanceArrayProperty(key, type, def, fuzzyArgs, args); 404 } 405 406 /** 407 * Returns the specified property as an array of instantiated objects. 408 * 409 * @param key The property name. 410 * @param outer The outer object if the class we're instantiating is an inner class. 411 * @param type The class type of the property. 412 * @param def The default object to return if the property doesn't exist. 413 * @param fuzzyArgs 414 * Use fuzzy constructor arg matching. 415 * <br>When <jk>true</jk>, constructor args can be in any order and extra args are ignored. 416 * <br>No-arg constructors are also used if no other constructors are found. 417 * @param args 418 * Arguments to pass to the constructor. 419 * Constructors matching the arguments are always used before no-arg constructors. 420 * @return A new property instance. 421 */ 422 public <T> T[] getInstanceArrayProperty(String key, Object outer, Class<T> type, T[] def, boolean fuzzyArgs, Object...args) { 423 return propertyStore.getInstanceArrayProperty(key, outer, type, def, fuzzyArgs, args); 424 } 425 426 /** 427 * Returns the keys found in the specified property group. 428 * 429 * <p> 430 * The keys are NOT prefixed with group names. 431 * 432 * @param group The group name. 433 * @return The set of property keys, or an empty set if the group was not found. 434 */ 435 public Set<String> getPropertyKeys(String group) { 436 return propertyStore.getPropertyKeys(group); 437 } 438 439 /** 440 * Returns the property store associated with this context. 441 * 442 * @return The property store associated with this context. 443 */ 444 @BeanIgnore 445 public final PropertyStore getPropertyStore() { 446 return propertyStore; 447 } 448 449 /** 450 * Creates a builder from this context object. 451 * 452 * <p> 453 * Builders are used to define new contexts (e.g. serializers, parsers) based on existing configurations. 454 * 455 * @return A new ContextBuilder object. 456 */ 457 public ContextBuilder builder() { 458 return null; 459 } 460 461 /** 462 * Create a new bean session based on the properties defined on this context. 463 * 464 * <p> 465 * Use this method for creating sessions if you don't need to override any 466 * properties or locale/timezone currently set on this context. 467 * 468 * @return A new session object. 469 */ 470 public Session createSession() { 471 return createSession(createDefaultSessionArgs()); 472 } 473 474 /** 475 * Create a new session based on the properties defined on this context combined with the specified 476 * runtime args. 477 * 478 * <p> 479 * Use this method for creating sessions if you don't need to override any 480 * properties or locale/timezone currently set on this context. 481 * 482 * @param args 483 * The session arguments. 484 * @return A new session object. 485 */ 486 public abstract Session createSession(SessionArgs args); 487 488 /** 489 * Defines default session arguments used when calling the {@link #createSession()} method. 490 * 491 * @return A SessionArgs object, possibly a read-only reusable instance. 492 */ 493 public abstract SessionArgs createDefaultSessionArgs(); 494 495 /** 496 * Returns the properties defined on this bean context as a simple map for debugging purposes. 497 * 498 * @return A new map containing the properties defined on this context. 499 */ 500 @BeanIgnore 501 public ObjectMap asMap() { 502 return new ObjectMap(); 503 } 504 505 @Override /* Object */ 506 public final int hashCode() { 507 return hashCode; 508 } 509 510 @Override /* Object */ 511 public final boolean equals(Object o) { 512 // Context objects are considered equal if they're the same class and have the same set of properties. 513 if (o == null) 514 return false; 515 if (o.getClass() != this.getClass()) 516 return false; 517 Context c = (Context)o; 518 return (c.propertyStore.equals(propertyStore)); 519 } 520 521 @Override /* Object */ 522 public String toString() { 523 try { 524 return asMap().toString(JsonSerializer.DEFAULT_LAX_READABLE); 525 } catch (SerializeException e) { 526 return e.getLocalizedMessage(); 527 } 528 } 529}