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