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 static org.apache.juneau.internal.CollectionUtils.*;
016import java.util.*;
017
018import org.apache.juneau.cp.*;
019import org.apache.juneau.internal.*;
020
021/**
022 * Base class for bean builders.
023 *
024 * <h5 class='section'>See Also:</h5><ul>
025 * </ul>
026 *
027 * @param <T> The bean type that the builder creates.
028 */
029@FluentSetters
030public class BeanBuilder<T> {
031
032   private Class<? extends T> type, defaultType;
033   private T impl;
034   private final BeanStore beanStore;
035
036   /**
037    * Constructor.
038    *
039    * @param beanStore The bean store to use for creating beans.
040    * @param defaultType The default bean type that this builder creates.
041    */
042   protected BeanBuilder(Class<? extends T> defaultType, BeanStore beanStore) {
043      this.defaultType = type = defaultType;
044      this.beanStore = beanStore;
045   }
046
047   /**
048    * Constructor.
049    *
050    * @param defaultType The type of bean being created.
051    */
052   protected BeanBuilder(Class<? extends T> defaultType) {
053      this(defaultType, BeanStore.INSTANCE);
054   }
055
056   /**
057    * Copy constructor.
058    *
059    * @param copyFrom The bean store to copy from.
060    */
061   protected BeanBuilder(BeanBuilder<T> copyFrom) {
062      type = copyFrom.type;
063      impl = copyFrom.impl;
064      beanStore = copyFrom.beanStore;
065   }
066
067   /**
068    * Creates the bean.
069    *
070    * @return A new bean.
071    */
072   public T build() {
073      if (impl != null)
074         return impl;
075      if (type == null || type == defaultType)
076         return buildDefault();
077      return creator().run();
078   }
079
080   /**
081    * Instantiates the creator for this bean.
082    *
083    * <p>
084    * Subclasses can override this to provide specialized handling.
085    *
086    * @return The creator for this bean.
087    */
088   protected BeanCreator<? extends T> creator() {
089      return beanStore
090         .createBean(type().orElseThrow(()->new RuntimeException("Type not specified.")))
091         .builder(BeanBuilder.class, this);
092   }
093
094   /**
095    * Creates the bean when the bean type is <jk>null</jk> or is the default value.
096    *
097    * @return A new bean.
098    */
099   protected T buildDefault() {
100      return beanStore
101         .createBean(type().orElseThrow(()->new RuntimeException("Type not specified.")))
102         .builder(BeanBuilder.class, this)
103         .run();
104   }
105
106   /**
107    * Overrides the bean type produced by the {@link #build()} method.
108    *
109    * <p>
110    * Use this method if you want to instantiated a bean subclass.
111    *
112    * @param value The setting value.
113    * @return  This object.
114    */
115   @SuppressWarnings("unchecked")
116   @FluentSetter
117   public BeanBuilder<T> type(Class<?> value) {
118      type = (Class<T>)value;
119      return this;
120   }
121
122   /**
123    * Returns the implementation type specified via {@link #type(Class)}.
124    *
125    * @return The implementation type specified via {@link #type(Class)}.
126    */
127   protected Optional<Class<? extends T>> type() {
128      return optional(type);
129   }
130
131   /**
132    * Overrides the bean returned by the {@link #build()} method.
133    *
134    * <p>
135    * Use this method if you want this builder to return an already-instantiated bean.
136    *
137    * @param value The setting value.
138    * @return  This object.
139    */
140   @FluentSetter
141   @SuppressWarnings("unchecked")
142   public BeanBuilder<T> impl(Object value) {
143      this.impl = (T)value;
144      return this;
145   }
146
147   /**
148    * Returns the override bean specified via {@link #impl(Object)}.
149    *
150    * @return The override bean specified via {@link #impl(Object)}.
151    */
152   protected Optional<T> impl() {
153      return optional(impl);
154   }
155
156   /**
157    * Returns the bean store passed in through the constructor.
158    *
159    * @return The bean store passed in through the constructor.
160    */
161   public BeanStore beanStore() {
162      return beanStore;
163   }
164
165   // <FluentSetters>
166
167   // </FluentSetters>
168}