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.lang.reflect.*;
016import java.util.*;
017
018import org.apache.juneau.annotation.*;
019import org.apache.juneau.csv.annotation.*;
020import org.apache.juneau.html.annotation.*;
021import org.apache.juneau.jso.annotation.*;
022import org.apache.juneau.json.annotation.*;
023import org.apache.juneau.jsonschema.annotation.*;
024import org.apache.juneau.msgpack.annotation.*;
025import org.apache.juneau.oapi.annotation.*;
026import org.apache.juneau.parser.annotation.*;
027import org.apache.juneau.plaintext.annotation.*;
028import org.apache.juneau.reflect.*;
029import org.apache.juneau.serializer.annotation.*;
030import org.apache.juneau.soap.annotation.*;
031import org.apache.juneau.svl.*;
032import org.apache.juneau.uon.annotation.*;
033import org.apache.juneau.urlencoding.annotation.*;
034import org.apache.juneau.xml.annotation.*;
035
036/**
037 * Builder class for building instances of serializers and parsers.
038 */
039public abstract class ContextBuilder {
040
041   /** Contains all the modifiable settings for the implementation class. */
042   protected final PropertyStoreBuilder psb;
043
044   /**
045    * Constructor.
046    * Default settings.
047    */
048   public ContextBuilder() {
049      this.psb = PropertyStore.create();
050   }
051
052   /**
053    * Constructor.
054    *
055    * @param ps The initial configuration settings for this builder.
056    */
057   public ContextBuilder(PropertyStore ps) {
058      if (ps == null)
059         ps = PropertyStore.DEFAULT;
060      this.psb = ps.builder();
061   }
062
063   /**
064    * Constructor.
065    *
066    * <p>
067    * Used in cases where multiple context builder are sharing the same property store builder.
068    * <br>(e.g. <c>HtlmlDocBuilder</c>)
069    *
070    * @param psb The property store builder to use.
071    */
072   protected ContextBuilder(PropertyStoreBuilder psb) {
073      this.psb = psb;
074   }
075
076   /**
077    * Returns access to the inner property store builder.
078    *
079    * <p>
080    * Used in conjunction with {@link #ContextBuilder(PropertyStoreBuilder)} when builders share property store builders.
081    *
082    * @return The inner property store builder.
083    */
084   protected PropertyStoreBuilder getPropertyStoreBuilder() {
085      return psb;
086   }
087
088   /**
089    * Build the object.
090    *
091    * @return The built object.
092    * Subsequent calls to this method will create new instances.
093    */
094   public abstract Context build();
095
096   /**
097    * Copies the settings from the specified property store into this builder.
098    *
099    * @param copyFrom The factory whose settings are being copied.
100    * @return This object (for method chaining).
101    */
102   public ContextBuilder apply(PropertyStore copyFrom) {
103      this.psb.apply(copyFrom);
104      return this;
105   }
106
107   /**
108    * Applies a set of annotations to this property store.
109    *
110    * @param al The list of all annotations annotated with {@link PropertyStoreApply}.
111    * @param r The string resolver for resolving variables in annotation values.
112    * @return This object (for method chaining).
113    */
114   public ContextBuilder applyAnnotations(AnnotationList al, VarResolverSession r) {
115      this.psb.applyAnnotations(al, r);
116      return this;
117   }
118
119   /**
120    * Applies any of the various <ja>@XConfig</ja> annotations on the specified class to this context.
121    *
122    * <p>
123    * Applies any of the following annotations:
124    * <ul class='javatree'>
125    *    <li class ='ja'>{@link BeanConfig}
126    *    <li class ='ja'>{@link CsvConfig}
127    *    <li class ='ja'>{@link HtmlConfig}
128    *    <li class ='ja'>{@link HtmlDocConfig}
129    *    <li class ='ja'>{@link JsoConfig}
130    *    <li class ='ja'>{@link JsonConfig}
131    *    <li class ='ja'>{@link JsonSchemaConfig}
132    *    <li class ='ja'>{@link MsgPackConfig}
133    *    <li class ='ja'>{@link OpenApiConfig}
134    *    <li class ='ja'>{@link ParserConfig}
135    *    <li class ='ja'>{@link PlainTextConfig}
136    *    <li class ='ja'>{@link SerializerConfig}
137    *    <li class ='ja'>{@link SoapXmlConfig}
138    *    <li class ='ja'>{@link UonConfig}
139    *    <li class ='ja'>{@link UrlEncodingConfig}
140    *    <li class ='ja'>{@link XmlConfig}
141    *    <li class ='ja'><c>RdfConfig</c>
142    * </ul>
143    *
144    * <p>
145    * Annotations are appended in the following order:
146    * <ol>
147    *    <li>On the package of this class.
148    *    <li>On interfaces ordered parent-to-child.
149    *    <li>On parent classes ordered parent-to-child.
150    *    <li>On this class.
151    * </ol>
152    *
153    * @param fromClasses The classes on which the annotations are defined.
154    * @return This object (for method chaining).
155    */
156   public ContextBuilder applyAnnotations(Class<?>...fromClasses) {
157      for (Class<?> c : fromClasses)
158         applyAnnotations(ClassInfo.of(c).getAnnotationListParentFirst(ConfigAnnotationFilter.INSTANCE), VarResolver.DEFAULT.createSession());
159      return this;
160   }
161
162   /**
163    * Applies any of the various <ja>@XConfig</ja> annotations on the specified method to this context.
164    *
165    * <p>
166    * Applies any of the following annotations:
167    * <ul class='javatree'>
168    *    <li class ='ja'>{@link BeanConfig}
169    *    <li class ='ja'>{@link CsvConfig}
170    *    <li class ='ja'>{@link HtmlConfig}
171    *    <li class ='ja'>{@link HtmlDocConfig}
172    *    <li class ='ja'>{@link JsoConfig}
173    *    <li class ='ja'>{@link JsonConfig}
174    *    <li class ='ja'>{@link JsonSchemaConfig}
175    *    <li class ='ja'>{@link MsgPackConfig}
176    *    <li class ='ja'>{@link OpenApiConfig}
177    *    <li class ='ja'>{@link ParserConfig}
178    *    <li class ='ja'>{@link PlainTextConfig}
179    *    <li class ='ja'>{@link SerializerConfig}
180    *    <li class ='ja'>{@link SoapXmlConfig}
181    *    <li class ='ja'>{@link UonConfig}
182    *    <li class ='ja'>{@link UrlEncodingConfig}
183    *    <li class ='ja'>{@link XmlConfig}
184    *    <li class ='ja'><c>RdfConfig</c>
185    * </ul>
186    *
187    * <p>
188    * Annotations are appended in the following orders:
189    * <ol>
190    *    <li>On the package of the method class.
191    *    <li>On interfaces ordered parent-to-child.
192    *    <li>On parent classes ordered parent-to-child.
193    *    <li>On the method class.
194    *    <li>On this method and matching methods ordered parent-to-child.
195    * </ol>
196    *
197    * @param fromMethods The methods on which the annotations are defined.
198    * @return This object (for method chaining).
199    */
200   public ContextBuilder applyAnnotations(Method...fromMethods) {
201      for (Method m : fromMethods)
202         applyAnnotations(MethodInfo.of(m).getAnnotationListParentFirst(ConfigAnnotationFilter.INSTANCE), VarResolver.DEFAULT.createSession());
203      return this;
204   }
205
206   /**
207    * Build a new instance of the specified object.
208    *
209    * @param c The subclass of {@link Context} to instantiate.
210    * @return A new object using the settings defined in this builder.
211    */
212
213   public <T extends Context> T build(Class<T> c) {
214      return ContextCache.INSTANCE.create(c, getPropertyStore());
215   }
216
217   /**
218    * Returns a read-only snapshot of the current property store on this builder.
219    *
220    * @return A property store object.
221    */
222   public PropertyStore getPropertyStore() {
223      return psb.build();
224   }
225
226   //-----------------------------------------------------------------------------------------------------------------
227   // Properties
228   //-----------------------------------------------------------------------------------------------------------------
229
230   /**
231    * Sets a configuration property on this object.
232    *
233    * @param name The property name.
234    * @param value The property value.
235    * @return This object (for method chaining).
236    * @see PropertyStoreBuilder#set(String, Object)
237    */
238   public ContextBuilder set(String name, Object value) {
239      psb.set(name, value);
240      return this;
241   }
242
243   /**
244    * Peeks at a configuration property on this object.
245    *
246    * @param key The property name.
247    * @return This object (for method chaining).
248    */
249   public Object peek(String key) {
250      return psb.peek(key);
251   }
252
253   /**
254    * Peeks at a configuration property on this object.
255    *
256    * @param c The type to convert to.
257    * @param key The property name.
258    * @return This object (for method chaining).
259    * @param <T> The type to convert to.
260    */
261   public <T> T peek(Class<T> c, String key) {
262      return psb.peek(c, key);
263   }
264
265   /**
266    * Sets multiple configuration properties on this object.
267    *
268    * @param properties The properties to set on this class.
269    * @return This object (for method chaining).
270    * @see PropertyStoreBuilder#set(java.util.Map)
271    */
272   public ContextBuilder set(Map<String,Object> properties) {
273      psb.set(properties);
274      return this;
275   }
276
277   /**
278    * Adds multiple configuration properties on this object.
279    *
280    * @param properties The properties to set on this class.
281    * @return This object (for method chaining).
282    * @see PropertyStoreBuilder#add(java.util.Map)
283    */
284   public ContextBuilder add(Map<String,Object> properties) {
285      psb.add(properties);
286      return this;
287   }
288
289   /**
290    * Adds a value to a SET or LIST property.
291    *
292    * @param name The property name.
293    * @param value The new value to add to the SET property.
294    * @return This object (for method chaining).
295    * @throws ConfigException If property is not a SET property.
296    */
297   public ContextBuilder addTo(String name, Object value) {
298      psb.addTo(name, value);
299      return this;
300   }
301
302   /**
303    * Adds or overwrites a value to a SET, LIST, or MAP property.
304    *
305    * @param name The property name.
306    * @param key The property value map key.
307    * @param value The property value map value.
308    * @return This object (for method chaining).
309    * @throws ConfigException If property is not a MAP property.
310    */
311   public ContextBuilder addTo(String name, String key, Object value) {
312      psb.addTo(name, key, value);
313      return this;
314   }
315
316   /**
317    * Removes a value from a SET, LIST, or MAP property.
318    *
319    * @param name The property name.
320    * @param value The property value in the SET property.
321    * @return This object (for method chaining).
322    * @throws ConfigException If property is not a SET property.
323    */
324   public ContextBuilder removeFrom(String name, Object value) {
325      psb.removeFrom(name, value);
326      return this;
327   }
328}