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 java.io.*; 016import java.util.*; 017 018import org.apache.juneau.rest.*; 019import org.apache.juneau.svl.*; 020import org.apache.juneau.utils.*; 021import org.apache.juneau.html.*; 022 023/** 024 * Defines an interface for resolvers of <js>"$W{...}"</js> string variables. 025 * 026 * <p> 027 * Widgets must provide one of the following public constructors: 028 * <ul> 029 * <li><code><jk>public</jk> Widget();</code> 030 * <li><code><jk>public</jk> Widget(PropertyStore);</code> 031 * </ul> 032 * 033 * <p> 034 * Widgets can be defined as inner classes of REST resource classes. 035 * 036 * <ul class='seealso'> 037 * <li class='link'>{@doc juneau-rest-server.HtmlDocAnnotation.Widgets} 038 * </ul> 039 */ 040public abstract class Widget implements HtmlWidget { 041 042 private final ClasspathResourceManager rm = new ClasspathResourceManager(getClass(), ClasspathResourceFinderRecursive.INSTANCE, false); 043 044 private static final String SESSION_req = "req"; 045 private static final String SESSION_res = "res"; 046 047 /** 048 * The widget key. 049 * 050 * <p> 051 * (i.e. The variable name inside the <js>"$W{...}"</js> variable). 052 * 053 * <p> 054 * The returned value must not be <jk>null</jk>. 055 * 056 * <p> 057 * If not overridden, the default value is the class simple name. 058 * 059 * @return The widget key. 060 */ 061 @Override 062 public String getName() { 063 return getClass().getSimpleName(); 064 } 065 066 private RestRequest req(VarResolverSession session) { 067 return session.getSessionObject(RestRequest.class, SESSION_req, true); 068 } 069 070 private RestResponse res(VarResolverSession session) { 071 return session.getSessionObject(RestResponse.class, SESSION_res, true); 072 } 073 074 @Override /* HtmlWidget */ 075 public String getHtml(VarResolverSession session) throws Exception { 076 return getHtml(req(session), res(session)); 077 } 078 079 @Override /* HtmlWidget */ 080 public String getScript(VarResolverSession session) throws Exception { 081 return getScript(req(session), res(session)); 082 } 083 084 @Override /* HtmlWidget */ 085 public String getStyle(VarResolverSession session) throws Exception { 086 return getStyle(req(session), res(session)); 087 } 088 089 /** 090 * Resolves the HTML content for this widget. 091 * 092 * <p> 093 * A returned value of <jk>null</jk> will cause nothing to be added to the page. 094 * 095 * @param req The HTTP request object. 096 * @param res The current HTTP response. 097 * @return The HTML content of this widget. 098 * @throws Exception Error occurred. 099 */ 100 public String getHtml(RestRequest req, RestResponse res) throws Exception { 101 return null; 102 } 103 104 /** 105 * Implement {@link #getHtml(RestRequest, RestResponse)}. 106 */ 107 @SuppressWarnings("javadoc") 108 @Deprecated 109 public String getHtml(RestRequest req) throws Exception { 110 return getHtml(req, null); 111 } 112 113 /** 114 * Resolves any Javascript that should be added to the <xt><head>/<script></xt> element. 115 * 116 * <p> 117 * A returned value of <jk>null</jk> will cause nothing to be added to the page. 118 * 119 * @param req The HTTP request object. 120 * @param res The current HTTP response. 121 * @return The Javascript needed by this widget. 122 * @throws Exception Error occurred. 123 */ 124 public String getScript(RestRequest req, RestResponse res) throws Exception { 125 return null; 126 } 127 128 /** 129 * Implement {@link #getScript(RestRequest, RestResponse)}. 130 */ 131 @SuppressWarnings("javadoc") 132 @Deprecated 133 public String getScript(RestRequest req) throws Exception { 134 return getScript(req, null); 135 } 136 137 /** 138 * Resolves any CSS styles that should be added to the <xt><head>/<style></xt> element. 139 * 140 * <p> 141 * A returned value of <jk>null</jk> will cause nothing to be added to the page. 142 * 143 * @param req The HTTP request object. 144 * @param res The current HTTP response. 145 * @return The CSS styles needed by this widget. 146 * @throws Exception Error occurred. 147 */ 148 public String getStyle(RestRequest req, RestResponse res) throws Exception { 149 return null; 150 } 151 152 /** 153 * Implement {@link #getStyle(RestRequest, RestResponse)}. 154 */ 155 @SuppressWarnings("javadoc") 156 @Deprecated 157 public String getStyle(RestRequest req) throws Exception { 158 return getStyle(req, null); 159 } 160 161 /** 162 * Retrieves the specified classpath resource and returns the contents as a string. 163 * 164 * <p> 165 * Same as {@link Class#getResourceAsStream(String)} except if it doesn't find the resource on this class, searches 166 * up the parent hierarchy chain. 167 * 168 * <p> 169 * If the resource cannot be found in the classpath, then an attempt is made to look relative to the JVM working directory. 170 * <br>Path traversals outside the working directory are not allowed for security reasons. 171 * 172 * @param name Name of the desired resource. 173 * @return The resource converted to a string, or <jk>null</jk> if the resource could not be found. 174 * @throws IOException Thrown by underlying stream. 175 */ 176 protected String getClasspathResourceAsString(String name) throws IOException { 177 return rm.getString(name); 178 } 179 180 /** 181 * Same as {@link #getClasspathResourceAsString(String)} except also looks for localized-versions of the file. 182 * 183 * <p> 184 * If the <c>locale</c> is specified, then we look for resources whose name matches that locale. 185 * <br>For example, if looking for the resource <js>"MyResource.txt"</js> for the Japanese locale, we will look for 186 * files in the following order: 187 * <ol> 188 * <li><js>"MyResource_ja_JP.txt"</js> 189 * <li><js>"MyResource_ja.txt"</js> 190 * <li><js>"MyResource.txt"</js> 191 * </ol> 192 * 193 * @param name Name of the desired resource. 194 * @param locale The locale. Can be <jk>null</jk>. 195 * @return The resource converted to a string, or <jk>null</jk> if the resource could not be found. 196 * @throws IOException Thrown by underlying stream. 197 */ 198 protected String getClasspathResourceAsString(String name, Locale locale) throws IOException { 199 return rm.getString(name, locale); 200 } 201 202 /** 203 * Convenience method for calling {@link #getClasspathResourceAsString(String)} except also strips Javascript comments from 204 * the file. 205 * 206 * <p> 207 * Comments are assumed to be Java-style block comments: <js>"/*"</js>. 208 * 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 loadScript(String name) throws IOException { 214 String s = getClasspathResourceAsString(name); 215 if (s != null) 216 s = s.replaceAll("(?s)\\/\\*(.*?)\\*\\/\\s*", ""); 217 return s; 218 } 219 220 /** 221 * Same as {@link #loadScript(String)} but replaces request-time SVL variables. 222 * 223 * <ul class='seealso'> 224 * <li class='jm'>{@link org.apache.juneau.rest.RestContext#getVarResolver()} 225 * <li class='link'>{@doc juneau-rest-server.SvlVariables} 226 * </ul> 227 * 228 * @param req The current HTTP request. 229 * @param res The current HTTP response. 230 * @param name Name of the desired resource. 231 * @return The resource converted to a string, or <jk>null</jk> if the resource could not be found. 232 * @throws IOException Thrown by underlying stream. 233 */ 234 protected String loadScriptWithVars(RestRequest req, RestResponse res, String name) throws IOException { 235 return req.getVarResolverSession().resolve(loadScript(name)); 236 } 237 238 /** 239 * Convenience method for calling {@link #getClasspathResourceAsString(String)} except also strips CSS comments from 240 * the file. 241 * 242 * <p> 243 * Comments are assumed to be Java-style block comments: <js>"/*"</js>. 244 * 245 * @param name Name of the desired resource. 246 * @return The resource converted to a string, or <jk>null</jk> if the resource could not be found. 247 * @throws IOException Thrown by underlying stream. 248 */ 249 protected String loadStyle(String name) throws IOException { 250 String s = getClasspathResourceAsString(name); 251 if (s != null) 252 s = s.replaceAll("(?s)\\/\\*(.*?)\\*\\/\\s*", ""); 253 return s; 254 } 255 256 /** 257 * Same as {@link #loadStyle(String)} but replaces request-time SVL variables. 258 * 259 * <ul class='seealso'> 260 * <li class='jm'>{@link org.apache.juneau.rest.RestContext#getVarResolver()} 261 * <li class='link'>{@doc juneau-rest-server.SvlVariables} 262 * </ul> 263 * 264 * @param req The current HTTP request. 265 * @param res The current HTTP response. 266 * @param name Name of the desired resource. 267 * @return The resource converted to a string, or <jk>null</jk> if the resource could not be found. 268 * @throws IOException Thrown by underlying stream. 269 */ 270 protected String loadStyleWithVars(RestRequest req, RestResponse res, String name) throws IOException { 271 return req.getVarResolverSession().resolve(loadStyle(name)); 272 } 273 274 /** 275 * Convenience method for calling {@link #getClasspathResourceAsString(String)} except also strips HTML comments from the 276 * file. 277 * 278 * <p> 279 * Comment are assumed to be <js>"<!-- -->"</js> code blocks. 280 * 281 * @param name Name of the desired resource. 282 * @return The resource converted to a string, or <jk>null</jk> if the resource could not be found. 283 * @throws IOException Thrown by underlying stream. 284 */ 285 protected String loadHtml(String name) throws IOException { 286 String s = getClasspathResourceAsString(name); 287 if (s != null) 288 s = s.replaceAll("(?s)<!--(.*?)-->\\s*", ""); 289 return s; 290 } 291 292 /** 293 * Same as {@link #loadHtml(String)} but replaces request-time SVL variables. 294 * 295 * <ul class='seealso'> 296 * <li class='jm'>{@link org.apache.juneau.rest.RestContext#getVarResolver()} 297 * <li class='link'>{@doc juneau-rest-server.SvlVariables} 298 * </ul> 299 * 300 * @param req The current HTTP request. 301 * @param res The current HTTP response. 302 * @param name Name of the desired resource. 303 * @return The resource converted to a string, or <jk>null</jk> if the resource could not be found. 304 * @throws IOException Thrown by underlying stream. 305 */ 306 protected String loadHtmlWithVars(RestRequest req, RestResponse res, String name) throws IOException { 307 return req.getVarResolverSession().resolve(loadHtml(name)); 308 } 309}