001// ***************************************************************************************************************************
002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
003// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
005// * with the License.  You may obtain a copy of the License at                                                              *
006// *                                                                                                                         *
007// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
008// *                                                                                                                         *
009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
011// * specific language governing permissions and limitations under the License.                                              *
012// ***************************************************************************************************************************
013package org.apache.juneau.rest.widget;
014
015import static org.apache.juneau.common.internal.ThrowableUtils.*;
016
017import java.io.*;
018
019import org.apache.juneau.rest.*;
020import org.apache.juneau.svl.*;
021import org.apache.juneau.cp.*;
022import org.apache.juneau.html.*;
023import org.apache.juneau.http.response.*;
024
025/**
026 * Defines an interface for resolvers of <js>"$W{...}"</js> string variables.
027 *
028 * <p>
029 * Widgets must provide one of the following public constructors:
030 * <ul>
031 *    <li><code><jk>public</jk> Widget();</code>
032 *    <li><code><jk>public</jk> Widget(ContextProperties);</code>
033 * </ul>
034 *
035 * <p>
036 * Widgets can be defined as inner classes of REST resource classes.
037 *
038 * <h5 class='section'>See Also:</h5><ul>
039 *    <li class='link'><a class="doclink" href="../../../../../index.html#jrs.HtmlPredefinedWidgets">Predefined Widgets</a>
040 *    <li class='link'><a class="doclink" href="../../../../../index.html#jrs.HtmlWidgets">Widgets</a>
041 * </ul>
042 */
043public abstract class Widget implements HtmlWidget {
044
045   /**
046    * The widget key.
047    *
048    * <p>
049    * (i.e. The variable name inside the <js>"$W{...}"</js> variable).
050    *
051    * <p>
052    * The returned value must not be <jk>null</jk>.
053    *
054    * <p>
055    * If not overridden, the default value is the class simple name.
056    *
057    * @return The widget key.
058    */
059   @Override
060   public String getName() {
061      return getClass().getSimpleName();
062   }
063
064   private RestRequest req(VarResolverSession session) {
065      return session.getBean(RestRequest.class).orElseThrow(InternalServerError::new);
066   }
067
068   private RestResponse res(VarResolverSession session) {
069      return session.getBean(RestResponse.class).orElseThrow(InternalServerError::new);
070   }
071
072   @Override /* HtmlWidget */
073   public String getHtml(VarResolverSession session) {
074      return getHtml(req(session), res(session));
075   }
076
077   @Override /* HtmlWidget */
078   public String getScript(VarResolverSession session) {
079      return getScript(req(session), res(session));
080   }
081
082   @Override /* HtmlWidget */
083   public String getStyle(VarResolverSession session) {
084      return getStyle(req(session), res(session));
085   }
086
087   /**
088    * Resolves the HTML content for this widget.
089    *
090    * <p>
091    * A returned value of <jk>null</jk> will cause nothing to be added to the page.
092    *
093    * @param req The HTTP request object.
094    * @param res The current HTTP response.
095    * @return The HTML content of this widget.
096    */
097   public String getHtml(RestRequest req, RestResponse res) {
098      return null;
099   }
100
101   /**
102    * Resolves any Javascript that should be added to the <xt>&lt;head&gt;/&lt;script&gt;</xt> element.
103    *
104    * <p>
105    * A returned value of <jk>null</jk> will cause nothing to be added to the page.
106    *
107    * @param req The HTTP request object.
108    * @param res The current HTTP response.
109    * @return The Javascript needed by this widget.
110    */
111   public String getScript(RestRequest req, RestResponse res) {
112      return null;
113   }
114
115   /**
116    * Resolves any CSS styles that should be added to the <xt>&lt;head&gt;/&lt;style&gt;</xt> element.
117    *
118    * <p>
119    * A returned value of <jk>null</jk> will cause nothing to be added to the page.
120    *
121    * @param req The HTTP request object.
122    * @param res The current HTTP response.
123    * @return The CSS styles needed by this widget.
124    */
125   public String getStyle(RestRequest req, RestResponse res) {
126      return null;
127   }
128
129   /**
130    * Returns the file finder to use for finding files on the file system.
131    *
132    * @param req The HTTP request object.
133    * @return The file finder to used for finding files on the file system.
134    */
135   protected FileFinder getFileFinder(RestRequest req) {
136      return req.getStaticFiles();
137   }
138
139   /**
140    * Loads the specified javascript file and strips any Javascript comments from the file.
141    *
142    * <p>
143    * Comments are assumed to be Java-style block comments: <js>"/*"</js>.
144    *
145    * @param req The HTTP request object.
146    * @param name Name of the desired resource.
147    * @return The resource converted to a string, or <jk>null</jk> if the resource could not be found.
148    */
149   protected String loadScript(RestRequest req, String name) {
150      try {
151         String s = getFileFinder(req).getString(name, null).orElse(null);
152         if (s != null)
153            s = s.replaceAll("(?s)\\/\\*(.*?)\\*\\/\\s*", "");
154         return s;
155      } catch (IOException e) {
156         throw new RuntimeException(e);
157      }
158   }
159
160   /**
161    * Same as {@link #loadScript(RestRequest,String)} but replaces request-time SVL variables.
162    *
163    * <h5 class='section'>See Also:</h5><ul>
164    *    <li class='jm'>{@link org.apache.juneau.rest.RestContext#getVarResolver()}
165    *    <li class='link'><a class="doclink" href="../../../../../index.html#jm.SvlVariables">SVL Variables</a>
166    * </ul>
167    *
168    * @param req The current HTTP request.
169    * @param res The current HTTP response.
170    * @param name Name of the desired resource.
171    * @return The resource converted to a string, or <jk>null</jk> if the resource could not be found.
172    * @throws IOException Thrown by underlying stream.
173    */
174   protected String loadScriptWithVars(RestRequest req, RestResponse res, String name) throws IOException {
175      return req.getVarResolverSession().resolve(loadScript(req, name));
176   }
177
178   /**
179    * Loads the specified CSS file and strips CSS comments from the file.
180    *
181    * <p>
182    * Comments are assumed to be Java-style block comments: <js>"/*"</js>.
183    *
184    * @param req The HTTP request object.
185    * @param name Name of the desired resource.
186    * @return The resource converted to a string, or <jk>null</jk> if the resource could not be found.
187    */
188   protected String loadStyle(RestRequest req, String name) {
189      try {
190         String s = getFileFinder(req).getString(name, null).orElse(null);
191         if (s != null)
192            s = s.replaceAll("(?s)\\/\\*(.*?)\\*\\/\\s*", "");
193         return s;
194      } catch (IOException e) {
195         throw asRuntimeException(e);
196      }
197   }
198
199   /**
200    * Same as {@link #loadStyle(RestRequest,String)} but replaces request-time SVL variables.
201    *
202    * <h5 class='section'>See Also:</h5><ul>
203    *    <li class='jm'>{@link org.apache.juneau.rest.RestContext#getVarResolver()}
204    *    <li class='link'><a class="doclink" href="../../../../../index.html#jm.SvlVariables">SVL Variables</a>
205    * </ul>
206    *
207    * @param req The current HTTP request.
208    * @param res The current HTTP response.
209    * @param name Name of the desired resource.
210    * @return The resource converted to a string, or <jk>null</jk> if the resource could not be found.
211    * @throws IOException Thrown by underlying stream.
212    */
213   protected String loadStyleWithVars(RestRequest req, RestResponse res, String name) throws IOException {
214      return req.getVarResolverSession().resolve(loadStyle(req, name));
215   }
216
217   /**
218    * Loads the specified HTML file and strips HTML comments from the file.
219    *
220    * <p>
221    * Comment are assumed to be <js>"&lt;!-- --&gt;"</js> code blocks.
222    *
223    * @param req The HTTP request object.
224    * @param name Name of the desired resource.
225    * @return The resource converted to a string, or <jk>null</jk> if the resource could not be found.
226    */
227   protected String loadHtml(RestRequest req, String name) {
228      try {
229         String s = getFileFinder(req).getString(name, null).orElse(null);
230         if (s != null)
231            s = s.replaceAll("(?s)<!--(.*?)-->\\s*", "");
232         return s;
233      } catch (IOException e) {
234         throw asRuntimeException(e);
235      }
236   }
237
238   /**
239    * Same as {@link #loadHtml(RestRequest,String)} but replaces request-time SVL variables.
240    *
241    * <h5 class='section'>See Also:</h5><ul>
242    *    <li class='jm'>{@link org.apache.juneau.rest.RestContext#getVarResolver()}
243    *    <li class='link'><a class="doclink" href="../../../../../index.html#jm.SvlVariables">SVL Variables</a>
244    * </ul>
245    *
246    * @param req The current HTTP request.
247    * @param res The current HTTP response.
248    * @param name Name of the desired resource.
249    * @return The resource converted to a string, or <jk>null</jk> if the resource could not be found.
250    * @throws IOException Thrown by underlying stream.
251    */
252   protected String loadHtmlWithVars(RestRequest req, RestResponse res, String name) throws IOException {
253      return req.getVarResolverSession().resolve(loadHtml(req, name));
254   }
255}