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.rest.server.servlet;
018
019import java.util.concurrent.atomic.*;
020
021import org.apache.juneau.rest.server.*;
022
023/**
024 * Optional base class for <c>@Rest</c> mixin classes &mdash; the third sibling of {@link RestServlet}
025 * (servlet flavor) and {@link RestResource} (child-resource flavor), completing the
026 * servlet / resource / mixin naming triad.
027 *
028 * <p>
029 * A <i>mixin</i> is a plain {@link Rest @Rest}-annotated POJO whose {@code @RestOp} methods are pulled
030 * into a host servlet/resource context when the host declares
031 * {@link Rest#mixins() @Rest(mixins=ThatMixin.class)}. Mixins compose through the existing sub-context
032 * model; {@code RestMixin} does <b>not</b> change that composition mechanism.
033 *
034 * <h5 class='section'>Opt-in, not mandatory:</h5>
035 *
036 * <p>
037 * Extending {@code RestMixin} is <b>optional</b>. A bare {@code @Rest} POJO with no base class remains a
038 * fully-supported mixin (annotation-only configuration), exactly as before &mdash; the framework reads
039 * such mixins reflectively. Capability mixins that ship without state (e.g. the api-docs pack) stay
040 * base-less; the new single-responsibility op-mixins extend this base to make the triad membership
041 * explicit.
042 *
043 * <h5 class='section'>Builder support:</h5>
044 *
045 * <p>
046 * The fluent programmatic-builder surface ({@link RestBuilder}/ {@link Builder}) lets a mixin be configured
047 * programmatically rather than (or in addition to) by annotation &mdash; builder-supplied values take precedence
048 * over {@link Rest @Rest} annotation values.  Use {@link #builder(Class)} for the common case, or subclass
049 * {@link Builder} for capability mixins that add their own setters.
050 *
051 * <h5 class='section'>Reaching the host resource:</h5>
052 *
053 * <p>
054 * Because a mixin's {@code @RestOp} methods are bound to a per-mixin {@link RestContext} sub-context (the
055 * sub-context has no children of its own), host-level introspection performed against the mixin's <i>own</i>
056 * context comes back empty.  {@link #getHostContext()} bridges that gap: it returns the {@link RestContext} of
057 * the host (mixed-into) resource so a mixin op can enumerate the host's child resources, swagger, stats, etc.
058 *
059 * <p class='bjava'>
060 *    <jc>// Render the host's child-resource navigation list from a mixin op.</jc>
061 *    <ja>@RestGet</ja>(path=<js>"/"</js>)
062 *    <jk>public</jk> ChildResourceDescriptions getChildren(RestRequest <jv>req</jv>) {
063 *       <jk>return new</jk> ChildResourceDescriptions(getHostContext(), <jv>req</jv>);
064 *    }
065 * </p>
066 *
067 * <h5 class='section'>See Also:</h5><ul>
068 *    <li class='jc'>{@link RestServlet}
069 *    <li class='jc'>{@link RestResource}
070 *    <li class='jm'>{@link #getHostContext()}
071 *    <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/RestServerComposition">REST Server — Mixins and Multi-Mount Paths</a>
072 * </ul>
073 *
074 * @since 10.0.0
075 */
076public abstract class RestMixin {
077
078   /**
079    * The per-mixin {@link RestContext} sub-context this mixin instance is bound to, captured via
080    * {@link #setContext(RestContext)} when the host composes the mixin.
081    *
082    * <p>
083    * Remains {@code null} when a {@code RestMixin} subclass is instantiated directly (not composed via
084    * {@link Rest#mixins() @Rest(mixins=...)}), in which case {@link #getHostContext()} returns {@code null}.
085    */
086   private final AtomicReference<RestContext> context = new AtomicReference<>();
087
088   /**
089    * The programmatic configuration builder stashed on this instance, or <jk>null</jk> when the
090    * mixin was constructed without a builder.  Mutable so it can be written by either the
091    * {@link #RestMixin(RestBuilder)} constructor or {@link Builder#build()}.  Read non-reflectively by
092    * {@link RestContext} during mixin sub-context construction so builder-supplied values take precedence over
093    * {@link Rest @Rest} annotation values.
094    */
095   RestBuilder<?> restBuilder;
096
097   /**
098    * Default constructor.
099    */
100   protected RestMixin() {}
101
102   /**
103    * Builder-injection constructor.
104    *
105    * @param builder The programmatic configuration builder.  May be <jk>null</jk>.
106    */
107   protected RestMixin(RestBuilder<?> builder) {
108      this.restBuilder = builder;
109   }
110
111   /**
112    * Returns the programmatic configuration builder stashed on this mixin, or <jk>null</jk> if none.
113    *
114    * @return The stashed builder, or <jk>null</jk> if none was injected.
115    */
116   @SuppressWarnings({
117      "java:S1452" // RestBuilder<?> wildcard return intentional; concrete builder type varies by REST resource class
118   })
119   public RestBuilder<?> getRestBuilder() {
120      return restBuilder;
121   }
122
123   /**
124    * Creates a new fluent builder for programmatically configuring an instance of the specified mixin type.
125    *
126    * @param <R> The mixin type.
127    * @param type The mixin type to build.  Must not be <jk>null</jk>.
128    * @return A new builder.
129    */
130   public static <R extends RestMixin> DefaultBuilder<R> builder(Class<R> type) {
131      return new DefaultBuilder<>(type);
132   }
133
134   /**
135    * Captures the per-mixin {@link RestContext} sub-context this mixin instance is bound to.
136    *
137    * <p>
138    * Invoked reflectively by the host's {@code RestContext.buildMixinContext(...)} while composing the mixin
139    * (mirroring the {@code setContext(RestContext)} contract honored by {@link RestServlet} and
140    * {@link RestResource} for child resources).  The supplied context is the mixin sub-context whose
141    * {@link RestContext#getParentContext() parent} is the host &mdash; that linkage is what {@link #getHostContext()}
142    * reads.
143    *
144    * @param value The mixin sub-context. Must not be <jk>null</jk>.
145    */
146   protected void setContext(RestContext value) {
147      context.set(value);
148   }
149
150   /**
151    * Returns the {@link RestContext} of the host (mixed-into) resource this mixin is composed into.
152    *
153    * <p>
154    * A mixin's {@code @RestOp} methods are bound to a per-mixin sub-context that has no children of its own;
155    * this accessor returns the host context so a mixin op (or config-time code) can introspect the host
156    * &mdash; most commonly its child resources via {@link RestContext#getRestChildren()} for the navigation
157    * page.  It is backed by the mixin sub-context's already-populated
158    * {@link RestContext#getParentContext() parent linkage}, so it is usable at config time and does not depend
159    * on an in-flight request.
160    *
161    * <h5 class='section'>Edge cases:</h5><ul>
162    *    <li class='note'><b>Standalone / no host</b> &mdash; when a {@code RestMixin} subclass is instantiated
163    *       directly rather than composed via {@link Rest#mixins() @Rest(mixins=...)}, this returns {@code null},
164    *       mirroring {@link RestContext#getParentContext()}'s top-level contract.  Callers needing host-only
165    *       behavior should null-check.
166    *    <li class='note'><b>Nested mixins</b> &mdash; under nested {@code @Rest(mixins=...)} the flat-inheritance
167    *       rule collects every mixin as a mixin of the single top-level host, so this returns that top-level
168    *       host (never an intermediate mixin).
169    * </ul>
170    *
171    * @return The host resource's {@link RestContext}, or {@code null} when this mixin is not composed into a host.
172    * @since 10.0.0
173    */
174   public RestContext getHostContext() {
175      var c = context.get();
176      return c == null ? null : c.getParentContext();
177   }
178
179   /**
180    * Fluent builder for programmatically configuring a {@link RestMixin} subclass.
181    *
182    * <p>
183    * Subclassable, self-typed (CRTP) flavor builder.  Capability mixins (e.g.
184    * {@code FaviconMixin}) extend this and add their own worker-config setters, which chain with true covariant
185    * returns alongside the inherited {@link RestBuilder}surface.  For the common (non-subclassed) case use
186    * {@link RestMixin#builder(Class)} which returns the concrete {@link DefaultBuilder} leaf.
187    *
188    * @param <R> The mixin type produced by {@link #build()}.
189    * @param <SELF> The concrete builder type (self type).
190    */
191   @SuppressWarnings({
192      "java:S119" // 'SELF' (CRTP self-type) is intentional and clearer than a single-letter name.
193   })
194   public static class Builder<R extends RestMixin,SELF extends Builder<R,SELF>> extends AbstractRestBuilder<R,SELF> {
195
196      /**
197       * Constructor.
198       *
199       * @param type The mixin type produced by {@link #build()}.  Must not be <jk>null</jk>.
200       */
201      protected Builder(Class<R> type) {
202         super(type);
203      }
204
205      @Override /* AbstractRestBuilder */
206      public R build() {
207         var r = createResource();
208         r.restBuilder = this;
209         return r;
210      }
211   }
212
213   /**
214    * Concrete default leaf builder returned by {@link RestMixin#builder(Class)} for the common (non-subclassed)
215    * case.
216    *
217    * @param <R> The mixin type produced by {@link #build()}.
218    */
219   public static final class DefaultBuilder<R extends RestMixin> extends Builder<R,DefaultBuilder<R>> {
220      DefaultBuilder(Class<R> type) {
221         super(type);
222      }
223   }
224}