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.cp;
014
015import static org.apache.juneau.internal.CollectionUtils.*;
016import java.util.*;
017import java.util.function.*;
018
019import org.apache.juneau.*;
020
021/**
022 * Utility class for instantiating a Context bean.
023 *
024 * <p>
025 * Contains either a pre-existing Context bean, or a builder for that bean.
026 * If it's a builder, then annotations can be applied to it.
027 *
028 * <h5 class='section'>See Also:</h5><ul>
029 * </ul>
030 *
031 * @param <T> The bean type.
032 */
033public class ContextBeanCreator<T> {
034
035   /**
036    * Creator.
037    *
038    * @param <T> The bean type.
039    * @param type The bean type.
040    * @return A new creator object.
041    */
042   public static <T> ContextBeanCreator<T> create(Class<T> type) {
043      return new ContextBeanCreator<>(type);
044   }
045
046   private Class<T> type;
047   private T impl;
048   private Context.Builder builder;
049
050   /**
051    * Constructor.
052    *
053    * @param type The bean type.
054    */
055   protected ContextBeanCreator(Class<T> type) {
056      this.type = type;
057   }
058
059   /**
060    * Copy constructor.
061    *
062    * @param copyFrom The creator to copy from.
063    */
064   protected ContextBeanCreator(ContextBeanCreator<T> copyFrom) {
065      this.type = copyFrom.type;
066      this.impl = copyFrom.impl;
067      this.builder = copyFrom.builder == null ? null : copyFrom.builder.copy();
068   }
069
070   /**
071    * Sets an already instantiated object on this creator.
072    *
073    * @param value The bean to set.
074    * @return This object.
075    */
076   @SuppressWarnings("unchecked")
077   public ContextBeanCreator<T> impl(Object value) {
078      this.impl = (T)value;
079      return this;
080   }
081
082   /**
083    * Sets the implementation type of the bean.
084    *
085    * <p>
086    * The class type must extend from {@link Context} and have a builder create method.
087    *
088    * @param value The bean type.
089    * @return This object.
090    */
091   @SuppressWarnings("unchecked")
092   public ContextBeanCreator<T> type(Class<? extends T> value) {
093      builder = Context.createBuilder((Class<? extends Context>) value);
094      if (builder == null)
095         throw new IllegalArgumentException("Creator for class {0} not found." + value.getName());
096      return this;
097   }
098
099   /**
100    * Returns access to the inner builder if the builder exists and is of the specified type.
101    *
102    * @param <B> The builder class type.
103    * @param c The builder class type.
104    * @return An optional containing the builder if it exists.
105    */
106   public <B extends Context.Builder> Optional<B> builder(Class<B> c) {
107      return optional(c.isInstance(builder) ? c.cast(builder) : null);
108   }
109
110   /**
111    * Applies an operation to the builder in this creator object.
112    *
113    * <p>
114    * Typically used to allow you to execute operations without breaking the fluent flow of the client builder.
115    * The operation is ignored if the builder isn't the specified type.
116    *
117    * @param <B> The builder class type.
118    * @param c The builder class type.
119    * @param operation The operation to apply.
120    * @return This object.
121    */
122   public <B extends Context.Builder> ContextBeanCreator<T> builder(Class<B> c, Consumer<B> operation) {
123      if (c.isInstance(builder))
124         operation.accept(c.cast(builder));
125      return this;
126   }
127
128   /**
129    * Returns true if any of the annotations/appliers can be applied to the inner builder (if it has one).
130    *
131    * @param work The work to check.
132    * @return This object.
133    */
134   public boolean canApply(AnnotationWorkList work) {
135      if (builder != null)
136         return (builder.canApply(work));
137      return false;
138   }
139
140   /**
141    * Applies the specified annotations to all applicable serializer builders in this group.
142    *
143    * @param work The annotations to apply.
144    * @return This object.
145    */
146   public ContextBeanCreator<T> apply(AnnotationWorkList work) {
147      if (builder != null)
148         builder.apply(work);
149      return this;
150   }
151
152   /**
153    * Creates a new copy of this creator.
154    *
155    * @return A new copy of this creator.
156    */
157   public ContextBeanCreator<T> copy() {
158      return new ContextBeanCreator<>(this);
159   }
160
161   /**
162    * Returns the built bean.
163    *
164    * @return The built bean.
165    */
166   @SuppressWarnings("unchecked")
167   public T create() {
168      if (impl != null)
169         return impl;
170      if (builder != null)
171         return (T)builder.build();
172      return null;
173   }
174}