PageRenderTime 53ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/src/main/java/com/atlassian/jira/plugins/bitbucket/spi/bitbucket/impl/BitbucketCommunicator.java

https://bitbucket.org/atlassian/jira-bitbucket-connector/
Java | 253 lines | 220 code | 26 blank | 7 comment | 17 complexity | 0f7b24b73bc0a984eeb1f9fce6cc404a MD5 | raw file
  1. package com.atlassian.jira.plugins.bitbucket.spi.bitbucket.impl;
  2. import com.atlassian.jira.plugins.bitbucket.api.Authentication;
  3. import com.atlassian.jira.plugins.bitbucket.api.AuthenticationFactory;
  4. import com.atlassian.jira.plugins.bitbucket.api.Changeset;
  5. import com.atlassian.jira.plugins.bitbucket.api.SourceControlException;
  6. import com.atlassian.jira.plugins.bitbucket.api.SourceControlException.UnauthorisedException;
  7. import com.atlassian.jira.plugins.bitbucket.api.SourceControlRepository;
  8. import com.atlassian.jira.plugins.bitbucket.api.SourceControlUser;
  9. import com.atlassian.jira.plugins.bitbucket.api.impl.BasicAuthentication;
  10. import com.atlassian.jira.plugins.bitbucket.spi.Communicator;
  11. import com.atlassian.jira.plugins.bitbucket.spi.CustomStringUtils;
  12. import com.atlassian.jira.plugins.bitbucket.spi.ExtendedResponseHandler.ExtendedResponse;
  13. import com.atlassian.jira.plugins.bitbucket.spi.RepositoryUri;
  14. import com.atlassian.jira.plugins.bitbucket.spi.RequestHelper;
  15. import com.atlassian.jira.plugins.bitbucket.spi.UrlInfo;
  16. import com.atlassian.jira.plugins.bitbucket.spi.bitbucket.BitbucketChangesetFactory;
  17. import com.atlassian.jira.plugins.bitbucket.spi.bitbucket.BitbucketUserFactory;
  18. import com.atlassian.jira.util.json.JSONArray;
  19. import com.atlassian.jira.util.json.JSONException;
  20. import com.atlassian.jira.util.json.JSONObject;
  21. import com.atlassian.sal.api.net.ResponseException;
  22. import org.apache.commons.httpclient.HttpStatus;
  23. import org.apache.commons.lang.StringUtils;
  24. import org.slf4j.Logger;
  25. import org.slf4j.LoggerFactory;
  26. import java.util.ArrayList;
  27. import java.util.Collections;
  28. import java.util.HashMap;
  29. import java.util.Iterator;
  30. import java.util.List;
  31. import java.util.Map;
  32. /**
  33. * Starting point for remote API calls to the bitbucket remote API
  34. */
  35. public class BitbucketCommunicator implements Communicator
  36. {
  37. private final Logger logger = LoggerFactory.getLogger(BitbucketCommunicator.class);
  38. private final AuthenticationFactory authenticationFactory;
  39. private final RequestHelper requestHelper;
  40. public BitbucketCommunicator(AuthenticationFactory authenticationFactory, RequestHelper requestHelper)
  41. {
  42. this.authenticationFactory = authenticationFactory;
  43. this.requestHelper = requestHelper;
  44. }
  45. @Override
  46. public SourceControlUser getUser(SourceControlRepository repository, String username)
  47. {
  48. try
  49. {
  50. RepositoryUri uri = repository.getRepositoryUri();
  51. logger.debug("parse user [ {} ]", username);
  52. String responseString = requestHelper.get(Authentication.ANONYMOUS, "/users/" + CustomStringUtils.encode(username), null, uri.getApiUrl());
  53. return BitbucketUserFactory.parse(new JSONObject(responseString).getJSONObject("user"));
  54. } catch (ResponseException e)
  55. {
  56. // TODO: Start with capital letter
  57. logger.debug("could not load user [ " + username + " ]");
  58. return SourceControlUser.UNKNOWN_USER;
  59. } catch (JSONException e)
  60. {
  61. logger.debug("could not load user [ " + username + " ]");
  62. return SourceControlUser.UNKNOWN_USER;
  63. }
  64. }
  65. @Override
  66. public Changeset getChangeset(SourceControlRepository repository, String node)
  67. {
  68. try
  69. {
  70. RepositoryUri uri = repository.getRepositoryUri();
  71. String owner = uri.getOwner();
  72. String slug = uri.getSlug();
  73. Authentication auth = authenticationFactory.getAuthentication(repository);
  74. logger.debug("parse changeset [ {} ] [ {} ] [ {} ]", new String[]{owner, slug, node});
  75. final String urlPath = "/repositories/" + CustomStringUtils.encode(owner) + "/" +
  76. CustomStringUtils.encode(slug) + "/changesets/" + CustomStringUtils.encode(node);
  77. String responseString = requestHelper.get(auth, urlPath, null, uri.getApiUrl());
  78. String responseFilesString = requestHelper.get(auth, urlPath + "/diffstat", null, uri.getApiUrl());
  79. return BitbucketChangesetFactory.parse(repository.getId(), new JSONObject(responseString), new JSONArray(responseFilesString));
  80. } catch (ResponseException e)
  81. {
  82. throw new SourceControlException("could not get result", e);
  83. } catch (JSONException e)
  84. {
  85. throw new SourceControlException("Could not parse json result", e);
  86. }
  87. }
  88. public List<Changeset> getChangesets(final SourceControlRepository repository, String startNode, int limit)
  89. {
  90. RepositoryUri uri = repository.getRepositoryUri();
  91. String owner = uri.getOwner();
  92. String slug = uri.getSlug();
  93. Authentication auth = authenticationFactory.getAuthentication(repository);
  94. logger.debug("parse bitbucket changesets [ {} ] [ {} ] [ {} ] [ {} ]", new String[]{owner, slug, startNode, String.valueOf(limit)});
  95. Map<String, Object> params = new HashMap<String, Object>();
  96. params.put("limit", String.valueOf(limit));
  97. if (startNode != null)
  98. {
  99. params.put("start", startNode);
  100. }
  101. List<Changeset> changesets = new ArrayList<Changeset>();
  102. try
  103. {
  104. ExtendedResponse extendedResponse = requestHelper.getExtendedResponse(auth, "/repositories/" + CustomStringUtils.encode(owner)
  105. + "/" + CustomStringUtils.encode(slug) + "/changesets", params, uri.getApiUrl());
  106. if (extendedResponse.getStatusCode() == HttpStatus.SC_UNAUTHORIZED)
  107. {
  108. throw new SourceControlException("Incorrect credentials");
  109. } else if (extendedResponse.getStatusCode() == HttpStatus.SC_NOT_FOUND)
  110. {
  111. // no more changesets
  112. return Collections.emptyList();
  113. }
  114. JSONArray list = new JSONObject(extendedResponse.getResponseString()).getJSONArray("changesets");
  115. for (int i = 0; i < list.length(); i++)
  116. {
  117. JSONObject json = list.getJSONObject(i);
  118. final String urlPath = "/repositories/" + CustomStringUtils.encode(owner) + "/" +
  119. CustomStringUtils.encode(slug) + "/changesets/" + CustomStringUtils.encode(json.getString("node"));
  120. String responseFilesString = requestHelper.getExtendedResponse(auth, urlPath + "/diffstat", null, uri.getApiUrl()).getResponseString();
  121. changesets.add(BitbucketChangesetFactory.parse(repository.getId(), json, new JSONArray(responseFilesString)));
  122. }
  123. } catch (ResponseException e)
  124. {
  125. logger.warn("Could not get changesets from node: {}", startNode);
  126. throw new SourceControlException("Error requesting changesets. Node: " + startNode + ". [" + e.getMessage() + "]", e);
  127. } catch (JSONException e)
  128. {
  129. throw new SourceControlException("Could not parse json object", e);
  130. }
  131. return changesets;
  132. }
  133. @Override
  134. public void setupPostcommitHook(SourceControlRepository repo, String postCommitUrl)
  135. {
  136. RepositoryUri uri = repo.getRepositoryUri();
  137. Authentication auth = new BasicAuthentication(repo.getAdminUsername(), repo.getAdminPassword());
  138. String urlPath = "/repositories/" + uri.getOwner() + "/" + uri.getSlug() + "/services";
  139. String apiUrl = uri.getApiUrl();
  140. String postData = "type=post;URL=" + postCommitUrl;
  141. try
  142. {
  143. requestHelper.post(auth, urlPath, postData, apiUrl);
  144. } catch (ResponseException e)
  145. {
  146. throw new SourceControlException("Could not add postcommit hook", e);
  147. }
  148. }
  149. @Override
  150. public void removePostcommitHook(SourceControlRepository repo, String postCommitUrl)
  151. {
  152. RepositoryUri uri = repo.getRepositoryUri();
  153. Authentication auth = new BasicAuthentication(repo.getAdminUsername(), repo.getAdminPassword());
  154. String urlPath = "/repositories/" + uri.getOwner() + "/" + uri.getSlug() + "/services";
  155. String apiUrl = uri.getApiUrl();
  156. // Find the hook
  157. try
  158. {
  159. String responseString = requestHelper.get(auth, urlPath, null, apiUrl);
  160. JSONArray jsonArray = new JSONArray(responseString);
  161. for (int i = 0; i < jsonArray.length(); i++)
  162. {
  163. JSONObject data = (JSONObject) jsonArray.get(i);
  164. String id = data.getString("id");
  165. JSONObject service = data.getJSONObject("service");
  166. JSONArray fields = service.getJSONArray("fields");
  167. JSONObject fieldData = (JSONObject) fields.get(0);
  168. String name = fieldData.getString("name");
  169. String value = fieldData.getString("value");
  170. if ("URL".equals(name) && postCommitUrl.equals(value))
  171. {
  172. // We have the hook, lets remove it
  173. requestHelper.delete(auth, apiUrl, urlPath + "/" + id);
  174. }
  175. }
  176. } catch (ResponseException e)
  177. {
  178. logger.warn("Error removing postcommit service [{}]", e.getMessage());
  179. } catch (JSONException e)
  180. {
  181. logger.warn("Error removing postcommit service [{}]", e.getMessage());
  182. }
  183. }
  184. @Override
  185. public Iterable<Changeset> getChangesets(final SourceControlRepository repository)
  186. {
  187. return new Iterable<Changeset>()
  188. {
  189. @Override
  190. public Iterator<Changeset> iterator()
  191. {
  192. return new BitbucketChangesetIterator(BitbucketCommunicator.this, repository);
  193. }
  194. };
  195. }
  196. @Override
  197. public UrlInfo getUrlInfo(final RepositoryUri repositoryUri)
  198. {
  199. logger.debug("get repository info in bitbucket [ {} ]", repositoryUri.getRepositoryUrl());
  200. Boolean repositoryPrivate = requestHelper.isRepositoryPrivate1(repositoryUri);
  201. if (repositoryPrivate == null) return null;
  202. return new UrlInfo(BitbucketRepositoryManager.BITBUCKET, repositoryPrivate.booleanValue());
  203. }
  204. @Override
  205. public void validateRepositoryAccess(String repositoryType, String projectKey, RepositoryUri repositoryUri, String username, String password,
  206. String adminUsername, String adminPassword, String accessToken) throws SourceControlException
  207. {
  208. Authentication auth;
  209. if (StringUtils.isNotBlank(username) && StringUtils.isNotBlank(password))
  210. {
  211. auth = new BasicAuthentication(username, password);
  212. } else
  213. {
  214. auth = Authentication.ANONYMOUS;
  215. }
  216. try
  217. {
  218. ExtendedResponse extendedResponse = requestHelper.getExtendedResponse(auth, repositoryUri.getRepositoryInfoUrl(), null, repositoryUri.getApiUrl());
  219. if (extendedResponse.getStatusCode() == HttpStatus.SC_UNAUTHORIZED)
  220. throw new UnauthorisedException("Invalid credentials");
  221. } catch (ResponseException e)
  222. {
  223. logger.debug(e.getMessage(), e);
  224. throw new SourceControlException(e.getMessage());
  225. }
  226. }
  227. }