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