Package org.meshcms.core

Source Code of org.meshcms.core.WebUtils

/*
* Copyright 2004-2009 Luciano Vernaschi
*
* This file is part of MeshCMS.
*
* MeshCMS is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* MeshCMS is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with MeshCMS.  If not, see <http://www.gnu.org/licenses/>.
*/

package org.meshcms.core;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.StringReader;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.charset.CharsetEncoder;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.Locale;
import java.util.Properties;
import java.util.Random;
import java.util.ResourceBundle;
import java.util.StringTokenizer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.activation.MimeType;
import javax.activation.MimeTypeParseException;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import javax.servlet.jsp.PageContext;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.meshcms.util.Path;
import org.meshcms.util.Utils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.w3c.tidy.Tidy;

/**
* A collection of utilities related to a web application.
*/
public final class WebUtils {
  public static final SimpleDateFormat numericDateFormatter =
      new SimpleDateFormat("yyyyMMddHHmmss");
 
  /**
   * Characters allowed in a file name.
   */
  public static final String FN_CHARS =
      "'()-.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz";
 
  /**
   * Mapping of the ISO-8859-1 characters to characters included in FN_CHARS.
   */
  public static final String FN_CHARMAP =
      "________________________________" +
      "__'____'()..--._0123456789..(-)." +
      "_ABCDEFGHIJKLMNOPQRSTUVWXYZ(_)__" +
      "'abcdefghijklmnopqrstuvwxyz(_)-_" +
      "________________________________" +
      "__cL.Y_P_Ca(__R-o-23'mP._10)423_" +
      "AAAAAAACEEEEIIIIENOOOOOxOUUUUYTS" +
      "aaaaaaaceeeeiiiienooooo-ouuuuyty";
 
  /**
   * Characters that are considered spacers in a file name.
   */
  public static final String FN_SPACERS = "_!'()-";
 
  /**
   * The default array of welcome file names. This array is used if the welcome
   * file names can't be found in the web.xml configuration file.
   */
  public static final String[] DEFAULT_WELCOME_FILES =
  {"index.html", "index.htm", "index.jsp"};
 
  private static final String AUTH_CODE_PREFIX = "AUTH: ";
  private static Random authRandom;
 
  public static Properties NUMBER_TO_ENTITY;
  public static Properties ENTITY_TO_NUMBER;
 
  public static final Pattern BODY_REGEX =
      Pattern.compile("(?s)<body[^>]*>(.*?)</body[^>]*>");
  // Pattern fixTagsPattern = Pattern.compile("(?s)([^>]*>|[^<>]+)+");
  public static final Pattern PRE_REGEX =
      Pattern.compile("(?s)<pre[^>]*>.*?</pre>");
  public static final Pattern PRE_BR_REGEX =
      Pattern.compile("<br[^>]*>(?:\\s*\\n)?");
  public static final Pattern HYPERLINK_REGEX =
      Pattern.compile("(?:https?://|ftp://|www\\.)[\\w-/=:#%&\\?\\.]+[\\w-/=:#%&\\?]");
  public static final Pattern EMAIL_REGEX =
      Pattern.compile("[\\w-\\.]+@[\\w-\\.]+\\.[a-zA-Z]{2,6}");

  static {
    String[] entities = {
      "39", "#39", "160", "nbsp", "161", "iexcl", "162", "cent", "163", "pound",
      "164", "curren", "165", "yen", "166", "brvbar", "167", "sect",
      "168", "uml", "169", "copy", "170", "ordf", "171", "laquo", "172", "not",
      "173", "shy", "174", "reg", "175", "macr", "176", "deg", "177", "plusmn",
      "178", "sup2", "179", "sup3", "180", "acute", "181", "micro",
      "182", "para", "183", "middot", "184", "cedil", "185", "sup1",
      "186", "ordm", "187", "raquo", "188", "frac14", "189", "frac12",
      "190", "frac34", "191", "iquest", "192", "Agrave", "193", "Aacute",
      "194", "Acirc", "195", "Atilde", "196", "Auml", "197", "Aring",
      "198", "AElig", "199", "Ccedil", "200", "Egrave", "201", "Eacute",
      "202", "Ecirc", "203", "Euml", "204", "Igrave", "205", "Iacute",
      "206", "Icirc", "207", "Iuml", "208", "ETH", "209", "Ntilde",
      "210", "Ograve", "211", "Oacute", "212", "Ocirc", "213", "Otilde",
      "214", "Ouml", "215", "times", "216", "Oslash", "217", "Ugrave",
      "218", "Uacute", "219", "Ucirc", "220", "Uuml", "221", "Yacute",
      "222", "THORN", "223", "szlig", "224", "agrave", "225", "aacute",
      "226", "acirc", "227", "atilde", "228", "auml", "229", "aring",
      "230", "aelig", "231", "ccedil", "232", "egrave", "233", "eacute",
      "234", "ecirc", "235", "euml", "236", "igrave", "237", "iacute",
      "238", "icirc", "239", "iuml", "240", "eth", "241", "ntilde",
      "242", "ograve", "243", "oacute", "244", "ocirc", "245", "otilde",
      "246", "ouml", "247", "divide", "248", "oslash", "249", "ugrave",
      "250", "uacute", "251", "ucirc", "252", "uuml", "253", "yacute",
      "254", "thorn", "255", "yuml", "402", "fnof", "913", "Alpha",
      "914", "Beta", "915", "Gamma", "916", "Delta", "917", "Epsilon",
      "918", "Zeta", "919", "Eta", "920", "Theta", "921", "Iota",
      "922", "Kappa", "923", "Lambda", "924", "Mu", "925", "Nu", "926", "Xi",
      "927", "Omicron", "928", "Pi", "929", "Rho", "931", "Sigma", "932", "Tau",
      "933", "Upsilon", "934", "Phi", "935", "Chi", "936", "Psi",
      "937", "Omega", "945", "alpha", "946", "beta", "947", "gamma",
      "948", "delta", "949", "epsilon", "950", "zeta", "951", "eta",
      "952", "theta", "953", "iota", "954", "kappa", "955", "lambda",
      "956", "mu", "957", "nu", "958", "xi", "959", "omicron", "960", "pi",
      "961", "rho", "962", "sigmaf", "963", "sigma", "964", "tau",
      "965", "upsilon", "966", "phi", "967", "chi", "968", "psi",
      "969", "omega", "977", "thetasym", "978", "upsih", "982", "piv",
      "8226", "bull", "8230", "hellip", "8242", "prime", "8243", "Prime",
      "8254", "oline", "8260", "frasl", "8472", "weierp", "8465", "image",
      "8476", "real", "8482", "trade", "8501", "alefsym", "8592", "larr",
      "8593", "uarr", "8594", "rarr", "8595", "darr", "8596", "harr",
      "8629", "crarr", "8656", "lArr", "8657", "uArr", "8658", "rArr",
      "8659", "dArr", "8660", "hArr", "8704", "forall", "8706", "part",
      "8707", "exist", "8709", "empty", "8711", "nabla", "8712", "isin",
      "8713", "notin", "8715", "ni", "8719", "prod", "8721", "sum",
      "8722", "minus", "8727", "lowast", "8730", "radic", "8733", "prop",
      "8734", "infin", "8736", "ang", "8743", "and", "8744", "or",
      "8745", "cap", "8746", "cup", "8747", "int", "8756", "there4",
      "8764", "sim", "8773", "cong", "8776", "asymp", "8800", "ne",
      "8801", "equiv", "8804", "le", "8805", "ge", "8834", "sub", "8835", "sup",
      "8836", "nsub", "8838", "sube", "8839", "supe", "8853", "oplus",
      "8855", "otimes", "8869", "perp", "8901", "sdot", "8968", "lceil",
      "8969", "rceil", "8970", "lfloor", "8971", "rfloor", "9001", "lang",
      "9002", "rang", "9674", "loz", "9824", "spades", "9827", "clubs",
      "9829", "hearts", "9830", "diams", "34", "quot", "38", "amp", "60", "lt",
      "62", "gt", "338", "OElig", "339", "oelig", "352", "Scaron",
      "353", "scaron", "376", "Yuml", "710", "circ", "732", "tilde",
      "8194", "ensp", "8195", "emsp", "8201", "thinsp", "8204", "zwnj",
      "8205", "zwj", "8206", "lrm", "8207", "rlm", "8211", "ndash",
      "8212", "mdash", "8216", "lsquo", "8217", "rsquo", "8218", "sbquo",
      "8220", "ldquo", "8221", "rdquo", "8222", "bdquo", "8224", "dagger",
      "8225", "Dagger", "8240", "permil", "8249", "lsaquo", "8250", "rsaquo",
      "8364", "euro"
    };
   
    NUMBER_TO_ENTITY = new Properties();
    ENTITY_TO_NUMBER = new Properties();
   
    for (int i = 0; i < entities.length; i += 2) {
      NUMBER_TO_ENTITY.setProperty(entities[i], entities[i + 1]);
      ENTITY_TO_NUMBER.setProperty(entities[i + 1], entities[i]);
    }
  }
 
  private WebUtils() {
  }

  public static String convertToHTMLEntities(String s, boolean encodeTags) {
    return convertToHTMLEntities(s, null, encodeTags);
  }
 
  public static String convertToHTMLEntities(String s, String charset, boolean encodeTags) {
    CharsetEncoder ce = charset == null ? null : Charset.forName(charset).newEncoder();
    StringBuffer sb = new StringBuffer(s.length());
   
    for (int i = 0; i < s.length(); i++) {
      char c = s.charAt(i);
      int n = ((int) c) & 0xFFFF;
     
      if (n > 127) {
        if (ce != null && ce.canEncode(c)) {
          sb.append(c);
        } else {
          String ent = NUMBER_TO_ENTITY.getProperty(Integer.toString(c));
         
          if (ent == null) {
            sb.append("&#").append(n).append(';');
          } else {
            sb.append('&').append(ent).append(';');
          }
        }
      } else if (encodeTags && (n == 34 || /* n == 38 || */ n == 39 || n == 60 || n == 62)) {
        sb.append('&').append(NUMBER_TO_ENTITY.getProperty(Integer.toString(c))).append(';');
      } else {
        sb.append(c);
      }
    }
   
    return sb.toString();
  }
 
  /**
   * Parses the web.xml configuration file and returns an array of welcome file
   * names. If the names can't be found, {@link #DEFAULT_WELCOME_FILES} is
   * returned.
   *
   * @param sc ServletContext required to access the <code>web.xml</code> file
   * @return an array of welcome file names
   */
  public static String[] getWelcomeFiles(ServletContext sc) {
    File webXml = new File(sc.getRealPath("/WEB-INF/web.xml"));
    String[] welcomeFiles = null;
   
    try {
      DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
      DocumentBuilder parser = factory.newDocumentBuilder();
      Document document = parser.parse(webXml);
      Element root = document.getDocumentElement();
      Element wfl = (Element)
      (root.getElementsByTagName("welcome-file-list").item(0));
      NodeList wfnl = wfl.getElementsByTagName("welcome-file");
      welcomeFiles = new String[wfnl.getLength()];
     
      for (int i = 0; i < welcomeFiles.length; i++) {
        welcomeFiles[i] = wfnl.item(i).getFirstChild().getNodeValue();
      }
    } catch (Exception ex) {
      ex.printStackTrace();
    }
   
    if (welcomeFiles == null || welcomeFiles.length == 0) {
      welcomeFiles = DEFAULT_WELCOME_FILES;
    }
   
    return welcomeFiles;
  }
 
  /**
   * Returns a request parameter in the form <code>&name=value</code>. Returns
   * null if the value has not been found.
   */
  public static String getFullParameter(HttpServletRequest request, String name) {
    String value = request.getParameter(name);
    return (value == null) ? "" : "&" + name + "=" + value;
  }
 
  /**
   * Returns the full context path of the given path.
   */
  public static String getPathInContext(HttpServletRequest request, Path path) {
    return request.getContextPath() + "/" + path;
  }
 
  /**
   * Reconstructs the full URL of the context home. The URL is returned as a
   * StringBuffer so other elements can be added easily.
   */
  public static StringBuffer getContextHomeURL(HttpServletRequest request) {
    StringBuffer sb = new StringBuffer();
    String scheme = request.getScheme();
    sb.append(scheme).append("://");
    sb.append(request.getServerName());
    int port = request.getServerPort();
   
    if (!(("http".equals(scheme) && port == 80) ||
        ("https".equals(scheme) && port == 443))) {
      sb.append(':').append(port);
    }
   
    return sb.append(request.getContextPath());
  }
 
  /**
   * Returns the complete path of the folder of current theme (context
   * path included).
   *
   * @param request used to get the theme name
   */
  public static String getFullThemeFolder(HttpServletRequest request) {
    Path themePath = (Path) request.getAttribute(HitFilter.THEME_PATH_ATTRIBUTE);
   
    return (themePath == null) ? "" :
      request.getContextPath() + "/" + themePath;
  }
 
  /**
   * Returns the complete path of the <code>main.jsp</code> file (context
   * path included).
   *
   * @param request used to get the theme name
   */
  public static String getFullThemeFile(HttpServletRequest request) {
    return getFullThemeFolder(request) + "/" + SiteMap.THEME_DECORATOR;
  }
 
  /**
   * Returns the complete path of the <code>main.css</code> file (context
   * path included).
   *
   * @param request used to get the theme name
   */
  public static String getFullThemeCSS(HttpServletRequest request) {
    return getFullThemeFolder(request) + "/" + SiteMap.THEME_CSS;
  }
 
  /**
   * Returns the complete path of the <code>meshcms.css</code> file (context
   * path included). If <code>meshcms.css</code> is not found in the theme
   * folder, the default from the admin theme is returned.
   *
   * @param request used to get the theme name
   */
  public static String getFullMeshCSS(WebSite webSite, HttpServletRequest request) {
    Path themePath = (Path) request.getAttribute(HitFilter.THEME_PATH_ATTRIBUTE);
    Path cssPath = themePath.add(SiteMap.MESHCMS_CSS);
   
    if (!webSite.getFile(cssPath).exists()) {
      cssPath = webSite.getAdminThemePath().add(SiteMap.MESHCMS_CSS);
    }
   
    return request.getContextPath() + "/" + cssPath;
  }
 
  /**
   * Returns the path of the folder of current theme, relative to page path.
   *
   * @param request used to get the theme name
   * @param pageDir path of the requested page folder
   */
  public static Path getThemeFolderPath(HttpServletRequest request, Path pageDir) {
    Path themePath = (Path) request.getAttribute(HitFilter.THEME_PATH_ATTRIBUTE);
    return (themePath == null) ? pageDir : themePath.getRelativeTo(pageDir);
  }
 
  /**
   * Returns the path of the <code>main.jsp</code> file, relative to page path.
   *
   * @param request used to get the theme name
   * @param pageDir path of the requested page folder
   */
  public static Path getThemeFilePath(HttpServletRequest request, Path pageDir) {
    return getThemeFolderPath(request, pageDir).add(SiteMap.THEME_DECORATOR);
  }
 
  /**
   * Returns the complete path of the <code>main.css</code> file, relative to
   * page path.
   *
   * @param request used to get the theme name
   * @param pageDir path of the requested page folder
   */
  public static Path getThemeCSSPath(HttpServletRequest request, Path pageDir) {
    return getThemeFolderPath(request, pageDir).add(SiteMap.THEME_CSS);
  }
 
  /**
   * Returns the path of the <code>meshcms.css</code> file, relative to page
   * path. If <code>meshcms.css</code> is not found in the theme
   * folder, the default from the admin theme is returned.
   *
   * @param request used to get the theme name
   * @param pageDir path of the requested page folder
   */
  public static Path getMeshCSSPath(WebSite webSite, HttpServletRequest request,
      Path pageDir) {
    Path themePath = (Path) request.getAttribute(HitFilter.THEME_PATH_ATTRIBUTE);
    Path cssPath = themePath.add(SiteMap.MESHCMS_CSS);
   
    if (!webSite.getFile(cssPath).exists()) {
      cssPath = webSite.getAdminThemePath().add(SiteMap.MESHCMS_CSS);
    }
   
    return cssPath.getRelativeTo(pageDir);
  }

  /**
   * Returns a numeric code for an object. This code is used in the menu, but
   * can be used elsewhere if needed. It is equal to the hash code of the
   * object, but never negative, since the minus sign creates problems when
   * converted to a string and used as part of a variable name in JavaScript.
   */
  public static int getMenuCode(Object o) {
    return o.hashCode() & 0x7FFFFFFF;
  }
 
  /**
   * Returns the 2nd level domain from which the request comes.
   */
  public static String get2ndLevelDomain(HttpServletRequest request) {
    return get2ndLevelDomain(request.getRequestURL().toString());
  }
 
  /**
   * Returns the 2nd level domain from the URL.
   */
  public static String get2ndLevelDomain(String urlString) {
    try {
      URL url = new URL(urlString);
      String host = url.getHost();
      int dot = host.lastIndexOf('.');
     
      if (dot != -1) {
        String partial = host.substring(0, dot);
        dot = partial.lastIndexOf('.');
       
        if (dot != -1) {
          host = host.substring(dot + 1);
        }
       
        return host;
      }
    } catch (Exception ex) {}
   
    return null;
  }
 
  /**
   * This method must be called to avoid the current page to be cached. For
   * example, some modules will call this method to be sure that they
   * are parsed again when the page is called another time.
   */
  public static void setBlockCache(HttpServletRequest request) {
    request.setAttribute(HitFilter.BLOCK_CACHE_ATTRIBUTE,
        HitFilter.BLOCK_CACHE_ATTRIBUTE);
  }
 
  /**
   * Checks the current Request scope to see if some class has called the
   * {@link #setBlockCache} method.
   */
  public static boolean isCacheBlocked(HttpServletRequest request) {
    return request.getAttribute(HitFilter.BLOCK_CACHE_ATTRIBUTE) != null;
  }
 
  /**
   * Tries to locate a Locale stored in the Page scope or in the Request scope.
   * If none is found, returns the Locale of the request, or at least the
   * system default Locale.
   */
  public static Locale getPageLocale(PageContext pageContext) {
    Locale locale = null;
   
    UserInfo userInfo = (UserInfo) pageContext.getAttribute("userInfo",
        PageContext.SESSION_SCOPE);
   
    if (userInfo != null) {
      locale = Utils.getLocale(userInfo.getPreferredLocaleCode());
    }
   
    if (locale == null) {
      locale = (Locale) pageContext.getAttribute(HitFilter.LOCALE_ATTRIBUTE,
          PageContext.PAGE_SCOPE);
    }
   
    Enumeration en = pageContext.getAttributeNamesInScope(PageContext.PAGE_SCOPE);
   
    while (locale == null && en.hasMoreElements()) {
      Object obj = pageContext.getAttribute((String) en.nextElement());
     
      if (obj instanceof Locale) {
        locale = (Locale) obj;
      }
    }
   
    if (locale == null) {
      locale = (Locale) pageContext.getAttribute(HitFilter.LOCALE_ATTRIBUTE,
          PageContext.REQUEST_SCOPE);
    }
   
    en = pageContext.getAttributeNamesInScope(PageContext.REQUEST_SCOPE);
   
    while (locale == null && en.hasMoreElements()) {
      Object obj = pageContext.getAttribute((String) en.nextElement(),
          PageContext.REQUEST_SCOPE);
     
      if (obj instanceof Locale) {
        locale = (Locale) obj;
      }
    }
   
    if (locale == null) {
      locale = pageContext.getRequest().getLocale();
    }
   
    if (locale == null) {
      locale = Locale.getDefault();
    }
   
    return locale;
  }
 
  /**
   * Tries to locate a ResourceBundle stored in the Page scope or in the Request
   * scope using the JSTL.
   *
   * @return the ResourceBundle, or null if not found
   */
  public static ResourceBundle getPageResourceBundle(PageContext pageContext) {
    Enumeration en = pageContext.getAttributeNamesInScope(PageContext.PAGE_SCOPE);
   
    while (en.hasMoreElements()) {
      Object obj = pageContext.getAttribute((String) en.nextElement());
     
      if (obj instanceof ResourceBundle) {
        return (ResourceBundle) obj;
      } else if (obj instanceof javax.servlet.jsp.jstl.fmt.LocalizationContext) {
        return ((javax.servlet.jsp.jstl.fmt.LocalizationContext) obj).getResourceBundle();
      }
    }
   
    en = pageContext.getAttributeNamesInScope(PageContext.REQUEST_SCOPE);
   
    while (en.hasMoreElements()) {
      Object obj = pageContext.getAttribute((String) en.nextElement(),
          PageContext.REQUEST_SCOPE);
     
      if (obj instanceof ResourceBundle) {
        return (ResourceBundle) obj;
      } else if (obj instanceof javax.servlet.jsp.jstl.fmt.LocalizationContext) {
        return ((javax.servlet.jsp.jstl.fmt.LocalizationContext) obj).getResourceBundle();
      }
    }
   
    return null;
  }
 
  /**
   * Returns a modified name that does not contain characters not recommended
   * in a file name.
   */
  public static String fixFileName(String name, boolean useSpacers) {
    name = name.trim();
    StringBuffer sb = new StringBuffer(name.length());
    boolean addSpacer = false;
    char spacer = FN_SPACERS.charAt(0);
    char c;
   
    for (int i = 0; i < name.length(); i++) {
      c = name.charAt(i);
     
      if (c < 256) {
        c = FN_CHARMAP.charAt(c);
      } else {
        c = spacer;
      }
     
      if (FN_SPACERS.indexOf(c) < 0) { // not a spacer
        if (addSpacer) { // needs to add a spacer due to previous characters
          if (useSpacers && sb.length() > 0) { // add a spacer only if not as first char
            sb.append(spacer);
          }
         
          addSpacer = false;
        }
       
        sb.append(c);
      } else {
        addSpacer = true; // it's a spacer, will be added next if needed
      }
    }
   
    while(sb.length() > 0 && sb.charAt(sb.length() - 1) == '.') {
      sb.deleteCharAt(sb.length() - 1);
    }
   
    if (sb.length() == 0) {
      sb.append(spacer);
    }
   
    return sb.toString();
  }
 
  /**
   * Returns a nicer representation of the number as a file length. The number
   * is returned as bytes, kilobytes or megabytes, with the unit attached.
   */
  public static String formatFileLength(long length, Locale locale,
      ResourceBundle bundle) {
    NumberFormat numberFormat = NumberFormat.getNumberInstance(locale);
    DecimalFormat format = (DecimalFormat) numberFormat;
    format.applyPattern("###0.##");
    double num = length;
    String unit;
   
    if (length < Utils.KBYTE) {
      unit = "genericUnitBytes";
    } else if (length < Utils.MBYTE) {
      num /= Utils.KBYTE;
      unit = "genericUnitKilobytes";
    } else if (length < Utils.GBYTE) {
      num /= Utils.MBYTE;
      unit = "genericUnitMegabytes";
    } else {
      num /= Utils.GBYTE;
      unit = "genericUnitGigabytes";
    }
   
    return format.format(num) + bundle.getString(unit);
  }
 
  public static String getCharsetCanonicalName(String charsetName) {
    Charset suggestedCharset;
   
    try {
      suggestedCharset = Charset.forName(charsetName);
      charsetName = suggestedCharset.name();
    } catch (Exception ex) {}
   
    return charsetName;
  }
 
  public static String parseCharset(String fullValue) {
    try {
      return new MimeType(fullValue).getParameter("charset");
    } catch (MimeTypeParseException ex) {
      return null;
    }
  }
 
  public static void updateLastModifiedTime(HttpServletRequest request, File file) {
    updateLastModifiedTime(request, file.lastModified());
  }
 
  public static void updateLastModifiedTime(HttpServletRequest request, long time) {
    if (time > getLastModifiedTime(request)) {
      request.setAttribute(HitFilter.LAST_MODIFIED_ATTRIBUTE, new Long(time));
    }
  }
 
  public static long getLastModifiedTime(HttpServletRequest request) {
    long time = 0L;
   
    try {
      time = ((Long) request.getAttribute(HitFilter.LAST_MODIFIED_ATTRIBUTE)).longValue();
    } catch (Exception ex) {}
   
    return time;
  }
 
  public static javax.mail.Session getMailSession(WebSite webSite) {
    Properties props = new Properties();
    props.put("mail.smtp.host", webSite.getConfiguration().getMailServer());
    final String smtpUsername = webSite.getConfiguration().getSmtpUsername();
    final String smtpPassword = webSite.getConfiguration().getSmtpPassword();
   
    if (!Utils.isNullOrWhitespace(smtpUsername)) {
      props.put("mail.smtp.auth", "true");
    }
   
    javax.mail.Session mailSession = javax.mail.Session.getInstance(props,
        new javax.mail.Authenticator() {
      protected javax.mail.PasswordAuthentication getPasswordAuthentication() {
        return new javax.mail.PasswordAuthentication(smtpUsername, smtpPassword);
      }
    });
   
    return mailSession;
  }
 
  public static File getCacheFile(WebSite webSite, SiteMap siteMap, Path pagePath) {
    if (siteMap == null) {
      siteMap = webSite.getSiteMap();
    }
   
    pagePath = siteMap.getServedPath(pagePath);
    File cacheFile = webSite.getRepositoryFile(pagePath, HitFilter.CACHE_FILE_NAME);
   
    // a cached page too small is suspicious
    if (cacheFile.exists() && cacheFile.length() > 256 &&
        cacheFile.lastModified() > siteMap.getLastModified()) {
      return cacheFile;
    }
   
    return null;
  }
 
  public static boolean isCached(WebSite webSite, SiteMap siteMap, Path pagePath) {
    if (siteMap == null) {
      siteMap = webSite.getSiteMap();
    }
   
    int cacheType = webSite.getConfiguration().getCacheType();
    pagePath = siteMap.getServedPath(pagePath);
   
    if (cacheType == Configuration.IN_MEMORY_CACHE) {
      return siteMap.isCached(pagePath);
    } else if (cacheType == Configuration.ON_DISK_CACHE ||
        cacheType == Configuration.MIXED_CACHE) {
      return getCacheFile(webSite, siteMap, pagePath) != null;
    }
   
    return false;
  }
 
  public static void removeFromCache(WebSite webSite, SiteMap siteMap, Path pagePath) {
    if (siteMap == null) {
      siteMap = webSite.getSiteMap();
    }
   
    int cacheType = webSite.getConfiguration().getCacheType();
    pagePath = siteMap.getServedPath(pagePath);
   
    if (cacheType == Configuration.IN_MEMORY_CACHE ||
        cacheType == Configuration.MIXED_CACHE) {
      siteMap.removeFromCache(pagePath);
    }
   
    if (cacheType == Configuration.ON_DISK_CACHE ||
        cacheType == Configuration.MIXED_CACHE) {
      File cacheFile = getCacheFile(webSite, siteMap, pagePath);
     
      if (cacheFile != null && cacheFile.exists()) {
        Utils.forceDelete(cacheFile);
      }
    }
  }
 
  public static Path getCorrespondingPath(WebSite webSite, Path path,
      String otherRoot) {
    Path cPath = path.replace(0, otherRoot);
    return webSite.getFile(cPath).exists() ? cPath : new Path(otherRoot);
  }
 
  public static String[] getAcceptedLanguages(HttpServletRequest request) {
    Enumeration alEnum = request.getHeaders("Accept-Language");
    List list = new ArrayList();
   
    while (alEnum.hasMoreElements()) {
      String s = (String) alEnum.nextElement();
      StringTokenizer st = new StringTokenizer(s, ",");
     
      while (st.hasMoreTokens()) {
        String token = st.nextToken();
        int sc = token.indexOf(';');
       
        if (sc >= 0) {
          token = token.substring(0, sc);
        }
       
        token = token.trim();
        token = Utils.replace(token, '-', "_");
       
        if (!list.contains(token)) {
          list.add(token);
        }
      }
    }
   
    // add main language codes as fallback (e.g. it_IT, en, en_US becomes
    // it_IT, en, en_US, it
    int n = list.size();
   
    for (int i = 0; i < n; i++) {
      String token = (String) list.get(i);
      int us = token.indexOf('_');
     
      if (us >= 0) {
        token = token.substring(0, us);
       
        if (!list.contains(token)) {
          list.add(token);
        }
      }
    }
   
    return (String[]) list.toArray(new String[list.size()]);
  }
 
  public static String fixRelativeURLs(String html, Path root, boolean relative) {
    Pattern p = Pattern.compile("(<(?:a|img)(?:[^>]*?)(?:src|href)=\")([^\":?]*)(\"[^>]*?>)",
        Pattern.CASE_INSENSITIVE);
    Matcher m = p.matcher(html);
    StringBuffer sb = new StringBuffer(html.length());
   
    while(m.find()) {
      Path path = relative ? new Path(m.group(2)).getRelativeTo(root) :
        new Path(root, m.group(2));
      m.appendReplacement(sb, m.group(1) + path.getAsLink() + m.group(3));
    }
   
    m.appendTail(sb);
    return sb.toString();
  }
 
  private static Pattern jspBlockPattern;
 
  public static Pattern getJSPBlockPattern() {
    if (jspBlockPattern == null) {
      jspBlockPattern = Pattern.compile("<(?!%@\\s*taglib[^>]*\\buri\\s*=\\s*\"" +
          "meshcms-taglib\"[^>]*\\bprefix\\s*=\\s*\"cms\"|%@\\s*page|%--|" +
          "/?cms:|/?\\w+(?!:)\\W|!--|!DOCTYPE)([^>]*)>");
    }
   
    return jspBlockPattern;
  }
 
  public static boolean verifyJSP(WebSite webSite, Path jspPath) {
    if (webSite instanceof VirtualWebSite) {
      VirtualWebSite vws = (VirtualWebSite) webSite;
      MainWebSite mws = vws.getMainWebSite();
     
      if (mws.getMultiSiteManager().isJSPBlocked(vws) &&
          !jspPath.isContainedIn(vws.getAdminPath())) {
        Pattern p = getJSPBlockPattern();
       
        try {
          Matcher m = p.matcher(Utils.readFully(vws.getFile(jspPath)));
          return !m.find();
        } catch (IOException ex) {
          vws.log("Error while verifying /" + jspPath + " in " +
              vws.getDirName(), ex);
        }
      }
    }
   
    return true;
  }
 
  public static String tidyHTML(WebSite webSite, String html) {
    // First, we need to fix a bug when <br> tags are enclosed in <pre> tags.
    // Simply replace <br> with \n using regular expressions
    StringBuffer sb = new StringBuffer();
    Matcher preM = PRE_REGEX.matcher(html);
   
    while (preM.find()) {
      String preTag = preM.group();
      Matcher brM = PRE_BR_REGEX.matcher(preTag);
      preTag = brM.replaceAll("\n").replaceAll("\\$", "\\\\\\$");
      preM.appendReplacement(sb, preTag);
    }
   
    preM.appendTail(sb);
   
    // Now we can safely use jTidy
    Tidy tidy = new Tidy();
    tidy.setConfigurationFromFile(webSite.getFile
        (webSite.getAdminPath().add("tidy.config")).getAbsolutePath());
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
   
    try {
      tidy.parse(new ByteArrayInputStream(sb.toString().getBytes("utf-8")), baos);
      return WebUtils.convertToHTMLEntities(baos.toString("utf-8"),
          Utils.SYSTEM_CHARSET, false);
    } catch (Exception ex) {
      webSite.log("Error while tidying HTML code", ex);
    }
   
    return null;
  }
 
  public static String createExcerpt(WebSite webSite, String body, int length,
      String contextPath, Path oldPage, Path newPage) {
    StringBuffer sb = new StringBuffer(length + 20);
    StringReader sr = new StringReader(body);
    int n;
    char c;
    int count = 0;
    boolean text = true;

    try {
      while ((n = sr.read()) != -1) {
        c = (char) n;
       
        if (c == '<') {
          text = false;
        } else if (text) {
          if (Character.isWhitespace(c)) {
            if (count >= length) {
              sb.append("&hellip;");
              break;
            }
          } else {
            count++;
          }
        } else if (c == '>') {
          text = true;
        }
       
        sb.append(c);
      }
    } catch (IOException ex) {
      webSite.log("Error while creating page excerpt", ex);
    }
   
    String excerpt = sb.toString();
    String tidy = tidyHTML(webSite, excerpt);
   
    if (tidy != null) {
      Matcher m = BODY_REGEX.matcher(tidy);
     
      if (m.find()) {
        excerpt = m.group(1);
      }
    }
   
    excerpt = fixLinks(webSite, excerpt, contextPath, oldPage, newPage);
   
    if (webSite.getConfiguration().isReplaceThumbnails()) {
      excerpt = replaceThumbnails(webSite, excerpt, contextPath, newPage);
    }

    return excerpt;
  }
 
  public static String fixLinks(WebSite webSite, String body,
      String contextPath, Path oldPage, Path newPage) {
    oldPage = webSite.getDirectory(oldPage);
    newPage = webSite.getDirectory(newPage);
   
    if (oldPage.equals(newPage)) {
      return body;
    }
   
    Pattern tagPattern = Pattern.compile("<(?:img|a)\\b[^>]*>");
    Pattern attrPattern = Pattern.compile("(src|href)\\s*=\\s*([\"'])(.*?)\\2");
    Matcher tagMatcher = tagPattern.matcher(body);
    StringBuffer sb = null;
   
    while (tagMatcher.find()) {
      if (sb == null) {
        sb = new StringBuffer(body.length());
      }
     
      String tag = tagMatcher.group();
      Matcher attrMatcher = attrPattern.matcher(tag);
     
      if (attrMatcher.find()) {
        String url = attrMatcher.group(3).trim();

        if (url.indexOf("://") < 0) {
          Path path = null;

          if (url.startsWith("/")) {
            if (contextPath.length() > 0 && url.startsWith(contextPath)) {
              url = url.substring(contextPath.length());
            }

            path = new Path(url);
          } else {
            path = new Path(oldPage, url);
          }

          if (path != null) {
            path = path.getRelativeTo(newPage);
           
            if (path.isRoot()) {
              path = new Path(webSite.getSiteMap().getCurrentWelcome(newPage));
            }
           
            String newTag = attrMatcher.replaceFirst(attrMatcher.group(1) +
                "=\"" + path + "\"");
            tagMatcher.appendReplacement(sb, newTag);
          }
        }
      }
    }
   
    if (sb != null) {
      tagMatcher.appendTail(sb);
      body = sb.toString();
    }
   
    return body;
  }
 
  public static String replaceThumbnails(WebSite webSite, String body,
      String contextPath, Path pagePath) {
    ResizedThumbnail thumbMaker = new ResizedThumbnail();
    thumbMaker.setHighQuality(webSite.getConfiguration().isHighQualityThumbnails());
    thumbMaker.setMode(ResizedThumbnail.MODE_STRETCH);
    Pattern whPattern = Pattern.compile
        ("width\\s*:\\s*(\\d+)\\s*px|width\\s*=[\"'](\\d+)[\"']|height\\s*:\\s*(\\d+)\\s*px|height\\s*=[\"'](\\d+)[\"']");
    Pattern srcPattern = Pattern.compile("src\\s*=\\s*([\"'])(.*?)\\1");
    Pattern imgPattern = Pattern.compile("<img\\b[^>]*>");
    Matcher imgMatcher = imgPattern.matcher(body);
    StringBuffer sb = null;
   
    while (imgMatcher.find()) {
      if (sb == null) {
        sb = new StringBuffer(body.length());
      }
     
      String imgTag = imgMatcher.group();
      Matcher whMatcher = whPattern.matcher(imgTag);
      int styleWidth = 0;
      int attrWidth = 0;
      int styleHeight = 0;
      int attrHeight = 0;
     
      while (whMatcher.find()) {
        styleWidth = Utils.parseInt(whMatcher.group(1), styleWidth);
        attrWidth = Utils.parseInt(whMatcher.group(2), attrWidth);
        styleHeight = Utils.parseInt(whMatcher.group(3), styleHeight);
        attrHeight = Utils.parseInt(whMatcher.group(4), attrHeight);
      }
     
      int w = (styleWidth < 1) ? attrWidth : styleWidth;
      int h = (styleHeight < 1) ? attrHeight : styleHeight;
     
      if (w > 0 || h > 0) {
        Matcher srcMatcher = srcPattern.matcher(imgTag);
       
        if (srcMatcher.find()) {
          String imgURL = srcMatcher.group(2).trim();
         
          if (imgURL.indexOf("://") < 0) {
            Path imgPath = null;
           
            if (imgURL.startsWith("/")) {
              if (contextPath.length() > 0 && imgURL.startsWith(contextPath)) {
                imgURL = imgURL.substring(contextPath.length());
              }
             
              imgPath = new Path(imgURL);
            } else {
              imgPath = new Path(webSite.getDirectory(pagePath), imgURL);
            }
           
            if (imgPath != null) {
              thumbMaker.setWidth(w);
              thumbMaker.setHeight(h);
              String thumbName = thumbMaker.getSuggestedFileName();
              Path thumbPath = thumbMaker.checkAndCreate(webSite, imgPath, thumbName);
             
              if (thumbPath != null) {
                String newImgTag = srcMatcher.replaceAll("src=\"" +
                    webSite.getLink(thumbPath, pagePath) + "\"");
                imgMatcher.appendReplacement(sb, newImgTag);
              }
            }
          }
        }
      }
    }
   
    if (sb != null) {
      imgMatcher.appendTail(sb);
      body = sb.toString();
    }
   
    return body;
  }
 
  public static String addToQueryString(String url, String name, String value,
      boolean encodeValue) {
    char sep = url.indexOf('?') < 0 ? '?' : '&';
    return url + sep + name + '=' + (encodeValue ? Utils.encodeURL(value) : value);
  }
 
  public static String findLinks(String text, boolean noFollow) {
    String rel = noFollow ? " rel=\"nofollow\"" : "";
    Matcher m = HYPERLINK_REGEX.matcher(text);
    StringBuffer sb = new StringBuffer(text.length());

    while (m.find()) {
      String link = m.group();
      String url = link;

      if (url.indexOf("://") < 0) {
        url = "http://" + url;
      }

      String tag = "<a href=\"" + url + "\"" + rel + '>' + link + "</a>";
      m.appendReplacement(sb, tag);
    }

    m.appendTail(sb);
    return sb.toString();
  }
 
  public static String findEmails(String text) {
    Matcher m = EMAIL_REGEX.matcher(text);
    StringBuffer sb = new StringBuffer(text.length());
   
    while (m.find()) {
      String email = m.group();
      String tag = "<a href=\"mailto:" + email + "\">" + email + "</a>";
      m.appendReplacement(sb, tag);
    }
   
    m.appendTail(sb);
    return sb.toString();
  }
 
  public static String setAuthCode(HttpSession session, String page) {
    if (authRandom == null) {
      authRandom = new Random();
    }
   
    String code = Integer.toString(authRandom.nextInt());
    session.setAttribute(AUTH_CODE_PREFIX + page, code);
    return code;
  }
 
  public static String getAuthCode(HttpSession session, String page) {
    String key = AUTH_CODE_PREFIX + page;
    String code = (String) session.getAttribute(key);
    session.removeAttribute(key);
    return Utils.noNull(code);
  }
}
TOP

Related Classes of org.meshcms.core.WebUtils

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.