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.console.freemarker;
018
019import static org.apache.juneau.commons.utils.Shorts.*;
020
021import java.util.*;
022
023/**
024 * One named toolkit pack: ordered CSS and JS asset paths, the packs it depends on, its {@link Kind}, and the
025 * resolver that turns each path into a URL.
026 *
027 * <p>
028 * Register one through {@code ConsoleFreemarkerMixin.Builder.registerToolkitPack(ToolkitPack)}.  A pack registered
029 * under an existing name replaces that pack completely, including its {@code dependsOn}.
030 *
031 * <h5 class='section'>Example:</h5>
032 * <p class='bjava'>
033 *    ToolkitPack.<jsm>create</jsm>(<js>"datatables-export"</js>)
034 *       .js(<jv>jszip</jv>, <jv>pdfmake</jv>, <jv>vfsFonts</jv>)
035 *       .dependsOn(<js>"datatables-buttons"</js>)
036 *       .kind(ToolkitPack.Kind.<jsf>VENDOR</jsf>)
037 *       .resolver(<jv>myResolver</jv>)
038 *       .build();
039 * </p>
040 *
041 * @since 10.0.0
042 */
043public final class ToolkitPack {
044
045   /**
046    * Where a pack's assets are emitted on the page.
047    *
048    * <p>
049    * {@link #VENDOR} CSS goes before the page {@code css=} and {@link #VENDOR} JS before every {@link #RUNTIME} script.
050    * {@link #RUNTIME} assets keep the position the {@code "views"} runtime always had.  A {@link #VENDOR} pack can't
051    * depend on a {@link #RUNTIME} pack.
052    */
053   public enum Kind {
054      /** A library or glue that runtime packs build on. */
055      VENDOR,
056      /** A first-party UI runtime ({@code "views"}, {@code "calendar"}). */
057      RUNTIME
058   }
059
060   private final String name;
061   private final List<String> cssPaths;
062   private final List<String> jsPaths;
063   private final List<String> dependsOn;
064   private final Kind kind;
065   private final ToolkitPackRegistry.AssetUrlResolver resolver;
066
067   private ToolkitPack(Builder b) {
068      name = b.name;
069      cssPaths = List.copyOf(b.cssPaths);
070      jsPaths = List.copyOf(b.jsPaths);
071      dependsOn = List.copyOf(b.dependsOn);
072      kind = b.kind;
073      resolver = b.resolver;
074   }
075
076   /**
077    * Starts a pack.
078    *
079    * @param name The pack name.  Must not be blank.
080    * @return A new builder.
081    */
082   public static Builder create(String name) {
083      if (ib(name))
084         throw iaex("Toolkit pack name must not be blank.");
085      return new Builder(name.trim());
086   }
087
088   /**
089    * Returns the pack name.
090    *
091    * @return The pack name.
092    */
093   public String name() { return name; }
094
095   /**
096    * Returns the ordered CSS asset paths.
097    *
098    * @return The ordered CSS asset paths.
099    */
100   public List<String> cssPaths() { return cssPaths; }
101
102   /**
103    * Returns the ordered JS asset paths.
104    *
105    * @return The ordered JS asset paths.
106    */
107   public List<String> jsPaths() { return jsPaths; }
108
109   /**
110    * Returns the names of the packs this one loads after, in order.
111    *
112    * @return The names of the packs this one loads after, in order.
113    */
114   public List<String> dependsOn() { return dependsOn; }
115
116   /**
117    * Returns the pack kind.
118    *
119    * @return The pack kind.
120    */
121   public Kind kind() { return kind; }
122
123   /**
124    * Returns the asset-URL resolver.
125    *
126    * @return The asset-URL resolver.
127    */
128   public ToolkitPackRegistry.AssetUrlResolver resolver() { return resolver; }
129
130   /** Builder for {@link ToolkitPack}. */
131   public static final class Builder {
132
133      final String name;
134      final List<String> cssPaths = new ArrayList<>();
135      final List<String> jsPaths = new ArrayList<>();
136      final List<String> dependsOn = new ArrayList<>();
137      Kind kind;
138      ToolkitPackRegistry.AssetUrlResolver resolver = ToolkitPackRegistry.VIEWS_RESOLVER;
139
140      Builder(String name) {
141         this.name = name;
142      }
143
144      /**
145       * Appends CSS asset paths.
146       *
147       * @param paths The paths.
148       * @return This object.
149       */
150      public Builder css(String...paths) { return css(Arrays.asList(paths)); }
151
152      /**
153       * Appends CSS asset paths.
154       *
155       * @param paths The paths.
156       * @return This object.
157       */
158      public Builder css(List<String> paths) { cssPaths.addAll(paths); return this; }
159
160      /**
161       * Appends JS asset paths.
162       *
163       * @param paths The paths.
164       * @return This object.
165       */
166      public Builder js(String...paths) { return js(Arrays.asList(paths)); }
167
168      /**
169       * Appends JS asset paths.
170       *
171       * @param paths The paths.
172       * @return This object.
173       */
174      public Builder js(List<String> paths) { jsPaths.addAll(paths); return this; }
175
176      /**
177       * Appends the names of packs this one depends on.
178       *
179       * @param names The pack names.
180       * @return This object.
181       */
182      public Builder dependsOn(String...names) { dependsOn.addAll(Arrays.asList(names)); return this; }
183
184      /**
185       * Sets the pack kind.  Required.
186       *
187       * @param value The kind.
188       * @return This object.
189       */
190      public Builder kind(Kind value) { kind = rnn(value); return this; }
191
192      /**
193       * Sets the asset-URL resolver.  Defaults to {@link ToolkitPackRegistry#VIEWS_RESOLVER}.
194       *
195       * @param value The resolver.
196       * @return This object.
197       */
198      public Builder resolver(ToolkitPackRegistry.AssetUrlResolver value) { resolver = rnn(value); return this; }
199
200      /**
201       * Builds the pack.
202       *
203       * @return A new pack.
204       * @throws IllegalArgumentException If no kind was set.
205       */
206      public ToolkitPack build() {
207         if (n(kind))
208            throw iaex("Toolkit pack '%s' needs kind(VENDOR) or kind(RUNTIME).", name);
209         return new ToolkitPack(this);
210      }
211   }
212}