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 fromClass The class on which the annotations are defined.
154    * @return This object (for method chaining).
155    */
156   public ContextBuilder applyAnnotations(Class<?> fromClass) {
157      applyAnnotations(ClassInfo.of(fromClass).getAnnotationListParentFirst(ConfigAnnotationFilter.INSTANCE), VarResolver.DEFAULT.createSession());
158      return this;
159   }
160
161   /**
162    * Applies any of the various <ja>@XConfig</ja> annotations on the specified method to this context.
163    *
164    * <p>
165    * Applies any of the following annotations:
166    * <ul class='javatree'>
167    *    <li class ='ja'>{@link BeanConfig}
168    *    <li class ='ja'>{@link CsvConfig}
169    *    <li class ='ja'>{@link HtmlConfig}
170    *    <li class ='ja'>{@link HtmlDocConfig}
171    *    <li class ='ja'>{@link JsoConfig}
172    *    <li class ='ja'>{@link JsonConfig}
173    *    <li class ='ja'>{@link JsonSchemaConfig}
174    *    <li class ='ja'>{@link MsgPackConfig}
175    *    <li class ='ja'>{@link OpenApiConfig}
176    *    <li class ='ja'>{@link ParserConfig}
177    *    <li class ='ja'>{@link PlainTextConfig}
178    *    <li class ='ja'>{@link SerializerConfig}
179    *    <li class ='ja'>{@link SoapXmlConfig}
180    *    <li class ='ja'>{@link UonConfig}
181    *    <li class ='ja'>{@link UrlEncodingConfig}
182    *    <li class ='ja'>{@link XmlConfig}
183    *    <li class ='ja'><c>RdfConfig</c>
184    * </ul>
185    *
186    * <p>
187    * Annotations are appended in the following orders:
188    * <ol>
189    *    <li>On the package of the method class.
190    *    <li>On interfaces ordered parent-to-child.
191    *    <li>On parent classes ordered parent-to-child.
192    *    <li>On the method class.
193    *    <li>On this method and matching methods ordered parent-to-child.
194    * </ol>
195    *
196    * @param fromMethod The method on which the annotations are defined.
197    * @return This object (for method chaining).
198    */
199   public ContextBuilder applyAnnotations(Method fromMethod) {
200      applyAnnotations(MethodInfo.of(fromMethod).getAnnotationListParentFirst(ConfigAnnotationFilter.INSTANCE), VarResolver.DEFAULT.createSession());
201      return this;
202   }
203
204   /**
205    * Build a new instance of the specified object.
206    *
207    * @param c The subclass of {@link Context} to instantiate.
208    * @return A new object using the settings defined in this builder.
209    */
210
211   public <T extends Context> T build(Class<T> c) {
212      return ContextCache.INSTANCE.create(c, getPropertyStore());
213   }
214
215   /**
216    * Returns a read-only snapshot of the current property store on this builder.
217    *
218    * @return A property store object.
219    */
220   public PropertyStore getPropertyStore() {
221      return psb.build();
222   }
223
224   //-----------------------------------------------------------------------------------------------------------------
225   // Properties
226   //-----------------------------------------------------------------------------------------------------------------
227
228   /**
229    * Sets a configuration property on this object.
230    *
231    * @param name The property name.
232    * @param value The property value.
233    * @return This object (for method chaining).
234    * @see PropertyStoreBuilder#set(String, Object)
235    */
236   public ContextBuilder set(String name, Object value) {
237      psb.set(name, value);
238      return this;
239   }
240
241   /**
242    * Peeks at a configuration property on this object.
243    *
244    * @param key The property name.
245    * @return This object (for method chaining).
246    */
247   public Object peek(String key) {
248      return psb.peek(key);
249   }
250
251   /**
252    * Peeks at a configuration property on this object.
253    *
254    * @param c The type to convert to.
255    * @param key The property name.
256    * @return This object (for method chaining).
257    * @param <T> The type to convert to.
258    */
259   public <T> T peek(Class<T> c, String key) {
260      return psb.peek(c, key);
261   }
262
263   /**
264    * Sets multiple configuration properties on this object.
265    *
266    * @param properties The properties to set on this class.
267    * @return This object (for method chaining).
268    * @see PropertyStoreBuilder#set(java.util.Map)
269    */
270   public ContextBuilder set(Map<String,Object> properties) {
271      psb.set(properties);
272      return this;
273   }
274
275   /**
276    * Adds multiple configuration properties on this object.
277    *
278    * @param properties The properties to set on this class.
279    * @return This object (for method chaining).
280    * @see PropertyStoreBuilder#add(java.util.Map)
281    */
282   public ContextBuilder add(Map<String,Object> properties) {
283      psb.add(properties);
284      return this;
285   }
286
287   /**
288    * Adds a value to a SET or LIST property.
289    *
290    * @param name The property name.
291    * @param value The new value to add to the SET property.
292    * @return This object (for method chaining).
293    * @throws ConfigException If property is not a SET property.
294    */
295   public ContextBuilder addTo(String name, Object value) {
296      psb.addTo(name, value);
297      return this;
298   }
299
300   /**
301    * Adds or overwrites a value to a SET, LIST, or MAP property.
302    *
303    * @param name The property name.
304    * @param key The property value map key.
305    * @param value The property value map value.
306    * @return This object (for method chaining).
307    * @throws ConfigException If property is not a MAP property.
308    */
309   public ContextBuilder addTo(String name, String key, Object value) {
310      psb.addTo(name, key, value);
311      return this;
312   }
313
314   /**
315    * Removes a value from a SET, LIST, or MAP property.
316    *
317    * @param name The property name.
318    * @param value The property value in the SET property.
319    * @return This object (for method chaining).
320    * @throws ConfigException If property is not a SET property.
321    */
322   public ContextBuilder removeFrom(String name, Object value) {
323      psb.removeFrom(name, value);
324      return this;
325   }
326}