
cat.inspiracio.orange.Template Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of orange-servlet Show documentation
Show all versions of orange-servlet Show documentation
Orange Servlet provides HTML templating with server-side Java.
OrangeServlet is a servlet that is registered on *.html.
It reads the html file at the right location according to URL.
It renders the file as html, executing some scripting:
* data-if="E" attributes for server-side conditional,
* data-for="T x : E" attributes for server-side loops,
* data-import="C" attributes for server-side class imports,
* data-substitute="file.html" substitute an element with the processed contents of a file,
* ${expressions} in element bodies and attribute values.
The newest version!
/* Copyright 2019 Alexander Bunkenburg
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package cat.inspiracio.orange;
import java.io.IOException;
import jakarta.servlet.RequestDispatcher;
import jakarta.servlet.ServletConfig;
import jakarta.servlet.ServletContext;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import jakarta.servlet.jsp.JspWriter;
import jakarta.servlet.jsp.PageContext;
import static jakarta.servlet.RequestDispatcher.ERROR_EXCEPTION;
/** A template that can write itself to response output.
* Initialise giving it a page context, and then call render(). */
public abstract class Template {
private static final String NL = "\n";
// state -----------------------------------------------
// All these variables are visible in the write() method.
// Like implicit objects in JSP 3.0.
// https://jakarta.ee/specifications/pages/3.0/jakarta-server-pages-spec-3.0
/** Request */
protected HttpServletRequest request;
/** Response. The template renders to this response. */
protected HttpServletResponse response;
/** Page context with all the object. */
protected PageContext pageContext;
/** Session */
protected HttpSession session;
/** The servlet context */
protected ServletContext application;
/** The response's output. */
protected JspWriter out;
/** Servlet configuration */
protected ServletConfig config;
/** The 'page' is this template itself. */
protected Template page;
/** An exception thrown by the template, or null. */
protected Throwable exception;
// construction --------------------------------
/** Initialise with page context.
* Subclasses must call this constructor.
* @param pc template.render() will write to pc.response.out,
* and the template may use the objects in this page context. */
public Template(PageContext pc) {
out = pc.getOut();
pageContext = pc;
request = (HttpServletRequest)pc.getRequest();
response = (HttpServletResponse)pc.getResponse();
session = pc.getSession();
application = pc.getServletContext();
config = pc.getServletConfig();
page = this; // Spec: "synonym for this", but with type Object.
exception = (Throwable) request.getAttribute(ERROR_EXCEPTION);
}
// abstract method -----------------------------
/** This is the method that template must implement.
* Rendering writes the template's output to response.
* @throws Exception Java-islands threw an exception. */
public abstract void render() throws Exception;
// orange logic ------------------------------
/** Sends a temporary redirect response to the client using the specified
* redirect location URL. This method can accept relative URLs;
* the servlet container must convert the relative URL to an absolute URL
* before sending the response to the client. If the location is relative
* without a leading '/' the container interprets it as relative to the
* current request URI. If the location is relative with a leading '/' the
* container interprets it as relative to the servlet container root.
*
* If the response has already been committed, this method throws an
* IllegalStateException. After using this method, the response should be
* considered to be committed and should not be written to.
*
* After redirect, template execution continues. There will be no more
* output to the response, but maybe there are other effects.
* In order to avoid it, you can follow it by
* if(true) return;
.
*
* Uses old-fashioned status code 302.
* @param location the redirect location URL, can be relative
* @throws IOException If an input or output exception occurs
* @throws IllegalStateException If the response was committed or if a partial
* URL is given and cannot be converted into a valid URL
*/
protected void redirect(String location) throws IOException {
response.sendRedirect(location);
// Should this be 303? I leave it with old 302.
}
/** Forward.
*
* After forward, template execution continues. There will be no more
* output to the response, but maybe there are other effects.
* In order to avoid it, you can follow it by
*
* if(true) return;
*
* @param u the forward location URL, can be relative
* @throws ServletException if the target resource throws this exception
* @throws IOException if the target resource throws this exception
* @throws IllegalStateException If the response was committed or if a partial
* URL is given and cannot be converted into a valid URL
*/
protected void forward(String u) throws ServletException, IOException {
RequestDispatcher dispatcher = request.getRequestDispatcher(u);
dispatcher.forward(request,response);
}
/** Quotes a value so that it can be an attribute's value.
* Escapes " by " and encloses in ".
* For null returns quote("").
* Called from generated write().
* @param o object
* @return quoted */
protected final String quote(Object o){
if(o==null) return "\"\"";
String s = o.toString();
if(s==null) return "\"\"";
String value = unquote(s);
return '"' + value + '"';
}
/** Escapes " by " .
* For null returns "".
* Called from generated write().
* @param o Object
* @return ... */
protected final String unquote(Object o){
if(o==null) return "";
String value = o.toString();
if(value==null) return "";
if(contains(value, '"'))
value=value.replaceAll("\"", """);
return value;
}
/** escape for html: ≤ &
* Called from generated write().
* @param o Object
* @return escaped */
protected final String escape(Object o){
if(o==null) return "";
String s = o.toString();
if(s==null) return "";
return s.replace("&", "&").replace("<", "<");
}
/** Escapes an int for html: just convert it to String.
* Called from generated write().
* @param i int
* @return escaped */
protected final String escape(int i){return Integer.toString(i);}
/** Boolean attribute: write the key if the value is true.
* Called from generated write().
* @param key key
* @param b value
* @throws IOException couldn't write */
protected final void attribute(String key, boolean b) throws IOException{
if(b)write(" " + key);
}
/** Attribute:
* If the value is empty, writes just the key,
* otherwise key and value, quoted.
* @param key key
* @param v value
* @throws IOException bad IO
* */
protected final void attribute(String key, Object v) throws IOException{
if(v==null){
write(" " + key);
return;
}
String s = v.toString();
if(empty(s)){
write(" " + key);
return;
}
write(" " + key + "=" + quote(s)); // TODO Optimise: in HTML5, the value often can be without quotes.
}
private boolean empty(String s){return s==null || s.isEmpty();}
/** Does the string contain this character? */
private boolean contains(String value, char c){return 0<=value.indexOf(c);}
// writing -------------------------------------
/** Writes an int to out.
* Called from generated write().
* @param i The integer to write.
* @return same template
* @throws IOException ... */
public final Template write(int i)throws IOException{
out.write(Integer.toString(i));
return this;
}
/** Writes an object to out.
* Does nothing if the object is empty (null or its toString() is null or "").
* @param o The object to write.
* @return same template
* @throws IOException ... */
public final Template write(Object o)throws IOException{
if(o==null) return this;
String s = o.toString();
return write(s);
}
/** Writes a String to out.
* Does nothing if the String is null or "".
* @param s The string to write.
* @return same template
* @throws IOException ... */
public final Template write(String s)throws IOException{
if(!empty(s)) out.write(s);
return this;
}
/** Write a string to output.
* @return same template
* @throws IOException ... */
public final Template writeln()throws IOException{return write(NL);}
/** Write a string to output.
* @param s ...
* @return same template
* @throws IOException ... */
public final Template writeln(String s)throws IOException{
write(s);
return writeln();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy