diff --git a/src/fr/devinsy/kiss4web/SimpleServletDispatcher.java b/src/fr/devinsy/kiss4web/SimpleServletDispatcher.java index 056d1ca..1ab2e4d 100644 --- a/src/fr/devinsy/kiss4web/SimpleServletDispatcher.java +++ b/src/fr/devinsy/kiss4web/SimpleServletDispatcher.java @@ -30,8 +30,12 @@ public class SimpleServletDispatcher extends HttpServlet { private static final long serialVersionUID = -3471226305721330069L; static protected org.apache.log4j.Logger logger = org.apache.log4j.Logger.getLogger (ServletDispatcher.class); - static protected Pattern URL_PARAMETER_PATTERN = Pattern.compile("^(.+)-\\d+\\.xhtml$"); - static protected Pattern URL_PARAMETER_PATTERN2 = Pattern.compile("^.+-(\\d+)\\.xhtml$"); + static final protected Pattern SHORT_REWRITED_URL_CLASS = Pattern.compile("^([^-]+)-.+\\.xhtml$"); + static final protected Pattern SHORT_REWRITED_URL_PARAMETERS = Pattern.compile("^[^-]+-(.+)\\.xhtml$"); + static final protected Pattern LONG_REWRITED_URL_CLASS = Pattern.compile("^([^-]+)-/.*$"); + //static final protected Pattern LONG_REWRITED_URL_PARAMETERS = Pattern.compile("^.+-/(.)+*$"); + static final protected Pattern REWRITE_PARAMETER = Pattern.compile("[^%\\w\\d]"); + protected String webclassesRootPath; @@ -71,7 +75,8 @@ public class SimpleServletDispatcher extends HttpServlet * "/good/" => "good.Good_xhtml" * "/good/morning.xhtml" => "good.Morning_xhtml" * "/good/morning_girl.xhtml" => "good.Morning_girl_xhtml" - * "/good/morning-123.xhtml" => "good.Morning_xhtml" (123 is detected as a parameter, it will be decoded in the class called later). + * "/good/morning-123.xhtml" => "good.Morning_xhtml" ('123' is detected as a parameter, it will be decoded in the class called later). + * "/good/morning-/12/toto.jpg" => "good.Morning" ('12' and 'toto.jpg" are detected as a parameter, they will be decoded in the class called later). */ static public String pathInfoToClassName (String pathInfo) { @@ -89,34 +94,58 @@ public class SimpleServletDispatcher extends HttpServlet } else { - String[] tokens = pathInfo.split ("/"); - StringList name = new StringList(); - - for (int tokenCounter = 1; tokenCounter < tokens.length - 1; tokenCounter++) + int keywordIndex = pathInfo.lastIndexOf("-/"); + + if (keywordIndex != -1) { - name.append (tokens[tokenCounter]); - name.append ('.'); - } - - String lastToken = tokens[tokens.length - 1]; - if (pathInfo.endsWith ("/")) - { - name.append(lastToken).append(".").append(lastToken.substring(0, 1).toUpperCase()).append(lastToken.substring(1)).append("_xhtml"); + // Long rewrited URL case. + String[] tokens = pathInfo.substring(0, keywordIndex).split("/"); + + StringList name = new StringList(); + // Note: as pathInfo starts always with a '/', the first good token index is 1. + for (int tokenCounter = 1; tokenCounter < tokens.length - 1; tokenCounter++) + { + name.append (tokens[tokenCounter]); + name.append ('.'); + } + + String lastToken = tokens[tokens.length - 1]; + name.append (lastToken.substring(0, 1).toUpperCase()).append (lastToken.substring(1).replace('.', '_')); + result = name.toString (); } else { - Matcher matcher = URL_PARAMETER_PATTERN.matcher(lastToken); - if (matcher.matches()) + String[] tokens = pathInfo.split ("/"); + + StringList name = new StringList(); + // Note: as pathInfo starts always with a '/', the first good token index is 1. + for (int tokenCounter = 1; tokenCounter < tokens.length - 1; tokenCounter++) { - //logger.debug("group 1=[" + matcher.group(1) + "]"); - lastToken = matcher.group(1) + ".xhtml"; + name.append (tokens[tokenCounter]); + name.append ('.'); } - - name.append (lastToken.substring(0, 1).toUpperCase()).append (lastToken.substring(1).replace('.', '_')); + + String lastToken = tokens[tokens.length - 1]; + if (pathInfo.endsWith ("/")) + { + name.append(lastToken).append(".").append(lastToken.substring(0, 1).toUpperCase()).append(lastToken.substring(1)).append("_xhtml"); + } + else + { + Matcher matcher = SHORT_REWRITED_URL_CLASS.matcher(lastToken); + if (matcher.matches()) + { + // Short rewrited URL case. + //logger.debug("group 1=[" + matcher.group(1) + "]"); + lastToken = matcher.group(1) + ".xhtml"; + } + + name.append (lastToken.substring(0, 1).toUpperCase()).append (lastToken.substring(1).replace('.', '_')); + } + + result = name.toString (); + logger.debug ("==>[" + tokens[tokens.length - 1] + "]"); } - - result = name.toString (); - logger.debug ("==>[" + tokens[tokens.length - 1] + "]"); } } @@ -329,7 +358,7 @@ public class SimpleServletDispatcher extends HttpServlet */ String path = request.getRequestURI(); - if ((!path.endsWith("/")) && (!path.endsWith(".xhtml"))) + if ((!path.endsWith("/")) && (!path.endsWith(".xhtml")) && (!path.contains("-/"))) { path = getServletContext ().getRealPath("/") + request.getRequestURI(); @@ -377,27 +406,136 @@ public class SimpleServletDispatcher extends HttpServlet } } + + /** + * "Code can be shortest, speedest and memory smallest, but not the three in same time, only two", unknow citation. + * + * Note: characters array avalaible here http://fr.wikipedia.org/wiki/Table_des_caract%C3%A8res_Unicode_%280000-0FFF%29 + */ + static protected char NONE = (char) 0; + static protected int[] rewritingParameterMapping = + { + /* 00 */ NONE , NONE , NONE , NONE , NONE , NONE , NONE , NONE , NONE , NONE , NONE , NONE , NONE , NONE , NONE , NONE , + /* 10 */ NONE , NONE , NONE , NONE , NONE , NONE , NONE , NONE , NONE , NONE , NONE , NONE , NONE , NONE , NONE , NONE , + /* 20 */ '-' , NONE , NONE , '-' , '-' , '-' , '-' , '-' , '-' , '-' , '-' , '-' , '-' , '-' , '-' , '-' , + /* 30 */ '0' , '1' , '2' , '3' , '4' , '5' , '6' , '7' , '8' , '9' , '-' , '-' , '-' , '-' , '-' , '-' , + /* 40 */ '\u0040', 'a' , 'b' , 'c' , 'd' , 'e' , 'f' , 'g' , 'h' , 'i' , 'j' , 'k' , 'l' , 'm' , 'n' , 'o' , + /* 50 */ 'p' , 'q' , 'r' , 's' , 't' , 'u' , 'v' , 'w' , 'x' , 'y' , 'z' , '-' , '-' , '-' , '-' , '-' , + /* 60 */ '-' , '\u0061', '\u0062', '\u0063', '\u0064', '\u0065', '\u0066', '\u0067', '\u0068', '\u0069', '\u006A', '\u006B', '\u006C', '\u006D', '\u006E', '\u006F', + /* 70 */ '\u0070', '\u0071', '\u0072', '\u0073', '\u0074', '\u0075', '\u0076', '\u0077', '\u0078', '\u0079', '\u007A', '\u007B', '\u007C', '\u007D', '-' , '-' , + /* 80 */ NONE , NONE , NONE , NONE , NONE , NONE , NONE , NONE , NONE , NONE , NONE , NONE , NONE , NONE , NONE , NONE , + /* 90 */ NONE , NONE , NONE , NONE , NONE , NONE , NONE , NONE , NONE , NONE , NONE , NONE , NONE , NONE , NONE , NONE , + /* A0 */ '\u00A0', '\u00A1', '\u00A2', '\u00A3', '\u00A4', '\u00A5', '\u00A6', '\u00A7', '\u00A8', '\u00A9', '\u00AA', '\u00AB', '\u00AC', '\u00AD', '\u00AE', '\u00AF', + /* B0 */ '-' , '\u00B1', '\u00B2', '\u00B3', '\u00B4', '\u00B5', '\u00B6', '\u00B7', '\u00B8', '\u00B9', '\u00BA', '\u00BB', '\u00BC', '\u00BD', '\u00BE', '\u00BF', + /* C0 */ 'a' , 'a' , 'a' , 'a' , 'a' , 'a' , 'a' , 'c' , 'e' , 'e' , 'e' , 'e' , 'i' , 'i' , 'i' , 'i' , + /* D0 */ '\u00D0', '\u00D1', 'o' , 'o' , 'o' , 'o' , 'o' , 'o' , '\u00D8', 'u' , 'u' , 'u' , 'u' , 'y' , '\u00DE', '\u00DF', + /* E0 */ 'a' , 'a' , 'a' , 'a' , 'a' , 'a' , 'a' , 'c' , 'e' , 'e' , 'e' , 'e' , 'i' , 'i' , 'i' , 'i' , + /* F0 */ 'o' , 'n' , 'o' , 'o' , 'o' , 'o' , 'o' , '\u00F7', '-' , 'u' , 'u' , 'u' , 'u' , 'y' , '-' , 'y' + }; + + + /** + * + * + * @param parameter + * @return + */ + static String rewriteParameter (String parameter) + { + String result; + + StringBuffer buffer = new StringBuffer(parameter.length()); + + char previousCar = NONE; + for (int charIndex = 0; charIndex < parameter.length(); charIndex++) + { + //logger.info("" + charIndex + " " + parameter.charAt(charIndex) + " " + (char) tab[parameter.charAt(charIndex)]); + char car = (char) rewritingParameterMapping[parameter.charAt(charIndex)]; + if (car != NONE) + { + if ((car != '-') || ((car == '-') && (previousCar != '-'))) + { + buffer.append(car); + previousCar = car; + } + } + } + + if (buffer.charAt(buffer.length() - 1) == '-') + { + buffer.setLength(buffer.length() - 1); + } + + result = buffer.toString(); + logger.info("[" + parameter + "] -> [" + result + "]"); + // + return (result); + } + + + /** + * This method gives a way for a short rewriting URL format. + * + * Sometimes, URL has to be rewrited because we need to put parameter in the page name. + * + * Example: + * "/good/article.xhtm?id=123&class=today&title=story's about me" + * => rewriteShorturl("/good/article", "xhtml", "123", "Story's aboute me"); + * => "/good/article-123-today-story-s-about-me.xhtml" + */ + static public String rewriteShortUrl(String uri, String extension, String... parameters) + { + String result; + + StringList string = new StringList(); + + string.append(uri); + + for (String parameter : parameters) + { + // Not use of String.replaceAll() method in goal to optimize Pattern compile action. + //string.append("-").append(REWRITE_PARAMETER.matcher(parameter.toLowerCase()).replaceAll("-")); + string.append("-").append(rewriteParameter(parameter)); + } + + if ((extension != null) && (extension.length() != 0)) + { + string.append(".").append(extension); + } + + result = string.toString(); + + // + return(result); + } + /** * Extract value from a path. * Example: * "/article-123.xhtml" => "123". */ - static public String rewritedParameter(String path) + static public String[] shortRewritedUrlParameters(String path) { - String result; + String[] result; - Matcher matcher = Pattern.compile("^.+-(\\d+)\\.xhtml$").matcher(path); + Matcher matcher = SHORT_REWRITED_URL_PARAMETERS.matcher(path); if (matcher.matches()) { - //logger.debug("group 1=[" + matcher.group(1) + "]"); - result = matcher.group(1); + if (matcher.groupCount() != 1) + { + result = null; + } + else + { + result = matcher.group(1).split("-"); + } } else { result = null; } - + // return(result); } @@ -406,20 +544,87 @@ public class SimpleServletDispatcher extends HttpServlet /** * */ - static public String rewritedParameter(HttpServletRequest request) + static public String[] shortRewritedUrlParameters(HttpServletRequest request) + { + String[] result; + + result = shortRewritedUrlParameters(request.getRequestURI()); + + // + return(result); + } + + + /** + * Return value of the first parameter. + */ + static public String shortRewritedUrlParameter(String path) { String result; - //logger.debug("uri=[" + request.getRequestURI() + "]"); - Matcher matcher = URL_PARAMETER_PATTERN2.matcher(request.getRequestURI()); - if (matcher.matches()) - { - //logger.debug("group 1=[" + matcher.group(1) + "]"); - result = matcher.group(1); - } - else + + String[] results = shortRewritedUrlParameters(path); + + if ((results == null) || (results.length == 0)) { result = null; } + else + { + result = results[0]; + } + + // + return(result); + } + + + /** + * + */ + static public String shortRewritedUrlParameter(HttpServletRequest request) + { + String result; + + result = shortRewritedUrlParameter(request.getRequestURI()); + + // + return(result); + } + + + /** + * This method gives a way for a long rewriting URL format. Long as in REST. + * + * Sometimes, URL has to be rewrited because we need to put parameter in the page name. + * + * Example: + * "/good/give_file?id=123&filename=foo.jpg" + * => rewriteShorturl("/good/give_file", "123", "foo.jpg"); + * => "/good/give_file-/123/foo.jpg" + * + * Note: "-/" is used to indicate the start of parameters. + * + */ + static public String rewriteLongUrl(String uri, String... parameters) + { + String result; + + StringList string = new StringList(); + + string.append(uri).append("-"); + if ((parameters == null) || (parameters.length == 0)) + { + string.append("/"); + } + else + { + for (String parameter : parameters) + { + string.append("/").append(parameter); + } + } + + result = string.toString(); // return(result); @@ -431,21 +636,25 @@ public class SimpleServletDispatcher extends HttpServlet * Example: * "/article-/123/doors/open.xhtml" => "123", "doors" and "open". */ - static public String[] rewritedParameters(String path) + static public String[] longRewritedUrlParameters(String path) { String[] result; - - result = new String[10]; // STU. - Matcher matcher = Pattern.compile("^.+-(\\d+)\\.xhtml$").matcher(path); - if (matcher.matches()) - { - //logger.debug("group 1=[" + matcher.group(1) + "]"); - result[0] = matcher.group(1); // STU. - } - else - { - result = null; - } + + result = path.substring(path.indexOf("-/") + 2).split("/"); + + // + return(result); + } + + + /** + * + */ + static public String[] rewritedUrlParameters(HttpServletRequest request) + { + String[] result; + + result = longRewritedUrlParameters(request.getRequestURI()); // return(result); diff --git a/src/fr/devinsy/util/web/SimpleSecurityAgent.java b/src/fr/devinsy/util/web/SimpleSecurityAgent.java index bfb767d..59dc55e 100644 --- a/src/fr/devinsy/util/web/SimpleSecurityAgent.java +++ b/src/fr/devinsy/util/web/SimpleSecurityAgent.java @@ -4,6 +4,8 @@ import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import fr.devinsy.kiss4web.CookieHelper; + /** * @@ -48,88 +50,6 @@ public class SimpleSecurityAgent } - /** - * - */ - static public Cookie buildCookie (String name, String value, int duration) - { - Cookie result; - - result = new Cookie (name, value); - result.setMaxAge (duration); - result.setPath ("/"); - result.setSecure (false); - - // - return (result); - } - - - /** - * - */ - static public Cookie getCookie (Cookie[] cookies, String key) - { - Cookie result = null; - - if (cookies == null) - { - result = null; - } - else - { - boolean ended = false; - int cookieCounter = 0; - while (!ended) - { - if (cookieCounter < cookies.length) - { - if (key.equals (cookies[cookieCounter].getName ())) - { - ended = true; - result = cookies[cookieCounter]; - } - else - { - cookieCounter += 1; - } - } - else - { - ended = true; - result = null; - } - } - } - - // - return (result); - } - - - /** - * - */ - static public Object getCookieValue (Cookie[] cookies, String key) - { - Object result; - - Cookie cookie = getCookie(cookies, key); - - if (cookie == null) - { - result = null; - } - else - { - result = cookie.getValue(); - } - - // - return(result); - } - - /** * */ @@ -137,7 +57,7 @@ public class SimpleSecurityAgent { String result; - result = (String) getCookieValue(request.getCookies (), this.userIdLabel); + result = (String) CookieHelper.getCookieValue(request, this.userIdLabel); // return(result); @@ -151,7 +71,7 @@ public class SimpleSecurityAgent { String result; - result = (String) getCookieValue(request.getCookies (), this.accountIdLabel); + result = (String) CookieHelper.getCookieValue(request, this.accountIdLabel); // return(result); @@ -166,7 +86,7 @@ public class SimpleSecurityAgent { String result; - result = (String) getCookieValue(request.getCookies (), this.authLabel); + result = (String) CookieHelper.getCookieValue(request, this.authLabel); // return(result); @@ -227,9 +147,10 @@ public class SimpleSecurityAgent // Refresh cookie. int duration = 60*60; String auth = computeAuth(String.valueOf(accountId), userId, request.getRemoteAddr(), this.secretKey); - response.addCookie (buildCookie(this.authLabel, auth, duration)); - response.addCookie (buildCookie(this.accountIdLabel, accountId, duration)); - response.addCookie (buildCookie(this.userIdLabel, userId, duration)); + + response.addCookie (CookieHelper.buildCookie(this.authLabel, auth, duration)); + response.addCookie (CookieHelper.buildCookie(this.accountIdLabel, accountId, duration)); + response.addCookie (CookieHelper.buildCookie(this.userIdLabel, userId, duration)); logger.info("set [" + auth + "," + accountId + "," + userId + "," + request.getRemoteAddr() + ")"); } @@ -240,8 +161,8 @@ public class SimpleSecurityAgent */ public void reset(HttpServletRequest request, HttpServletResponse response) { - response.addCookie(buildCookie(this.authLabel, "", 0)); - response.addCookie(buildCookie(this.accountIdLabel, "", 0)); - response.addCookie(buildCookie(this.userIdLabel, "", 0)); + CookieHelper.reset(response, this.authLabel); + CookieHelper.reset(response, this.accountIdLabel); + CookieHelper.reset(response, this.userIdLabel); } } \ No newline at end of file