001package io.avaje.inject;
002
003import java.util.List;
004
005/**
006 * Provides a global system wide BeanScope that contains all the beans.
007 * <p>
008 * This will automatically get all the beans and wire them all as necessary. It will use
009 * a shutdown hook to fire any <code>@PreDestroy</code> methods on beans.
010 * </p>
011 *
012 * <h3>Example: get a bean</h3>
013 * <pre>{@code
014 *
015 *   CoffeeMaker coffeeMaker = ApplicationScope.get(CoffeeMaker.class);
016 *   coffeeMaker.brew();
017 *
018 * }</pre>
019 *
020 * <h3>Example: get all the beans implementing an interface</h3>
021 * <pre>{@code
022 *
023 *   // e.g. register all WebRoutes for a web framework
024 *
025 *   List<WebRoute> routes = ApplicationScope.list(WebRoute.class);
026 *
027 *   // register all the routes ...
028 *
029 * }</pre>
030 */
031public class ApplicationScope {
032
033  private static final BeanScope appScope = init();
034
035  private static BeanScope init() {
036    return BeanScope.newBuilder().build();
037  }
038
039  private ApplicationScope() {
040    // hide
041  }
042
043  /**
044   * Return the underlying BeanScope.
045   */
046  public static BeanScope scope() {
047    return appScope;
048  }
049
050  /**
051   * Return a single bean given the type.
052   *
053   * <pre>{@code
054   *
055   *   CoffeeMaker coffeeMaker = ApplicationScope.get(CoffeeMaker.class);
056   *   coffeeMaker.brew();
057   *
058   * }</pre>
059   *
060   * @param type an interface or bean type
061   */
062  public static <T> T get(Class<T> type) {
063    return appScope.get(type);
064  }
065
066  /**
067   * Return a single bean given the type and name.
068   *
069   * <pre>{@code
070   *
071   *   Heater heater = ApplicationScope.get(Heater.class, "electric");
072   *   heater.heat();
073   *
074   * }</pre>
075   *
076   * @param type an interface or bean type
077   * @param name the name qualifier of a specific bean
078   */
079  public static <T> T get(Class<T> type, String name) {
080    return appScope.get(type, name);
081  }
082
083
084  /**
085   * Return the list of beans that implement the interface.
086   *
087   * <pre>{@code
088   *
089   *   // e.g. register all web routes with web a framework
090   *
091   *   List<WebRoute> routes = ApplicationScope.list(WebRoute.class);
092   *
093   * }</pre>
094   *
095   * @param interfaceType An interface class.
096   */
097  public static <T> List<T> list(Class<T> interfaceType) {
098    return appScope.list(interfaceType);
099  }
100
101  /**
102   * Return the list of beans that implement the interface ordering based on <code>@Priority</code>.
103   *
104   * <pre>{@code
105   *
106   *   // e.g. register all web routes with web a framework
107   *
108   *   List<WebRoute> routes = ApplicationScope.listByPriority(WebRoute.class);
109   *
110   * }</pre>
111   *
112   * @param interfaceType An interface class.
113   */
114  public static <T> List<T> listByPriority(Class<T> interfaceType) {
115    return appScope.listByPriority(interfaceType);
116  }
117
118  /**
119   * Return the list of beans that have an annotation.
120   *
121   * <pre>{@code
122   *
123   *   // e.g. register all controllers with web a framework
124   *   // .. where Controller is an annotation on the beans
125   *
126   *   List<Object> controllers = ApplicationScope.listByAnnotation(Controller.class);
127   *
128   * }</pre>
129   *
130   * <p>
131   * The classic use case for this is registering controllers or routes to
132   * web frameworks like Sparkjava, Javalin, Rapidoid etc.
133   *
134   * @param annotation An annotation class.
135   */
136  public static List<Object> listByAnnotation(Class<?> annotation) {
137    return appScope.listByAnnotation(annotation);
138  }
139
140  /**
141   * Start building a RequestScope.
142   *
143   * <pre>{@code
144   *
145   *   try (RequestScope requestScope = ApplicationScope.newRequestScope()
146   *       // supply some instances
147   *       .withBean(HttpRequest.class, request)
148   *       .withBean(HttpResponse.class, response)
149   *       .build()) {
150   *
151   *       MyController controller = requestScope.get(MyController.class);
152   *       controller.process();
153   *
154   *   }
155   *
156   *   ...
157   *
158   *   // define request scoped beans
159   *   @Request
160   *   MyController {
161   *
162   *     // can depend on supplied instances, singletons and other request scope beans
163   *     @Inject
164   *     MyController(HttpRequest request, HttpResponse response, MyService myService) {
165   *       ...
166   *     }
167   *
168   *   }
169   *
170   * }</pre>
171   *
172   * @return The request scope builder
173   */
174  public static RequestScopeBuilder newRequestScope() {
175    return appScope.newRequestScope();
176  }
177}