Util.java revision 345
0N/A/*
0N/A * CDDL HEADER START
0N/A *
0N/A * The contents of this file are subject to the terms of the
0N/A * Common Development and Distribution License (the "License").
0N/A * You may not use this file except in compliance with the License.
0N/A *
0N/A * See LICENSE.txt included in this distribution for the specific
0N/A * language governing permissions and limitations under the License.
0N/A *
0N/A * When distributing Covered Code, include this CDDL HEADER in each
0N/A * file and include the License file at LICENSE.txt.
0N/A * If applicable, add the following below this CDDL HEADER, with the
0N/A * fields enclosed by brackets "[]" replaced with your own identifying
0N/A * information: Portions Copyright [yyyy] [name of copyright owner]
0N/A *
0N/A * CDDL HEADER END
0N/A */
0N/A
0N/A/*
1054N/A * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
1190N/A * Use is subject to license terms.
1185N/A */
0N/Apackage org.opensolaris.opengrok.web;
0N/A
65N/Aimport java.io.IOException;
125N/Aimport java.io.UnsupportedEncodingException;
125N/Aimport java.io.Writer;
1185N/Aimport java.net.URI;
58N/Aimport java.net.URISyntaxException;
77N/Aimport java.net.URLEncoder;
125N/Aimport java.util.StringTokenizer;
125N/Aimport java.text.DecimalFormat;
125N/Aimport java.text.NumberFormat;
1092N/Aimport org.opensolaris.opengrok.configuration.RuntimeEnvironment;
1016N/Aimport org.opensolaris.opengrok.history.Annotation;
125N/A
1092N/A/**
261N/A * File for useful functions
261N/A */
583N/Apublic class Util {
312N/A /**
1062N/A * Return a string which represents a <code>CharSequence</code> in HTML.
312N/A *
467N/A * @param q a character sequence
428N/A * @return a string representing the character sequence in HTML
126N/A */
1088N/A
58N/A public static String htmlize(CharSequence q) {
394N/A StringBuilder sb = new StringBuilder(q.length() * 2);
1185N/A htmlize(q, sb);
8N/A return sb.toString();
1185N/A }
1185N/A
1185N/A /**
77N/A * Append a character sequence to an <code>Appendable</code> object. Escape
0N/A * special characters for HTML.
0N/A *
0N/A * @param q a character sequence
0N/A * @param out the object to append the character sequence to
0N/A * @exception IOException if an I/O error occurs
0N/A */
491N/A public static void htmlize(CharSequence q, Appendable out)
439N/A throws IOException {
491N/A for (int i = 0; i < q.length(); i++) {
465N/A htmlize(q.charAt(i), out);
465N/A }
491N/A }
491N/A
491N/A /**
886N/A * Append a character sequence to a <code>StringBuilder</code>
886N/A * object. Escape special characters for HTML. This method is identical to
886N/A * <code>htmlize(CharSequence,Appendable)</code>, except that it is
886N/A * guaranteed not to throw <code>IOException</code> because it uses a
886N/A * <code>StringBuilder</code>.
886N/A *
491N/A * @param q a character sequence
491N/A * @param out the object to append the character sequence to
491N/A * @see #htmlize(CharSequence, Appendable)
491N/A */
65N/A public static void htmlize(CharSequence q, StringBuilder out) {
65N/A try {
65N/A htmlize(q, (Appendable) out);
65N/A } catch (IOException ioe) {
464N/A // StringBuilder's append methods are not declared to throw
0N/A // IOException, so this should never happen.
58N/A throw new RuntimeException("StringBuilder should not throw IOException", ioe);
312N/A }
312N/A }
1185N/A
260N/A public static void htmlize(char[] cs, int length, Appendable out)
491N/A throws IOException {
428N/A for (int i = 0; i < length && i < cs.length; i++) {
376N/A htmlize(cs[i], out);
376N/A }
0N/A }
11N/A
0N/A /**
240N/A * Append a character to a an <code>Appendable</code> object. If the
1016N/A * character has special meaning in HTML, append a sequence of characters
58N/A * representing the special character.
58N/A *
58N/A * @param c the character to append
58N/A * @param out the object to append the character to
77N/A * @exception IOException if an I/O error occurs
207N/A */
1185N/A private static void htmlize(char c, Appendable out) throws IOException {
207N/A switch (c) {
910N/A case '&':
1190N/A out.append("&amp;");
77N/A break;
260N/A case '>':
112N/A out.append("&gt;");
77N/A break;
77N/A case '<':
77N/A out.append("&lt;");
77N/A break;
260N/A case '\n':
77N/A out.append("<br/>");
77N/A break;
77N/A default:
491N/A out.append(c);
1088N/A }
77N/A }
491N/A
111N/A public static String breadcrumbPath(String urlPrefix, String l) {
111N/A return breadcrumbPath(urlPrefix, l, '/');
111N/A }
111N/A
1088N/A public static String breadcrumbPath(String urlPrefix, String l, char sep) {
111N/A if (l == null || l.length() <= 1) {
111N/A return l;
111N/A }
491N/A StringBuilder hyperl = new StringBuilder(20);
1088N/A if (l.charAt(0) == sep) {
1088N/A hyperl.append(sep);
1088N/A }
1088N/A int s = 0,
1088N/A e = 0;
1088N/A while ((e = l.indexOf(sep, s)) >= 0) {
886N/A if (e - s > 0) {
111N/A hyperl.append("<a href=\"" + urlPrefix);
491N/A hyperl.append(l.substring(0, e));
77N/A hyperl.append("/\">");
77N/A hyperl.append(l.substring(s, e));
1185N/A hyperl.append("</a>");
491N/A hyperl.append(sep);
491N/A }
491N/A s = e + 1;
77N/A }
491N/A if (s < l.length()) {
1088N/A hyperl.append("<a href=\"" + urlPrefix);
1062N/A hyperl.append(l);
491N/A hyperl.append("\">");
491N/A hyperl.append(l.substring(s, l.length()));
1088N/A hyperl.append("</a>");
491N/A }
491N/A return hyperl.toString();
491N/A }
491N/A
491N/A public static String redableSize(long num) {
491N/A float l = (float) num;
491N/A NumberFormat formatter = new DecimalFormat("#,###,###,###.#");
491N/A if (l < 1024) {
1088N/A return formatter.format(l);
491N/A } else if (l < 1048576) {
491N/A return (formatter.format(l / 1024) + "K");
491N/A } else {
491N/A return ("<b>" + formatter.format(l / 1048576) + "M</b>");
491N/A }
491N/A }
491N/A
491N/A public static void readableLine(int num, Writer out, Annotation annotation)
1088N/A throws IOException {
491N/A String snum = String.valueOf(num);
1088N/A if (num > 1) {
491N/A out.write("\n");
491N/A }
491N/A out.write("<a class=\"");
491N/A out.write((num % 10 == 0 ? "hl" : "l"));
491N/A out.write("\" name=\"");
491N/A out.write(snum);
491N/A out.write("\">");
491N/A out.write((num > 999 ? " " : (num > 99 ? " " : (num > 9 ? " " : " "))));
491N/A out.write(snum);
491N/A out.write(" </a>");
491N/A if (annotation != null) {
491N/A String r = annotation.getRevision(num);
1016N/A boolean enabled = annotation.isEnabled(num);
1016N/A
1016N/A out.write("<span class=\"blame\"><span class=\"l\"> ");
491N/A for (int i = r.length(); i < annotation.getWidestRevision(); i++) {
491N/A out.write(" ");
491N/A }
491N/A
491N/A if (enabled) {
491N/A out.write("<a href=\"");
491N/A out.write(URIEncode(annotation.getFilename()));
491N/A out.write("?a=true&r=");
491N/A out.write(URIEncode(r));
799N/A out.write("\">");
1088N/A }
799N/A
886N/A htmlize(r, out);
886N/A
886N/A if (enabled) {
886N/A out.write("</a>");
886N/A }
891N/A
886N/A out.write(" </span>");
891N/A
886N/A String a = annotation.getAuthor(num);
886N/A out.write("<span class=\"l\"> ");
886N/A for (int i = a.length(); i < annotation.getWidestAuthor(); i++) {
886N/A out.write(" ");
886N/A }
886N/A String link = RuntimeEnvironment.getInstance().getUserPage();
491N/A if (link != null && link.length() > 0) {
491N/A out.write("<a href=\"");
491N/A out.write(link);
1088N/A out.write(URIEncode(a));
491N/A out.write("\">");
1088N/A htmlize(a, out);
491N/A out.write("</a>");
491N/A } else {
491N/A htmlize(a, out);
491N/A }
491N/A out.write(" </span></span>");
491N/A }
491N/A }
491N/A
491N/A /**
1088N/A * Append path and date into a string in such a way that lexicographic
491N/A * sorting gives the same results as a walk of the file hierarchy. Thus
1088N/A * null (\u0000) is used both to separate directory components and to
491N/A * separate the path from the date.
1088N/A */
491N/A public static String uid(String path, String date) {
491N/A return path.replace('/', '\u0000') + "\u0000" + date;
491N/A }
491N/A
491N/A public static String uid2url(String uid) {
1088N/A String url = uid.replace('\u0000', '/'); // replace nulls with slashes
491N/A return url.substring(0, url.lastIndexOf('/')); // remove date from end
491N/A }
491N/A
491N/A public static String URIEncode(String q) {
491N/A try {
1088N/A // We should probably use an encoding which supports a larger
1062N/A // character set, but use ISO-8859-1 for now, since that's what
491N/A // we use other places in the code.
1115N/A return URLEncoder.encode(q, "ISO-8859-1");
1115N/A } catch (UnsupportedEncodingException e) {
1115N/A // Should not happen. ISO-8859-1 must be supported by all JVMs.
77N/A return null;
491N/A }
1106N/A }
1106N/A
1106N/A public static String URIEncodePath(String path) {
1106N/A try {
1106N/A URI uri = new URI(null, null, path, null);
489N/A return uri.getRawPath();
1106N/A } catch (URISyntaxException ex) {
490N/A ex.printStackTrace();
1106N/A return "";
491N/A }
1106N/A }
1106N/A
1106N/A public static String formQuoteEscape(String q) {
1106N/A if (q == null) {
1106N/A return "";
490N/A }
1106N/A StringBuilder sb = new StringBuilder();
1106N/A char c;
1106N/A for (int i = 0; i < q.length(); i++) {
1106N/A c = q.charAt(i);
1106N/A if (c == '"') {
490N/A sb.append("&quot;");
1106N/A } else {
491N/A sb.append(c);
1088N/A }
491N/A }
1026N/A return sb.toString();
1088N/A }
1026N/A
491N/A /**
491N/A * Build a string that may be converted to a Query and passed to Lucene.
491N/A * All parameters may be passed as null or an empty string to indicate that
491N/A * they are unused.
491N/A *
1088N/A * @param freetext The string from the "Full Search" text-field. This field
491N/A * will be applied as it is specified.
1088N/A * @param defs The string from the "Definition" text-field. This field
491N/A * will be searched for in the <b>defs</b> field in the lucene
491N/A * index. All occurences of ":" will be replaced with "\:"
491N/A * @param refs The string from the "Symbol" text-field. This field
491N/A * will be searched for in the <b>refs</b> field in the lucene
491N/A * index. All occurences of ":" will be replaced with "\:"
491N/A * @param path The string from the "File Path" text-field. This field
491N/A * will be searched for in the <b>path</b> field in the lucene
491N/A * index. All occurences of ":" will be replaced with "\:"
491N/A * @param hist The string from the "History" text-field. This field
1088N/A * will be searched for in the <b>hist</b> field in the lucene
491N/A * index. All occurences of ":" will be replaced with "\:"
491N/A * @return A string to be parsed by the Lucene parser.
491N/A */
491N/A public static String buildQueryString(String freetext, String defs, String refs, String path, String hist) {
491N/A StringBuilder sb = new StringBuilder();
99N/A if (freetext != null && freetext.length() > 0) {
491N/A sb.append(freetext.replace("::", "\\:\\:"));
491N/A }
1088N/A
491N/A if (defs != null && defs.length() > 0) {
1088N/A sb.append(" defs:(");
491N/A sb.append(defs.replace(":", "\\:"));
491N/A sb.append(")");
491N/A }
491N/A
126N/A if (refs != null && refs.length() > 0) {
126N/A sb.append(" refs:(");
126N/A sb.append(refs.replace(":", "\\:"));
491N/A sb.append(")");
491N/A }
491N/A
491N/A if (path != null && path.length() > 0) {
491N/A sb.append(" path:(");
491N/A sb.append(path.replace(":", "\\:"));
491N/A sb.append(")");
491N/A }
491N/A
491N/A if (hist != null && hist.length() > 0) {
491N/A sb.append(" hist:(");
491N/A sb.append(hist.replace(":", "\\:"));
491N/A sb.append(")");
126N/A }
491N/A
491N/A return sb.toString();
491N/A }
491N/A}
491N/A