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