Package org.eclipse.orion.server.git.servlets

Source Code of org.eclipse.orion.server.git.servlets.GitTreeHandlerV1

/*******************************************************************************
* 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;
  }
}
TOP

Related Classes of org.eclipse.orion.server.git.servlets.GitTreeHandlerV1

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.