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