Java tutorial
/* * ==================================================================== * Copyright (c) 2005-2012 sventon project. All rights reserved. * * This software is licensed as described in the file LICENSE, which * you should have received as part of this distribution. The terms * are also available at http://www.sventon.org. * If newer versions of this license are posted there, you may use a * newer version instead, at your option. * ==================================================================== */ package org.sventon.util; import org.apache.commons.lang.StringEscapeUtils; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.text.StrSubstitutor; import org.sventon.model.ChangeType; import org.sventon.model.ChangedPath; import org.sventon.model.LogEntry; import org.sventon.model.RepositoryName; import javax.servlet.http.HttpServletResponse; import java.text.DateFormat; import java.util.HashMap; import java.util.Map; import java.util.SortedSet; import java.util.regex.Matcher; import static org.sventon.util.EncodingUtils.encodeUrl; /** * Class responsible for creating HTML formatted content. * * @author jesper@sventon.org */ public final class HTMLCreator { public static final String LOG_MESSAGE_KEY = "logMessage"; public static final String AUTHOR_KEY = "author"; public static final String DATE_KEY = "date"; public static final String ADDED_COUNT_KEY = "addedCount"; public static final String MODIFIED_COUNT_KEY = "modifiedCount"; public static final String REPLACED_COUNT_KEY = "replacedCount"; public static final String DELETED_COUNT_KEY = "deletedCount"; public static final String CHANGED_PATHS_KEY = "changedPaths"; /** * Prevent instantiation. */ private HTMLCreator() { } /** * Creates a string containing the details for a given revision. * * @param bodyTemplate Body template string. * @param logEntry log entry revision. * @param baseURL Application base URL. * @param repositoryName Repository name. * @param response Response, null if n/a. * @param dateFormat Date formatter instance. * @return Result */ public static String createRevisionDetailBody(final String bodyTemplate, final LogEntry logEntry, final String baseURL, final RepositoryName repositoryName, final DateFormat dateFormat, final HttpServletResponse response) { final Map<String, String> valueMap = new HashMap<String, String>(); int added = 0; int modified = 0; int replaced = 0; int deleted = 0; //noinspection unchecked final SortedSet<ChangedPath> latestChangedPaths = logEntry.getChangedPaths(); for (final ChangedPath entryPath : latestChangedPaths) { final ChangeType type = entryPath.getType(); switch (type) { case ADDED: added++; break; case MODIFIED: modified++; break; case REPLACED: replaced++; break; case DELETED: deleted++; break; default: throw new IllegalArgumentException("Unsupported type: " + type); } } final String logMessage = WebUtils.nl2br(StringEscapeUtils.escapeHtml(logEntry.getMessage())); //TODO: Parse to apply Bugtraq link final String author = logEntry.getAuthor(); valueMap.put(ADDED_COUNT_KEY, Matcher.quoteReplacement(String.valueOf(added))); valueMap.put(MODIFIED_COUNT_KEY, Matcher.quoteReplacement(String.valueOf(modified))); valueMap.put(REPLACED_COUNT_KEY, Matcher.quoteReplacement(String.valueOf(replaced))); valueMap.put(DELETED_COUNT_KEY, Matcher.quoteReplacement(String.valueOf(deleted))); valueMap.put(LOG_MESSAGE_KEY, Matcher.quoteReplacement(StringUtils.trimToEmpty(logMessage))); valueMap.put(AUTHOR_KEY, Matcher.quoteReplacement(StringUtils.trimToEmpty(author))); valueMap.put(DATE_KEY, dateFormat.format(logEntry.getDate())); valueMap.put(CHANGED_PATHS_KEY, Matcher.quoteReplacement(HTMLCreator.createChangedPathsTable(logEntry.getChangedPaths(), logEntry.getRevision(), null, baseURL, repositoryName, false, false, response))); return new StrSubstitutor(valueMap).replace(bodyTemplate); } /** * Creates a HTML table containing the changed paths for given revision. * * @param changedPaths Paths changed in this revision. * @param revision Revision. * @param pathAtRevision The target's path at current revision or <tt>null</tt> if unknown. * @param baseURL Base application URL. * @param repositoryName Repository name. * @param showLatestRevInfo If true, the latest revision details DIV will be displayed. * @param linkToHead If true, navigation links will be pointing at HEAD if applicable. * @param response The HTTP response, used to encode the session parameter to the generated URLs. Null if n/a. * @return The HTML table. */ public static String createChangedPathsTable(final SortedSet<ChangedPath> changedPaths, final long revision, final String pathAtRevision, final String baseURL, final RepositoryName repositoryName, final boolean showLatestRevInfo, final boolean linkToHead, final HttpServletResponse response) { final StringBuilder sb = new StringBuilder("<table class=\"changedPathsTable\">\n"); sb.append(" <tr>\n"); sb.append(" <th align=\"left\">Action</th>\n"); sb.append(" <th align=\"left\">Path</th>\n"); sb.append(" </tr>\n"); for (final ChangedPath path : changedPaths) { final ChangeType changeType = path.getType(); sb.append(" <tr>\n"); sb.append(" <td valign=\"top\"><i>").append(changeType).append("</i></td>\n"); sb.append(" <td>"); String goToUrl; switch (changeType) { case ADDED: // fall thru case REPLACED: // goToUrl goToUrl = createGoToUrl(baseURL, path.getPath(), revision, repositoryName, linkToHead); if (response != null) { goToUrl = response.encodeURL(goToUrl); } sb.append("<a href=\"").append(goToUrl); if (showLatestRevInfo) { sb.append("&showlatestrevinfo=true"); } sb.append("\" title=\"Show\">"); if (path.getPath().equals(pathAtRevision)) { sb.append("<i>").append(path.getPath()).append("</i>").append("</a>"); } else { sb.append(path.getPath()).append("</a>"); } break; case MODIFIED: // diffUrl String diffUrl = createDiffUrl(baseURL, path.getPath(), revision, repositoryName, linkToHead); if (response != null) { diffUrl = response.encodeURL(diffUrl); } sb.append("<a href=\"").append(diffUrl); if (showLatestRevInfo) { sb.append("&showlatestrevinfo=true"); } sb.append("\" title=\"Diff with previous version\">"); if (path.getPath().equals(pathAtRevision)) { sb.append("<i>").append(path.getPath()).append("</i>").append("</a>"); } else { sb.append(path.getPath()).append("</a>"); } break; case DELETED: // del goToUrl = createGoToUrl(baseURL, path.getPath(), revision - 1, repositoryName, false); if (response != null) { goToUrl = response.encodeURL(goToUrl); } sb.append("<a href=\"").append(goToUrl); sb.append("\" title=\"Show previous revision\"><del>").append(path.getPath()).append("</del></a>"); break; default: throw new IllegalArgumentException("Unsupported type: " + changeType); } if (path.getCopyPath() != null) { sb.append("<br>(<i>Copy from</i> "); goToUrl = createGoToUrl(baseURL, path.getCopyPath(), path.getCopyRevision(), repositoryName, false); if (response != null) { goToUrl = response.encodeURL(goToUrl); } sb.append("<a href=\"").append(goToUrl); if (showLatestRevInfo) { sb.append("&showlatestrevinfo=true"); } sb.append("\" title=\"Show\">").append(path.getCopyPath()).append("</a>").append(" @ "); String revisionInfoUrl = createRevisionInfoUrl(baseURL, path.getCopyRevision(), repositoryName); if (response != null) { revisionInfoUrl = response.encodeURL(revisionInfoUrl); } sb.append("<a href=\"").append(revisionInfoUrl); sb.append("\">"); sb.append(path.getCopyRevision()).append("</a>)"); } sb.append("</td>\n"); sb.append(" </tr>\n"); } sb.append("</table>"); return sb.toString(); } /** * Creates a <i>goto</i> URL based on given parameters. * * @param baseURL Base application URL * @param path Path * @param revision Revision * @param repositoryName Repository name. * @param linkToHead If true, the navigation link will point to head. * @return The URL */ protected static String createGoToUrl(final String baseURL, final String path, final long revision, final RepositoryName repositoryName, final boolean linkToHead) { final StringBuilder sb = new StringBuilder(baseURL).append("repos/"); sb.append(encodeUrl(repositoryName.toString() + "/goto" + path)); sb.append("?revision=").append(linkToHead ? "HEAD" : revision); return sb.toString(); } /** * Creates a <i>diff</i> URL based on given parameters. * * @param baseURL Base application URL * @param path Path * @param revision Revision * @param repositoryName Repository name. * @param linkToHead If true, the navigation link will point to head. * @return The URL */ protected static String createDiffUrl(final String baseURL, final String path, final long revision, final RepositoryName repositoryName, final boolean linkToHead) { final String entry1 = path + "@" + revision; final String entry2 = path + "@" + (revision - 1); final StringBuilder sb = new StringBuilder(baseURL).append("repos/"); sb.append(encodeUrl(repositoryName.toString() + "/diff" + path)); sb.append("?revision=").append(linkToHead ? "HEAD" : revision); sb.append("&entries=").append(entry1); sb.append("&entries=").append(entry2); return sb.toString(); } /** * Creates a <i>revision info</i> URL based on given parameters. * * @param baseURL Base application URL * @param revision Revision * @param repositoryName Repository name. * @return The URL */ protected static String createRevisionInfoUrl(final String baseURL, final long revision, final RepositoryName repositoryName) { final StringBuilder sb = new StringBuilder(baseURL).append("repos/"); sb.append(encodeUrl(repositoryName.toString() + "/info")); sb.append("?revision=").append(encodeUrl(String.valueOf(revision))); return sb.toString(); } }