001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.juneau;
018
019import static org.apache.juneau.commons.utils.Utils.*;
020
021import java.util.*;
022
023import org.apache.juneau.cp.*;
024
025/**
026 * Base class for bean builders.
027 *
028 *
029 * @param <T> The bean type that the builder creates.
030 */
031public class BeanBuilder<T> {
032
033   private Class<? extends T> type, defaultType;
034   private T impl;
035   private final BeanStore beanStore;
036
037   /**
038    * Copy constructor.
039    *
040    * @param copyFrom The bean store to copy from.
041    */
042   protected BeanBuilder(BeanBuilder<T> copyFrom) {
043      type = copyFrom.type;
044      impl = copyFrom.impl;
045      beanStore = copyFrom.beanStore;
046   }
047
048   /**
049    * Constructor.
050    *
051    * @param beanStore The bean store to use for creating beans.
052    * @param defaultType The default bean type that this builder creates.
053    */
054   protected BeanBuilder(Class<? extends T> defaultType, BeanStore beanStore) {
055      this.defaultType = type = defaultType;
056      this.beanStore = beanStore;
057   }
058
059   /**
060    * Returns the bean store passed in through the constructor.
061    *
062    * @return The bean store passed in through the constructor.
063    */
064   public BeanStore beanStore() {
065      return beanStore;
066   }
067
068   /**
069    * Creates the bean.
070    *
071    * @return A new bean.
072    */
073   public T build() {
074      if (nn(impl))
075         return impl;
076      if (type == null || type == defaultType)
077         return buildDefault();
078      return creator().run();
079   }
080
081   /**
082    * Overrides the bean returned by the {@link #build()} method.
083    *
084    * <p>
085    * Use this method if you want this builder to return an already-instantiated bean.
086    *
087    * @param value The setting value.
088    * @return  This object.
089    */
090   @SuppressWarnings("unchecked")
091   public BeanBuilder<T> impl(Object value) {
092      impl = (T)value;
093      return this;
094   }
095
096   /**
097    * Overrides the bean type produced by the {@link #build()} method.
098    *
099    * <p>
100    * Use this method if you want to instantiated a bean subclass.
101    *
102    * @param value The setting value.
103    * @return  This object.
104    */
105   @SuppressWarnings("unchecked")
106   public BeanBuilder<T> type(Class<?> value) {
107      type = (Class<T>)value;
108      return this;
109   }
110
111   /**
112    * Creates the bean when the bean type is <jk>null</jk> or is the default value.
113    *
114    * @return A new bean.
115    */
116   protected T buildDefault() {
117      return beanStore.createBean(type().orElseThrow(() -> new IllegalStateException("Type not specified."))).builder(BeanBuilder.class, this).run();
118   }
119
120   /**
121    * Instantiates the creator for this bean.
122    *
123    * <p>
124    * Subclasses can override this to provide specialized handling.
125    *
126    * @return The creator for this bean.
127    */
128   protected BeanCreator<? extends T> creator() {
129      return beanStore.createBean(type().orElseThrow(() -> new IllegalStateException("Type not specified."))).builder(BeanBuilder.class, this);
130   }
131
132   /**
133    * Returns the override bean specified via {@link #impl(Object)}.
134    *
135    * @return The override bean specified via {@link #impl(Object)}.
136    */
137   protected Optional<T> impl() {
138      return opt(impl);
139   }
140
141   /**
142    * Returns the implementation type specified via {@link #type(Class)}.
143    *
144    * @return The implementation type specified via {@link #type(Class)}.
145    */
146   protected Optional<Class<? extends T>> type() {
147      return opt(type);
148   }
149}