
cat.inspiracio.orange.Resolver 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.File;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.List;
import static java.nio.charset.StandardCharsets.UTF_8;
/** Resolves java package and class names for an html file.
*
* No state. */
public class Resolver {
/** Default constructor */
public Resolver() {}
/** Java reserved words. https://en.wikipedia.org/wiki/List_of_Java_keywords */
private static final List reserved = Arrays.asList(
"abstract",
"assert",
"boolean",
"break",
"byte",
"case",
"catch",
"char",
"class",
"const",
"continue",
"default",
"do",
"double",
"else",
"enum",
"exports",
"extends",
"false",
"final",
"finally",
"float",
"for",
"goto",
"if",
"implements",
"import",
"instanceof",
"int",
"interface",
"long",
"module",
"native",
"new",
"null",
"package",
"private",
"protected",
"public",
"requires",
"return",
"short",
"static",
"strictfp",
"super",
"switch",
"synchronized",
"this",
"throw",
"throws",
"transient",
"true",
"try",
"var",
"void",
"volatile",
"while"
);
List reserved(){return Resolver.reserved;}
boolean reserved(String s){ return reserved.contains(s);}
/** all package names start with this so that they don't coincide with anything */
private static final String PREFIX = "cat.inspiracio.orange.webapp";
/** Fully-qualified class name from an absolute path.
* Called from OrangeServlet.
* @param path Absolute in webapp. Starts with /. */
String fqcn(String path){
String p = packageName(path);// cat.inspiracio.orange.webapp
String c = className(path);
return p + "." + c;
}
/** Resolves path v relative to the path of this template.
*
* Called from Template.substitute().
* Package-visible for tests.
*
* @param base Path to the calling *.html file, inside webapp. Starts with /.
* @param v relative or absolute path, like "hr.html" or "/cacti/cactus.html".
* Absolute path must not contain "." or ".." directories.
*
* @return fully qualified class name of v */
String fqcn(String base, String v){
// Absolute path. May it contain ".." or "."?
// if(v.startsWith("/")) return fqcn(v);
// fqcn v with respect to the current template
Path p = new File(base).toPath().resolveSibling(v).normalize();
String s = p.toString();
return fqcn(s);
}
/** Makes a java package name from a request path.
*
* Called from OrangeMojo.
* Package-visibility for tests.
/index.html --> cat.inspiracio.orange.webapp
/cacti/Cactaceae/6.html --> cat.inspiracio.orange.webapp.cacti.cactaceae
/WEB-INF/cactus/index.html --> cat.inspiracio.orange.webapp.web_inf.cactus
/WEB-INF/404.html --> cat.inspiracio.orange.webapp.web_inf
/WEB-INF/throwable.html --> cat.inspiracio.orange.webapp.web_inf
/googlef5cc28e2ffb847a5.html--> cat.inspiracio.orange.webapp
* @param path like "/WEB-INF/404.html" Absolute in webapp. Starts with /.
* @throws RuntimeException Format is not right. For example, has no "/".
*/
String packageName(String path){
String folder = folder(path);
String[] parts = folder.split("/");
StringBuilder builder = new StringBuilder(PREFIX);
for(int i=1; i index
/cacti/Cactaceae/6.html --> _6
/WEB-INF/cactus/index.html --> index
/WEB-INF/404.html --> _404
/WEB-INF/throwable.html --> throwable
/googlef5cc28e2ffb847a5.html--> googlef5cc28e2ffb847a5
* @param path like "/cacti/Cactaceae/6.html"
* @return Just the class name without package, like "_6"
*/
String className(String path){
String file = file(path);
String name = dropExtension(file);
return identifier(name);
}
// helpers -------------------------------------------------------
/** Transforms a string s into a similar string that is a valid java identifier.
*
* If s is null, IllegalArgumentException.
* If s is empty, IllegalArgumentException.
*
* If s is a java reserved word, prefixes with '_'.
*
* If the first character is a not a java identifier start, prefixes with '_'.
*
* Any character that is not a java identifier part, is replaced with '$' and
* hex representation of the UTF8 bytes. (Similar to URL-encoding but uses $ for %.)
* */
String identifier(String s){
if(s.isEmpty()) throw new IllegalArgumentException("String is empty.");
if(reserved(s)) return "_" + s;
StringBuilder builder = new StringBuilder();
// First character legal
if(!Character.isJavaIdentifierStart(s.charAt(0)))
builder.append('_');
for(char c : s.toCharArray()) {
if(Character.isJavaIdentifierPart(c)) {
builder.append(c);
} else {
byte[] bytes = Character.toString(c).getBytes(UTF_8);
for(byte b : bytes){
builder.append('$');
builder.append(Integer.toHexString(b));
}
}
}
return builder.toString();
}
private String folder(String path){
int i = path.lastIndexOf("/");
if(i<0) throw new RuntimeException("packageName " + path);
return path.substring(0, i);
}
private String file(String path){
int i = path.lastIndexOf("/");
if(i<0) throw new RuntimeException("className " + path);
return path.substring(i+1);
}
private String dropExtension(String path){
int dot = path.lastIndexOf('.');
if(-1
© 2015 - 2025 Weber Informatics LLC | Privacy Policy