
cat.inspiracio.orange.Resolver Maven / Gradle / Ivy
/* 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.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.List;
/** Resolves java package and class names for an html file.
*
* no state */
public class 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", "continue", "default", "do", "double", "else", "enum", "exports", "extends", "final", "finally", "float", "for", "if", "implements", "import", "instanceof", "int", "interface", "long", "module", "native", "new", "package", "private", "protected", "public", "requires", "return", "short", "static", "strictfp", "super", "switch", "synchronized", "this", "throw", "throws", "transient", "try", "void", "volatile", "while", "true", "null", "false", "var", "const", "goto");
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.length()==0)
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(StandardCharsets.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);
String folder = path.substring(0, i);
return folder;
}
private String file(String path){
int i = path.lastIndexOf("/");
if(i<0)
throw new RuntimeException("className " + path);
String file = path.substring(i+1);//drop folders. path=""
return file;
}
private String dropExtension(String path){
int dot = path.lastIndexOf('.');
if(-1
© 2015 - 2025 Weber Informatics LLC | Privacy Policy