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