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.petstore.console;
018
019import org.apache.juneau.commons.inject.*;
020import org.apache.juneau.petstore.console.dev.*;
021import org.apache.juneau.petstore.service.*;
022import org.apache.juneau.rest.server.*;
023import org.apache.juneau.console.datatables.*;
024import org.apache.juneau.rest.server.servlet.*;
025import org.apache.juneau.rest.server.staticfile.*;
026import org.apache.juneau.rest.server.view.*;
027import org.apache.juneau.rest.server.view.freemarker.*;
028import org.apache.juneau.console.freemarker.*;
029import org.apache.juneau.console.views.*;
030
031/**
032 * Base class for every petstore console page resource: registers the console FreeMarker mixin with
033 * {@code base.ftlh} as chrome, and injects the shared {@link PetStore}.
034 *
035 * <p>
036 * Children don't inherit the parent's mixins, so every page class extends this one instead of re-declaring the
037 * mixin, which E-B12 would reject.
038 *
039 * <p>
040 * The views and DataTables toolkit packs link their assets page-relative (e.g. {@code /console/store/juneau-views.js}),
041 * so every page also composes {@link ViewsMixin} and {@link DataTablesMixin} to serve them from its own mount.
042 *
043 * <h5 class='section'>Example:</h5>
044 * <p class='bjava'>
045 *    <ja>@Rest</ja>(path=<js>"/ops/audit"</js>)
046 *    <jk>public class</jk> AuditRest <jk>extends</jk> PetstoreConsolePage {
047 *       <ja>@RestGet</ja>(path=<js>"/"</js>)
048 *       <jk>public</jk> View page() { <jk>return</jk> FreemarkerView.<jsm>of</jsm>(<js>"audit.ftlh"</js>); }
049 *    }
050 * </p>
051 */
052@Rest(mixins={FreemarkerMixin.class, ViewsMixin.class, DataTablesMixin.class, WebJarsMixin.class}, responseProcessors=FreemarkerViewRenderer.class)
053public abstract class PetstoreConsolePage extends BasicRestServlet {
054
055   private static final long serialVersionUID = 1L;
056
057   /** Classpath folder holding the console templates. */
058   public static final String TEMPLATES = "/org/apache/juneau/petstore/console/templates/";
059
060   /** Response header naming the render path of a builder-twin page, so a twin test can tell the two paths apart. */
061   public static final String PAGE_HEADER = "X-Petstore-Page";
062
063   /**
064    * Whether this request asks for the builder twin of a page ({@code ?builder}, with or without a value).
065    *
066    * @param req The request.
067    * @return <jk>true</jk> if the page should render from its {@link PageSpec}.
068    */
069   public static boolean builder(RestRequest req) {
070      return req.containsQueryParam("builder");
071   }
072
073   /**
074    * Renders a builder-twin page, marked with {@link #PAGE_HEADER}.
075    *
076    * @param req The request.
077    * @param spec The page spec.
078    * @return The view.
079    */
080   public static View twin(RestRequest req, PageSpec spec) {
081      return spec.header(PAGE_HEADER, "builder").view(req);
082   }
083
084   @SuppressWarnings({
085      "java:S2226" // the field is set by the framework's @Bean injection after construction, so it cannot be final.
086   })
087   @Bean
088   private transient PetStore store;
089
090   /**
091    * The console FreeMarker mixin: petstore templates, {@code base.ftlh} chrome, {@code assetUrl(..)} over this
092    * package's bundled scripts, and the {@link InventoryGaugeCardType} custom card type.
093    *
094    * @return The mixin.
095    */
096   @Bean
097   public FreemarkerMixin freemarker() {
098      // assetUrl('/console/petstore.js') versions the shared page script served by PetstoreConsoleResource.
099      return ConsoleFreemarkerMixin.create().basePath(TEMPLATES).chromeTemplate("base.ftlh")
100         .adopterAssets(PetstoreConsolePage.class.getClassLoader(), "org/apache/juneau/petstore")
101         .cardType(new InventoryGaugeCardType()).requirePacks("charts").build();
102   }
103
104   /**
105    * @return The shared store.
106    * @throws IllegalStateException If no {@link PetStore} {@code @Bean} was wired into the host.
107    */
108   protected PetStore store() {
109      if (store == null)
110         throw new IllegalStateException("No PetStore bean is wired: declare a @Bean PetStore on the host that mounts " + getClass().getSimpleName());
111      return store;
112   }
113}