Java tutorial
/******************************************************************************* * Copyright (c) 2010, 2014 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.orion.server.gerritfs; import java.io.IOException; import java.io.PrintWriter; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.errors.IncorrectObjectTypeException; import org.eclipse.jgit.errors.MissingObjectException; import org.eclipse.jgit.lib.AnyObjectId; import org.eclipse.jgit.lib.Config; import org.eclipse.jgit.lib.FileMode; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ObjectLoader; import org.eclipse.jgit.lib.PersonIdent; import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.revwalk.RevTree; import org.eclipse.jgit.revwalk.RevWalk; import org.eclipse.jgit.treewalk.CanonicalTreeParser; import org.eclipse.jgit.treewalk.TreeWalk; import org.eclipse.jgit.treewalk.filter.PathFilter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.gerrit.extensions.annotations.Export; import com.google.gerrit.httpd.WebSession; import com.google.gerrit.reviewdb.client.Project.NameKey; import com.google.gerrit.server.AccessPath; import com.google.gerrit.server.account.AccountCache; import com.google.gerrit.server.account.AccountException; import com.google.gerrit.server.account.AccountManager; import com.google.gerrit.server.account.AccountState; import com.google.gerrit.server.account.AuthRequest; import com.google.gerrit.server.config.GerritServerConfig; import com.google.gerrit.server.git.GitRepositoryManager; import com.google.gerrit.server.project.NoSuchProjectException; import com.google.gerrit.server.project.ProjectControl; import com.google.inject.Inject; import com.google.inject.Provider; import com.google.inject.Singleton; @Export("/list/*") @Singleton public class GerritListFile extends HttpServlet { private final GitRepositoryManager repoManager; private final ProjectControl.Factory projControlFactory; private final Provider<WebSession> session; private final AccountCache accountCache; private final Config config; private final AccountManager accountManager; private static Logger log = LoggerFactory.getLogger(GerritListFile.class); @Inject public GerritListFile(final GitRepositoryManager repoManager, final ProjectControl.Factory project, Provider<WebSession> session, AccountCache accountCache, @GerritServerConfig Config config, final AccountManager accountManager) { this.repoManager = repoManager; this.projControlFactory = project; this.session = session; this.accountCache = accountCache; this.config = config; this.accountManager = accountManager; } @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { handleAuth(req); resp.setCharacterEncoding("UTF-8"); final PrintWriter out = resp.getWriter(); try { String pathInfo = req.getPathInfo(); Pattern pattern = Pattern.compile("/([^/]*)(?:/([^/]*)(?:/(.*))?)?"); Matcher matcher = pattern.matcher(pathInfo); matcher.matches(); String projectName = null; String refName = null; String filePath = null; if (matcher.groupCount() > 0) { projectName = matcher.group(1); refName = matcher.group(2); filePath = matcher.group(3); if (projectName == null || projectName.equals("")) { projectName = null; } else { projectName = java.net.URLDecoder.decode(projectName, "UTF-8"); } if (refName == null || refName.equals("")) { refName = null; } else { refName = java.net.URLDecoder.decode(refName, "UTF-8"); } if (filePath == null || filePath.equals("")) { filePath = null; } else { filePath = java.net.URLDecoder.decode(filePath, "UTF-8"); } } if (projectName != null) { if (filePath == null) filePath = ""; NameKey projName = NameKey.parse(projectName); ProjectControl control; try { control = projControlFactory.controlFor(projName); if (!control.isVisible()) { log.debug("Project not visible!"); resp.sendError(HttpServletResponse.SC_UNAUTHORIZED, "You need to be logged in to see private projects"); return; } } catch (NoSuchProjectException e1) { } Repository repo = repoManager.openRepository(projName); if (refName == null) { ArrayList<HashMap<String, Object>> contents = new ArrayList<HashMap<String, Object>>(); List<Ref> call; try { call = new Git(repo).branchList().call(); Git git = new Git(repo); for (Ref ref : call) { HashMap<String, Object> jsonObject = new HashMap<String, Object>(); jsonObject.put("name", ref.getName()); jsonObject.put("type", "ref"); jsonObject.put("size", "0"); jsonObject.put("path", ""); jsonObject.put("project", projectName); jsonObject.put("ref", ref.getName()); lastCommit(git, null, ref.getObjectId(), jsonObject); contents.add(jsonObject); } String response = JSONUtil.write(contents); resp.setContentType("application/json"); resp.setHeader("Cache-Control", "no-cache"); resp.setHeader("ETag", "W/\"" + response.length() + "-" + response.hashCode() + "\""); log.debug(response); out.write(response); } catch (GitAPIException e) { } } else { Ref head = repo.getRef(refName); if (head == null) { ArrayList<HashMap<String, String>> contents = new ArrayList<HashMap<String, String>>(); String response = JSONUtil.write(contents); resp.setContentType("application/json"); resp.setHeader("Cache-Control", "no-cache"); resp.setHeader("ETag", "W/\"" + response.length() + "-" + response.hashCode() + "\""); log.debug(response); out.write(response); return; } RevWalk walk = new RevWalk(repo); // add try catch to catch failures Git git = new Git(repo); RevCommit commit = walk.parseCommit(head.getObjectId()); RevTree tree = commit.getTree(); TreeWalk treeWalk = new TreeWalk(repo); treeWalk.addTree(tree); treeWalk.setRecursive(false); if (!filePath.equals("")) { PathFilter pathFilter = PathFilter.create(filePath); treeWalk.setFilter(pathFilter); } if (!treeWalk.next()) { CanonicalTreeParser canonicalTreeParser = treeWalk.getTree(0, CanonicalTreeParser.class); ArrayList<HashMap<String, Object>> contents = new ArrayList<HashMap<String, Object>>(); if (canonicalTreeParser != null) { while (!canonicalTreeParser.eof()) { String path = canonicalTreeParser.getEntryPathString(); FileMode mode = canonicalTreeParser.getEntryFileMode(); listEntry(path, mode.equals(FileMode.TREE) ? "dir" : "file", "0", path, projectName, head.getName(), git, contents); canonicalTreeParser.next(); } } String response = JSONUtil.write(contents); resp.setContentType("application/json"); resp.setHeader("Cache-Control", "no-cache"); resp.setHeader("ETag", "\"" + tree.getId().getName() + "\""); log.debug(response); out.write(response); } else { // if (treeWalk.isSubtree()) { // treeWalk.enterSubtree(); // } ArrayList<HashMap<String, Object>> contents = new ArrayList<HashMap<String, Object>>(); do { if (treeWalk.isSubtree()) { String test = new String(treeWalk.getRawPath()); if (test.length() /*treeWalk.getPathLength()*/ > filePath.length()) { listEntry(treeWalk.getNameString(), "dir", "0", treeWalk.getPathString(), projectName, head.getName(), git, contents); } if (test.length() /*treeWalk.getPathLength()*/ <= filePath.length()) { treeWalk.enterSubtree(); } } else { ObjectId objId = treeWalk.getObjectId(0); ObjectLoader loader = repo.open(objId); long size = loader.getSize(); listEntry(treeWalk.getNameString(), "file", Long.toString(size), treeWalk.getPathString(), projectName, head.getName(), git, contents); } } while (treeWalk.next()); String response = JSONUtil.write(contents); resp.setContentType("application/json"); resp.setHeader("Cache-Control", "no-cache"); resp.setHeader("ETag", "\"" + tree.getId().getName() + "\""); log.debug(response); out.write(response); } walk.release(); treeWalk.release(); } } } finally { out.close(); } } private void listEntry(String name, String type, String size, String path, String projectName, String ref, Git git, ArrayList<HashMap<String, Object>> contents) { HashMap<String, Object> jsonObject = new HashMap<String, Object>(); jsonObject.put("name", name); jsonObject.put("type", type); jsonObject.put("size", size); jsonObject.put("path", path); jsonObject.put("project", projectName); jsonObject.put("ref", ref); //if (type.equals("dir")) { lastCommit(git, path, null, jsonObject); //} contents.add(jsonObject); } private void lastCommit(Git git, String path, AnyObjectId revId, HashMap<String, Object> jsonObject) { HashMap<String, Object> latestCommitObj = new HashMap<String, Object>(); HashMap<String, String> authorObj = new HashMap<String, String>(); HashMap<String, String> committerObj = new HashMap<String, String>(); Iterable<RevCommit> log = null; try { if (path != null) { log = git.log().addPath(path).setMaxCount(1).call(); } else if (revId != null) { log = git.log().add(revId).setMaxCount(1).call(); } Iterator<RevCommit> it = log.iterator(); while (it.hasNext()) { RevCommit rev = (RevCommit) it.next(); PersonIdent committer = rev.getCommitterIdent(); committerObj.put("Name", committer.getName()); committerObj.put("Email", committer.getEmailAddress()); committerObj.put("Date", committer.getWhen().toString()); PersonIdent author = rev.getAuthorIdent(); authorObj.put("Name", author.getName()); String authorEmail = author.getEmailAddress(); authorObj.put("Email", authorEmail); authorObj.put("Date", author.getWhen().toString()); latestCommitObj.put("Author", authorObj); latestCommitObj.put("Committer", committerObj); latestCommitObj.put("Message", rev.getFullMessage()); latestCommitObj.put("SHA1", rev.getId().getName()); latestCommitObj.put("AvatarURL", getImageLink(authorEmail)); jsonObject.put("LastCommit", latestCommitObj); } } catch (GitAPIException e) { } catch (MissingObjectException e) { } catch (IncorrectObjectTypeException e) { } } private void handleAuth(HttpServletRequest req) { String username = req.getRemoteUser(); if (username != null) { if (config.getBoolean("auth", "userNameToLowerCase", false)) { username = username.toLowerCase(Locale.US); } log.debug("User name: " + username); AccountState who = accountCache.getByUsername(username); log.debug("AccountState " + who); if (who == null && username.matches("^([a-zA-Z0-9][a-zA-Z0-9._-]*[a-zA-Z0-9]|[a-zA-Z0-9])$")) { log.debug("User is not registered with Gerrit. Register now."); // This approach assumes an auth type of HTTP_LDAP final AuthRequest areq = AuthRequest.forUser(username); try { accountManager.authenticate(areq); who = accountCache.getByUsername(username); if (who == null) { log.warn("Unable to register user \"" + username + "\". Continue as anonymous."); } else { log.debug("User registered."); } } catch (AccountException e) { log.warn("Exception registering user \"" + username + "\". Continue as anonymous.", e); } } if (who != null && who.getAccount().isActive()) { log.debug("Not anonymous user"); WebSession ws = session.get(); ws.setUserAccountId(who.getAccount().getId()); ws.setAccessPathOk(AccessPath.REST_API, true); } else { log.debug("Anonymous user"); } } } public static String getImageLink(String emailAddress) { MessageDigest digest; try { digest = MessageDigest.getInstance("MD5"); //$NON-NLS-1$ } catch (NoSuchAlgorithmException e) { //without MD5 we can't compute gravatar hashes return null; } digest.update(emailAddress.trim().toLowerCase().getBytes()); byte[] digestValue = digest.digest(); StringBuffer result = new StringBuffer("https://www.gravatar.com/avatar/"); //$NON-NLS-1$ for (int i = 0; i < digestValue.length; i++) { String current = Integer.toHexString((digestValue[i] & 0xFF)); //left pad with zero if (current.length() == 1) result.append('0'); result.append(current); } //Default to "mystery man" icon if the user has no gravatar, and use a 40 pixel image result.append("?d=mm"); //$NON-NLS-1$ return result.toString(); } }