org.eclipse.orion.server.git.servlets.GitTreeHandlerV1.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.orion.server.git.servlets.GitTreeHandlerV1.java

Source

/*******************************************************************************
 * Copyright (c) 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.git.servlets;

import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.URIUtil;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.ListBranchCommand.ListMode;
import org.eclipse.jgit.errors.MissingObjectException;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectLoader;
import org.eclipse.jgit.lib.ObjectStream;
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.TreeWalk;
import org.eclipse.jgit.treewalk.filter.PathFilter;
import org.eclipse.orion.internal.server.servlets.ServletResourceHandler;
import org.eclipse.orion.server.core.IOUtilities;
import org.eclipse.orion.server.core.LogHelper;
import org.eclipse.orion.server.core.OrionConfiguration;
import org.eclipse.orion.server.core.ProtocolConstants;
import org.eclipse.orion.server.core.ServerStatus;
import org.eclipse.orion.server.core.metastore.ProjectInfo;
import org.eclipse.orion.server.core.metastore.UserInfo;
import org.eclipse.orion.server.core.metastore.WorkspaceInfo;
import org.eclipse.orion.server.git.servlets.GitUtils.Traverse;
import org.eclipse.orion.server.servlets.JsonURIUnqualificationStrategy;
import org.eclipse.orion.server.servlets.OrionServlet;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

public class GitTreeHandlerV1 extends AbstractGitHandler {

    GitTreeHandlerV1(ServletResourceHandler<IStatus> statusHandler) {
        super(statusHandler);
    }

    private JSONObject listEntry(String name, long timeStamp, boolean isDir, long length, URI location,
            String appendName) {
        JSONObject jsonObject = new JSONObject();
        try {
            jsonObject.put(ProtocolConstants.KEY_NAME, name);
            jsonObject.put(ProtocolConstants.KEY_LOCAL_TIMESTAMP, timeStamp);
            jsonObject.put(ProtocolConstants.KEY_DIRECTORY, isDir);
            jsonObject.put(ProtocolConstants.KEY_LENGTH, length);
            if (location != null) {
                if (isDir && !location.getPath().endsWith("/")) { //$NON-NLS-1$
                    location = URIUtil.append(location, ""); //$NON-NLS-1$
                }
                if (appendName != null) {
                    if (!appendName.startsWith("/") && !location.getPath().endsWith("/")) //$NON-NLS-1$  //$NON-NLS-2$
                        appendName = "/" + appendName; //$NON-NLS-1$
                    location = new URI(location.getScheme(), location.getAuthority(),
                            location.getPath() + appendName, null, location.getFragment());
                    if (isDir) {
                        location = URIUtil.append(location, ""); //$NON-NLS-1$
                    }
                }
                jsonObject.put(ProtocolConstants.KEY_LOCATION, location);
                if (isDir) {
                    try {
                        jsonObject.put(ProtocolConstants.KEY_CHILDREN_LOCATION, new URI(location.getScheme(),
                                location.getAuthority(), location.getPath(), "depth=1", location.getFragment())); //$NON-NLS-1$
                    } catch (URISyntaxException e) {
                        throw new RuntimeException(e);
                    }
                }
            }
            JSONObject attributes = new JSONObject();
            attributes.put("ReadOnly", true); //$NON-NLS-1$
            jsonObject.put(ProtocolConstants.KEY_ATTRIBUTES, attributes);

        } catch (JSONException e) {
        } catch (URISyntaxException e) {
            // cannot happen because the key is non-null and the values are strings
            throw new RuntimeException(e);
        }
        return jsonObject;
    }

    private boolean isAccessAllowed(String userName, ProjectInfo webProject) {
        try {
            UserInfo user = OrionConfiguration.getMetaStore().readUser(userName);
            for (String workspaceId : user.getWorkspaceIds()) {
                WorkspaceInfo workspace = OrionConfiguration.getMetaStore().readWorkspace(workspaceId);
                if (workspace != null && workspace.getProjectNames().contains(webProject.getFullName()))
                    return true;
            }
        } catch (Exception e) {
            // fall through and deny access
            LogHelper.log(e);
        }
        return false;
    }

    @Override
    public boolean handleRequest(HttpServletRequest request, HttpServletResponse response, String path)
            throws ServletException {
        String userId = request.getRemoteUser();
        if (path.length() == 0) {
            if (userId == null) {
                statusHandler.handleRequest(request, response, new ServerStatus(IStatus.ERROR,
                        HttpServletResponse.SC_FORBIDDEN, "User name not specified", null));
                return false;
            }
            try {
                UserInfo user = OrionConfiguration.getMetaStore().readUser(userId);
                List<String> workspaces = user.getWorkspaceIds();
                WorkspaceInfo workspace = OrionConfiguration.getMetaStore().readWorkspace(workspaces.get(0));
                URI baseLocation = getURI(request);
                URI baseLocationFile = URIUtil.append(baseLocation, "file"); //$NON-NLS-N$
                if (workspace != null) {
                    JSONArray children = new JSONArray();
                    for (String projectName : workspace.getProjectNames()) {
                        ProjectInfo project = OrionConfiguration.getMetaStore().readProject(workspace.getUniqueId(),
                                projectName);
                        if (isAccessAllowed(user.getUserName(), project)) {
                            IPath projectPath = GitUtils.pathFromProject(workspace, project);
                            Map<IPath, File> gitDirs = GitUtils.getGitDirs(projectPath, Traverse.GO_DOWN);
                            for (Map.Entry<IPath, File> entry : gitDirs.entrySet()) {
                                JSONObject repo = listEntry(entry.getKey().lastSegment(), 0, true, 0,
                                        baseLocationFile, entry.getKey().toPortableString());
                                children.put(repo);
                            }
                        }
                    }
                    JSONObject result = listEntry("/", 0, true, 0, baseLocation, null); //$NON-NLS-1$
                    result.put(ProtocolConstants.KEY_CHILDREN, children);
                    OrionServlet.writeJSONResponse(request, response, result,
                            JsonURIUnqualificationStrategy.ALL_NO_GIT);
                    return true;
                }
            } catch (Exception e) {
                return statusHandler.handleRequest(request, response,
                        new ServerStatus(IStatus.ERROR, HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
                                "An error occurred while obtaining workspace data.", e));
            }
            return true;
        }
        return super.handleRequest(request, response, path);
    }

    @Override
    protected boolean handleGet(RequestInfo requestInfo) throws ServletException {
        HttpServletRequest request = requestInfo.request;
        HttpServletResponse response = requestInfo.response;
        String gitSegment = requestInfo.gitSegment;
        Repository repo = requestInfo.db;
        String pattern = requestInfo.relativePath;
        IPath filePath = requestInfo.filePath;
        String meta = request.getParameter("parts"); //$NON-NLS-1$
        RevWalk walk = null;
        TreeWalk treeWalk = null;
        IPath filterPath = new Path(pattern);
        try {
            if (filterPath.segmentCount() == 0) {
                JSONArray children = new JSONArray();
                URI baseLocation = getURI(request);
                List<Ref> call = new Git(repo).branchList().setListMode(ListMode.ALL).call();
                for (Ref ref : call) {
                    String branchName = Repository.shortenRefName(ref.getName());
                    JSONObject branch = listEntry(branchName, 0, true, 0, baseLocation,
                            GitUtils.encode(branchName));
                    children.put(branch);
                }
                JSONObject result = listEntry(filePath.segment(0), 0, true, 0, baseLocation, null);
                result.put(ProtocolConstants.KEY_CHILDREN, children);
                OrionServlet.writeJSONResponse(request, response, result,
                        JsonURIUnqualificationStrategy.ALL_NO_GIT);
                return true;
            }

            gitSegment = GitUtils.decode(filterPath.segment(0));
            filterPath = filterPath.removeFirstSegments(1);
            pattern = filterPath.toPortableString();
            ObjectId head = repo.resolve(gitSegment);
            if (head == null) {
                throw new Exception("Missing ref in git segment");
            }
            walk = new RevWalk(repo);
            // add try catch to catch failures

            RevCommit commit = walk.parseCommit(head);
            RevTree tree = commit.getTree();
            treeWalk = new TreeWalk(repo);
            treeWalk.addTree(tree);
            treeWalk.setRecursive(false);
            if (!pattern.equals("")) { //$NON-NLS-1$
                PathFilter pathFilter = PathFilter.create(pattern);
                treeWalk.setFilter(pathFilter);
            }
            JSONArray contents = new JSONArray();
            JSONObject result = null;
            ArrayList<JSONObject> parents = new ArrayList<JSONObject>();

            URI baseLocation = ServletResourceHandler.getURI(request);
            Path basePath = new Path(baseLocation.getPath());
            IPath tmp = new Path("/"); //$NON-NLS-1$
            for (int i = 0; i < 5; i++) {
                tmp = tmp.append(basePath.segment(i));
            }
            URI cloneLocation = new URI(baseLocation.getScheme(), baseLocation.getAuthority(),
                    tmp.toPortableString(), null, baseLocation.getFragment());
            JSONObject ref = listEntry(gitSegment, 0, true, 0, cloneLocation, GitUtils.encode(gitSegment));

            parents.add(ref);
            parents.add(
                    listEntry(new Path(cloneLocation.getPath()).lastSegment(), 0, true, 0, cloneLocation, null));
            URI locationWalk = URIUtil.append(cloneLocation, GitUtils.encode(gitSegment));
            while (treeWalk.next()) {
                if (treeWalk.isSubtree()) {
                    if (treeWalk.getPathLength() > pattern.length()) {
                        String name = treeWalk.getNameString();
                        contents.put(listEntry(name, 0, true, 0, locationWalk, name));
                    }
                    if (treeWalk.getPathLength() <= pattern.length()) {
                        locationWalk = URIUtil.append(locationWalk, treeWalk.getNameString());
                        parents.add(0, listEntry(treeWalk.getNameString(), 0, true, 0, locationWalk, null));
                        treeWalk.enterSubtree();
                    }
                } else {
                    ObjectId objId = treeWalk.getObjectId(0);
                    ObjectLoader loader = repo.open(objId);
                    long size = loader.getSize();
                    if (treeWalk.getPathLength() == pattern.length()) {
                        if ("meta".equals(meta)) { //$NON-NLS-1$
                            result = listEntry(treeWalk.getNameString(), 0, false, 0, locationWalk,
                                    treeWalk.getNameString());
                        } else {
                            return getFileContents(request, response, repo, treeWalk, tree);
                        }
                    } else {
                        String name = treeWalk.getNameString();
                        contents.put(listEntry(name, 0, false, size, locationWalk, name));
                    }
                }
            }
            if (result == null) {
                result = parents.remove(0);
                result.put("Children", contents); //$NON-NLS-1$
            }
            result.put("Parents", new JSONArray(parents)); //$NON-NLS-1$
            response.setContentType("application/json"); //$NON-NLS-1$
            response.setHeader("Cache-Control", "no-cache"); //$NON-NLS-1$
            response.setHeader("ETag", "\"" + tree.getId().getName() + "\""); //$NON-NLS-1$
            OrionServlet.writeJSONResponse(request, response, result);
            return true;
        } catch (Exception e) {
            return statusHandler.handleRequest(request, response,
                    new ServerStatus(IStatus.ERROR, HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
                            "An error occured when requesting commit info.", e));
        } finally {
            if (walk != null)
                walk.release();
            if (treeWalk != null)
                treeWalk.release();
        }
    }

    private boolean getFileContents(HttpServletRequest request, HttpServletResponse response, Repository repo,
            TreeWalk treeWalk, RevTree tree) {
        ObjectStream stream = null;
        try {
            ObjectId objId = treeWalk.getObjectId(0);
            ObjectLoader loader = repo.open(objId);
            response.setHeader("Cache-Control", "no-cache"); //$NON-NLS-1$
            response.setHeader("ETag", "\"" + tree.getId().getName() + "\""); //$NON-NLS-1$ //$NON-NLS-2$
            response.setContentType("application/octet-stream"); //$NON-NLS-1$
            stream = loader.openStream();
            IOUtilities.pipe(stream, response.getOutputStream(), true, false);
        } catch (MissingObjectException e) {
        } catch (IOException e) {
        } finally {
            try {
                if (stream != null)
                    stream.close();
            } catch (IOException e) {
            }
        }
        return true;
    }
}