Java tutorial
// Copyright 2012 Google Inc. All Rights Reserved. // // 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 com.google.gitiles; import static com.google.common.base.Preconditions.checkNotNull; import static javax.servlet.http.HttpServletResponse.SC_NOT_FOUND; import com.google.common.base.Charsets; import org.eclipse.jgit.diff.DiffFormatter; import org.eclipse.jgit.errors.IncorrectObjectTypeException; import org.eclipse.jgit.errors.MissingObjectException; import org.eclipse.jgit.http.server.ServletUtils; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.revwalk.RevWalk; import org.eclipse.jgit.treewalk.AbstractTreeIterator; import org.eclipse.jgit.treewalk.CanonicalTreeParser; import org.eclipse.jgit.treewalk.EmptyTreeIterator; import org.eclipse.jgit.treewalk.filter.PathFilter; import java.io.IOException; import java.io.OutputStream; import java.util.Arrays; import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** Serves an HTML page with all the diffs for a commit. */ public class DiffServlet extends BaseServlet { private static final String PLACEHOLDER = "id=\"DIFF_OUTPUT_BLOCK\""; private final Linkifier linkifier; public DiffServlet(Renderer renderer, Linkifier linkifier) { super(renderer); this.linkifier = checkNotNull(linkifier, "linkifier"); } @Override protected void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException { GitilesView view = ViewFilter.getView(req); Repository repo = ServletUtils.getRepository(req); RevWalk walk = new RevWalk(repo); try { boolean showCommit; AbstractTreeIterator oldTree; AbstractTreeIterator newTree; try { // If we are viewing the diff between a commit and one of its parents, // include the commit detail in the rendered page. showCommit = isParentOf(walk, view.getOldRevision(), view.getRevision()); oldTree = getTreeIterator(walk, view.getOldRevision().getId()); newTree = getTreeIterator(walk, view.getRevision().getId()); } catch (MissingObjectException e) { res.setStatus(SC_NOT_FOUND); return; } catch (IncorrectObjectTypeException e) { res.setStatus(SC_NOT_FOUND); return; } Map<String, Object> data = getData(req); data.put("title", "Diff - " + view.getRevisionRange()); if (showCommit) { data.put("commit", new CommitSoyData(linkifier, req, repo, walk, view) .toSoyData(walk.parseCommit(view.getRevision().getId()))); } if (!data.containsKey("repositoryName") && (view.getRepositoryName() != null)) { data.put("repositoryName", view.getRepositoryName()); } if (!data.containsKey("breadcrumbs")) { data.put("breadcrumbs", view.getBreadcrumbs()); } String[] html = renderAndSplit(data); res.setStatus(HttpServletResponse.SC_OK); res.setContentType(FormatType.HTML.getMimeType()); res.setCharacterEncoding(Charsets.UTF_8.name()); setCacheHeaders(req, res); OutputStream out = res.getOutputStream(); try { out.write(html[0].getBytes(Charsets.UTF_8)); formatHtmlDiff(out, repo, walk, oldTree, newTree, view.getTreePath()); out.write(html[1].getBytes(Charsets.UTF_8)); } finally { out.close(); } } finally { walk.release(); } } private static boolean isParentOf(RevWalk walk, Revision oldRevision, Revision newRevision) throws MissingObjectException, IncorrectObjectTypeException, IOException { RevCommit newCommit = walk.parseCommit(newRevision.getId()); if (newCommit.getParentCount() > 0) { return Arrays.asList(newCommit.getParents()).contains(oldRevision.getId()); } else { return oldRevision == Revision.NULL; } } private String[] renderAndSplit(Map<String, Object> data) { String html = renderer.newRenderer("gitiles.diffDetail").setData(data).render(); int id = html.indexOf(PLACEHOLDER); if (id < 0) { throw new IllegalStateException("Template must contain " + PLACEHOLDER); } int lt = html.lastIndexOf('<', id); int gt = html.indexOf('>', id + PLACEHOLDER.length()); return new String[] { html.substring(0, lt), html.substring(gt + 1) }; } private void formatHtmlDiff(OutputStream out, Repository repo, RevWalk walk, AbstractTreeIterator oldTree, AbstractTreeIterator newTree, String path) throws IOException { DiffFormatter diff = new HtmlDiffFormatter(renderer, out); try { if (!path.equals("")) { diff.setPathFilter(PathFilter.create(path)); } diff.setRepository(repo); diff.setDetectRenames(true); diff.format(oldTree, newTree); } finally { diff.release(); } } private static AbstractTreeIterator getTreeIterator(RevWalk walk, ObjectId id) throws IOException { if (!id.equals(ObjectId.zeroId())) { CanonicalTreeParser p = new CanonicalTreeParser(); p.reset(walk.getObjectReader(), walk.parseTree(id)); return p; } else { return new EmptyTreeIterator(); } } }