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