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&lt;? <jk>extends</jk> T&gt;</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&lt;? <jk>extends</jk> T&gt;</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&lt;? <jk>extends</jk> T&gt;</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}