You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@manifoldcf.apache.org by kw...@apache.org on 2015/11/29 12:29:48 UTC

svn commit: r1717034 - /manifoldcf/trunk/connectors/confluence/connector/src/main/java/org/apache/manifoldcf/crawler/connectors/confluence/client/ConfluenceClient.java

Author: kwright
Date: Sun Nov 29 11:29:48 2015
New Revision: 1717034

URL: http://svn.apache.org/viewvc?rev=1717034&view=rev
Log:
Reformat to meet MCF standards

Modified:
    manifoldcf/trunk/connectors/confluence/connector/src/main/java/org/apache/manifoldcf/crawler/connectors/confluence/client/ConfluenceClient.java

Modified: manifoldcf/trunk/connectors/confluence/connector/src/main/java/org/apache/manifoldcf/crawler/connectors/confluence/client/ConfluenceClient.java
URL: http://svn.apache.org/viewvc/manifoldcf/trunk/connectors/confluence/connector/src/main/java/org/apache/manifoldcf/crawler/connectors/confluence/client/ConfluenceClient.java?rev=1717034&r1=1717033&r2=1717034&view=diff
==============================================================================
--- manifoldcf/trunk/connectors/confluence/connector/src/main/java/org/apache/manifoldcf/crawler/connectors/confluence/client/ConfluenceClient.java (original)
+++ manifoldcf/trunk/connectors/confluence/connector/src/main/java/org/apache/manifoldcf/crawler/connectors/confluence/client/ConfluenceClient.java Sun Nov 29 11:29:48 2015
@@ -69,649 +69,649 @@ import com.google.common.collect.Lists;
  */
 public class ConfluenceClient {
 
-	private static final String VIEW_PERMISSION = "view";
-	
-	private static final String CONTENT_PATH = "/rest/api/content";
-	private static final String AUTHORITY_PATH = "/rpc/json-rpc/confluenceservice-v2/";
-	private static final String EXPANDABLE_PARAMETERS = "expand=body.view,metadata.labels,space,history,version";
-	private static final String CHILD_ATTACHMENTS_PATH = "/child/attachment/";
-	private static final String LABEL_PATH = "/label";
-
-	private Logger logger = LoggerFactory.getLogger(ConfluenceClient.class);
-
-	private String protocol;
-	private Integer port;
-	private String host;
-	private String path;
-	private String username;
-	private String password;
-
-	private CloseableHttpClient httpClient;
-	private HttpClientContext httpContext;
-
-	/**
-	 * <p>Creates a new client instance using the given parameters</p>
-	 * @param protocol the protocol
-	 * @param host the host
-	 * @param port the port
-	 * @param path the path to Confluence instance
-	 * @param username the username used to make the requests. Null or empty to use anonymous user
-	 * @param password the password
-	 * @throws ManifoldCFException 
-	 */
-	public ConfluenceClient(String protocol, String host, Integer port,
-			String path, String username, String password) throws ManifoldCFException {
-		this.protocol = protocol;
-		this.host = host;
-		this.port = port;
-		this.path = path;
-		this.username = username;
-		this.password = password;
-
-		connect();
-	}
-
-	/**
-	 * <p>Connect methods used to initialize the underlying client</p>
-	 * @throws ManifoldCFException 
-	 */
-	private void connect() throws ManifoldCFException {
-
-		int socketTimeout = 900000;
-	    int connectionTimeout = 60000;
-
-	    javax.net.ssl.SSLSocketFactory httpsSocketFactory = KeystoreManagerFactory.getTrustingSecureSocketFactory();
-	    SSLConnectionSocketFactory myFactory = new SSLConnectionSocketFactory(new InterruptibleSocketFactory(httpsSocketFactory,connectionTimeout),
-	      NoopHostnameVerifier.INSTANCE);
-
-	    PoolingHttpClientConnectionManager poolingConnectionManager = new PoolingHttpClientConnectionManager(RegistryBuilder.<ConnectionSocketFactory>create()
-	        .register("http", PlainConnectionSocketFactory.getSocketFactory())
-	        .register("https", myFactory)
-	        .build());
-	    poolingConnectionManager.setDefaultMaxPerRoute(1);
-	    poolingConnectionManager.setValidateAfterInactivity(60000);
-	    poolingConnectionManager.setDefaultSocketConfig(SocketConfig.custom()
-	      .setTcpNoDelay(true)
-	      .setSoTimeout(socketTimeout)
-	      .build());
-
-
-	    RequestConfig.Builder requestBuilder = RequestConfig.custom()
-	      .setCircularRedirectsAllowed(true)
-	      .setSocketTimeout(socketTimeout)
-	      .setExpectContinueEnabled(true)
-	      .setConnectTimeout(connectionTimeout)
-	      .setConnectionRequestTimeout(socketTimeout);
-
-
-	    httpClient = HttpClients.custom()
-	      .setConnectionManager(poolingConnectionManager)
-	      .disableAutomaticRetries()
-	      .setDefaultRequestConfig(requestBuilder.build())
-	      .setRequestExecutor(new HttpRequestExecutor(socketTimeout))
-	      .setRedirectStrategy(new DefaultRedirectStrategy())
-	      .build();
-	    
-	   }
-
-	/**
-	 * <p>Close the client. No further requests can be done</p>
-	 */
-	public void close() {
-		if (httpClient != null) {
-			try {
-				httpClient.close();
-			} catch (IOException e) {
-				logger.debug("Error closing http connection. Reason: {}",
-						e.getMessage());
-				e.printStackTrace();
-			}
-		}
-	}
-
-	/**
-	 * <p>Check method used to test if Confluence instance is up and running</p>
-	 * 
-	 * @return a {@code Boolean} indicating whether the Confluence instance is alive or not
-	 * 
-	 * @throws Exception
-	 */
-	public boolean check() throws Exception {
-		HttpResponse response;
-		try {
-			if (httpClient == null) {
-				connect();
-			}
-
-			String url = String.format("%s://%s:%s/%s/%s?limit=1", protocol, host,
-					port, path, CONTENT_PATH);
-			logger.debug(
-					"[Processing] Hitting url: {} for confluence status check fetching : ",
-					"Confluence URL", sanitizeUrl(url));
-			HttpGet httpGet = createGetRequest(url);
-			response = httpClient.execute(httpGet);
-			int statusCode = response.getStatusLine().getStatusCode();
-			if (statusCode != 200)
-				throw new Exception(
-						"[Checking connection] Confluence server appears to be down");
-			else
-				return true;
-		} catch (IOException e) {
-			logger.warn(
-					"[Checking connection] Confluence server appears to be down",
-					e);
-			throw new Exception("Confluence appears to be down", e);
-		}
-	}
-
-	/**
-	 * <p>Check method used to test if Confluence instance is up and running when using Authority connector (JSON-RPC API)</p>
-	 * <p>This method will be deleted when all JSON-RPC methods are available through the REST API
-	 * 
-	 * @return a {@code Boolean} indicating whether the Confluence instance is alive or not
-	 * 
-	 * @throws Exception
-	 */
-	public boolean checkAuth() throws Exception {
-		try {
-			if (httpClient == null) {
-				connect();
-			}
-			getSpaces();
-			return true;
-		} catch (Exception e) {
-			logger.warn(
-					"[Checking connection] Confluence server appears to be down",
-					e);
-			throw e;
-		}
-	}
-	/**
-	 * <p>
-	 * Create a get request for the given url
-	 * </p>
-	 * 
-	 * @param url
-	 *            the url
-	 * @return the created {@code HttpGet} instance
-	 */
-	private HttpGet createGetRequest(String url) {
-		String finalUrl = useBasicAuthentication() ? url + "&os_authType=basic": url;
-		String sanitizedUrl = sanitizeUrl(finalUrl);
-		HttpGet httpGet = new HttpGet(sanitizedUrl);
-		httpGet.addHeader("Accept", "application/json");
-		if (useBasicAuthentication()) {
-			httpGet.addHeader(
-					"Authorization",
-					"Basic "
-							+ Base64.encodeBase64String(String.format("%s:%s",
-									this.username, this.password).getBytes(
-									Charset.forName("UTF-8"))));
-		}
-		return httpGet;
-	}
-
-	/**
-	 * <p>
-	 * Get a list of Confluence pages
-	 * </p>
-	 * 
-	 * @return a {@code ConfluenceResponse} containing the result pages and
-	 *         some pagination values
-	 * @throws Exception
-	 */
-	public ConfluenceResponse<Page> getPages() throws Exception {
-		return getPages(0, 50, Optional.<String> absent());
-	}
-
-	/**
-	 * <p>
-	 * Get a list of Confluence pages using pagination
-	 * </p>
-	 * 
-	 * @param start The start value to get pages from
-	 * @param limit The number of pages to get from start
-	 * @return a {@code ConfluenceResponse} containing the result pages and
-	 *         some pagination values
-	 * @throws Exception
-	 */
-	@SuppressWarnings("unchecked")
-	public ConfluenceResponse<Page> getPages(int start, int limit,
-			Optional<String> space) throws Exception {
-		String url = String.format("%s://%s:%s/%s/%s?limit=%s&start=%s", protocol,
-				host, port, path, CONTENT_PATH, limit, start);
-		if (space.isPresent()) {
-			url = String.format("%s&spaceKey=%s", url, space.get());
-		}
-		return (ConfluenceResponse<Page>) getConfluenceResources(url, Page.builder());
-	}
-
-	/**
-	 * <p>Get the {@code ConfluenceResources} from the given url</p>
-	 * @param url The url identifying the REST resource to get the documents
-	 * @param builder The builder used to build the resources contained in the response
-	 * @return a {@code ConfluenceResponse} containing the page results
-	 * @throws Exception
-	 */
-	private ConfluenceResponse<? extends ConfluenceResource> getConfluenceResources(String url, ConfluenceResourceBuilder<? extends ConfluenceResource> builder) throws Exception {
-		logger.debug("[Processing] Hitting url for get confluence resources: {}", sanitizeUrl(url));
-
-		try {
-			HttpGet httpGet = createGetRequest(url);
-			HttpResponse response = executeRequest(httpGet);
-			ConfluenceResponse<? extends ConfluenceResource> confluenceResponse = responseFromHttpEntity(response
-					.getEntity(), builder);
-			EntityUtils.consume(response.getEntity());
-			return confluenceResponse;
-		} catch (IOException e) {
-			logger.error("[Processing] Failed to get page(s)", e);
-			throw new Exception("Confluence appears to be down", e);
-		}
-	}
-
-	/**
-	 * <p>Creates a ConfluenceResponse from the entity returned in the HttpResponse</p>
-	 * @param entity the {@code HttpEntity} to extract the response from
-	 * @return a {@code ConfluenceResponse} with the requested information
-	 * @throws Exception
-	 */
-	private <T extends ConfluenceResource> ConfluenceResponse<T> responseFromHttpEntity(HttpEntity entity, ConfluenceResourceBuilder<T> builder)
-			throws Exception {
-		String stringEntity = EntityUtils.toString(entity);
-
-		JSONObject responseObject;
-		try {
-			responseObject = new JSONObject(stringEntity);
-			ConfluenceResponse<T> response = ConfluenceResponse
-					.fromJson(responseObject, builder);
-			if (response.getResults().size() == 0) {
-				logger.debug("[Processing] No {} found in the Confluence response", builder.getType().getSimpleName());
-			}
-
-			return response;
-		} catch (JSONException e) {
-			logger.debug("Error parsing JSON response");
-			throw new Exception();
-		}
-
-	}
-	
-	/**
-	 * <p>Get the attachments of the given page</p>
-	 * @param pageId the page id
-	 * @return a {@code ConfluenceResponse} instance containing the attachment results and some pagination values</p>
-	 * @throws Exception
-	 */
-	public ConfluenceResponse<Attachment> getPageAttachments(String pageId)
-			throws Exception {
-		return getPageAttachments(pageId, 0, 50);
-	}
-
-	/**
-	 * <p>Get the attachments of the given page using pagination</p>
-	 * @param pageId the page id
-	 * @param start The start value to get attachments from
-	 * @param limit The number of attachments to get from start
-	 * @return a {@code ConfluenceResponse} instance containing the attachment results and some pagination values</p>
-	 * @throws Exception
-	 */
-	public ConfluenceResponse<Attachment> getPageAttachments(String pageId, int start,
-			int limit) throws Exception {
-		String url = String.format("%s://%s:%s/%s/%s/%s%s?limit=%s&start=%s",
-				protocol, host, port, path, CONTENT_PATH, pageId, CHILD_ATTACHMENTS_PATH,
-				limit, start);
-		@SuppressWarnings("unchecked")
-		ConfluenceResponse<Attachment> confluenceResources = (ConfluenceResponse<Attachment>) getConfluenceResources(url, Attachment.builder());
-		return confluenceResources;
-	}
-	
-	/**
-	 * <p>
-	 * Gets a specific attachment contained in the specific page
-	 * </p>
-	 * 
-	 * @param attachmentId
-	 * @param pageId
-	 * @return the {@code Attachment} instance
-	 */
-	public Attachment getAttachment(String attachmentId) {
-		String url = String
-				.format("%s://%s:%s/%s/%s/%s?%s",
-						protocol, host, port, path, CONTENT_PATH, attachmentId, EXPANDABLE_PARAMETERS);
-		logger.debug(
-				"[Processing] Hitting url for getting document content : {}",
-				sanitizeUrl(url));
-		try {
-			HttpGet httpGet = createGetRequest(url);
-			HttpResponse response = executeRequest(httpGet);
-			HttpEntity entity = response.getEntity();
-			MutableAttachment attachment = attachmentFromHttpEntity(entity);
-			EntityUtils.consume(entity);
-			retrieveAndSetAttachmentContent(attachment);
-			return attachment;
-		} catch (Exception e) {
-			logger.error("[Processing] Failed to get attachment {}. Error: {}",
-					url, e.getMessage());
-		}
-
-		return new Attachment();
-	}
-
-	/**
-	 * <p>
-	 * Downloads and retrieves the attachment content, setting it in the given
-	 * {@code Attachment} instance
-	 * </p>
-	 * 
-	 * @param attachment
-	 *            the {@code Attachment} instance to download and set the
-	 *            content
-	 * @throws Exception
-	 */
-	private void retrieveAndSetAttachmentContent(MutableAttachment attachment)
-			throws Exception {
-		StringBuilder sb = new StringBuilder();
-		sb.append(attachment.getBaseUrl()).append(attachment.getUrlContext())
-				.append(attachment.getDownloadUrl());
-		String url = sanitizeUrl(sb.toString());
-		logger.debug(
-				"[Processing] Hitting url for getting attachment content : {}",
-				url);
-		try {
-			HttpGet httpGet = createGetRequest(url);
-			HttpResponse response = executeRequest(httpGet);
-			attachment.setLength(response.getEntity().getContentLength());
-			byte[] byteContent = IOUtils.toByteArray(response.getEntity()
-					.getContent());
-			EntityUtils.consumeQuietly(response.getEntity());
-			attachment.setContentStream(new ByteArrayInputStream(byteContent));
-		} catch (Exception e) {
-
-			logger.error(
-					"[Processing] Failed to get attachment content from {}. Error: {}",
-					url, e.getMessage());
-			throw e;
-		}
-
-	}
-
-
-	/**
-	 * <p>Get a Confluence page identified by its id</p>
-	 * @param pageId the page id
-	 * @return the Confluence page
-	 */
-	public Page getPage(String pageId) {
-		String url = String
-				.format("%s://%s:%s/%s/%s/%s?%s",
-						protocol, host, port, path, CONTENT_PATH, pageId, EXPANDABLE_PARAMETERS);
-		url = sanitizeUrl(url);
-		logger.debug(
-				"[Processing] Hitting url for getting document content : {}",
-				url);
-		try {
-			HttpGet httpGet = createGetRequest(url);
-			HttpResponse response = executeRequest(httpGet);
-			HttpEntity entity = response.getEntity();
-			MutablePage page = pageFromHttpEntity(entity);
-			EntityUtils.consume(entity);
-			List<Label> labels = getLabels(pageId);
-			page.setLabels(labels);
-			return page;
-		} catch (Exception e) {
-			logger.error("[Processing] Failed to get page {0}. Error: {1}",
-					url, e.getMessage());
-		}
-
-		return new Page();
-	}
-
-	/**
-	 * <p>Get the labels of a specific page</p> 
-	 * @param pageId The pageId to get the labels
-	 * @return a {@code List<Label>} of labels
-	 */
-	public List<Label> getLabels(String pageId) {
-				
-		List<Label> labels = Lists.newArrayList();
-		int lastStart = 0;
-		int limit = 50;
-		boolean isLast = false;
-		do {
-			String url = String
-					.format("%s://%s:%s/%s/%s/%s/%s?start=%s&limit=%s",
-							protocol, host, port, path, CONTENT_PATH, pageId, LABEL_PATH, lastStart, limit);
-			url = sanitizeUrl(url);
-			logger.debug(
-					"[Processing] Hitting url for getting page labels : {}",
-					url);
-			try {
-				@SuppressWarnings("unchecked")
-				ConfluenceResponse<Label> response = (ConfluenceResponse<Label>) getConfluenceResources(url, Label.builder());
-				labels.addAll(response.getResults());
-				lastStart += response.getResults().size();
-				isLast = response.isLast();
-			} catch (Exception e) {
-				logger.debug("Error getting labels for page {}. Reason: {}", pageId, e.getMessage());
-			}
-		}
-		while(!isLast);
-		
-		return labels;
-	}
-	
-	/**
-	 * 
-	 * @param username
-	 * @return
-	 * @throws Exception
-	 */
-	public ConfluenceUser getUserAuthorities(String username) throws Exception {
-		List<String> authorities = Lists.<String>newArrayList();
-		Spaces spaces = getSpaces();
-		for(Space space: spaces) {
-			List<String> permissions = getSpacePermissionsForUser(space, username);
-			if(permissions.contains(VIEW_PERMISSION)) {
-				authorities.add(space.getKey());
-			}
-		}
-		
-		return new ConfluenceUser(username, authorities);
-	
-	}
-	
-	private HttpPost createPostRequest(String url) {
-		HttpPost httpPost = new HttpPost(url);
-		httpPost.addHeader("Accept", "application/json");
-		httpPost.addHeader("Content-Type", "application/json");
-		if (useBasicAuthentication()) {
-			httpPost.addHeader(
-					"Authorization",
-					"Basic "
-							+ Base64.encodeBase64String(String.format("%s:%s",
-									this.username, this.password).getBytes(
-									Charset.forName("UTF-8"))));
-		}
-		return httpPost;
-	}
-	
-	/**
-	 * <p>Execute the given {@code HttpUriRequest} using the configured client</p> 
-	 * @param request the {@code HttpUriRequest} to be executed
-	 * @return the {@code HttpResponse} object returned from the server
-	 * @throws Exception
-	 */
-	private HttpResponse executeRequest(HttpUriRequest request)
-			throws Exception {
-		String url = request.getURI().toString();
-		logger.debug(
-				"[Processing] Hitting url for getting document content : {}",
-				url);
-
-		try {
-			HttpResponse response = httpClient.execute(request, httpContext);
-			if (response.getStatusLine().getStatusCode() != 200) {
-				throw new Exception("Confluence error. "
-						+ response.getStatusLine().getStatusCode() + " "
-						+ response.getStatusLine().getReasonPhrase());
-			}
-			return response;
-		} catch (Exception e) {
-			logger.error("[Processing] Failed to get page {}. Error: {}",
-					url, e.getMessage());
-			throw e;
-		}
-	}
-
-	/**
-	 * <p>Creates a Confluence page object from the given entity returned by the server</p>
-	 * @param entity the {@code HttpEntity} to create the {@code MutablePage} from
-	 * @return the Confluence page instance
-	 * @throws Exception
-	 */
-	private MutablePage pageFromHttpEntity(HttpEntity entity) throws Exception {
-		String stringEntity = EntityUtils.toString(entity);
-
-		JSONObject responseObject;
-		try {
-			responseObject = new JSONObject(stringEntity);
-			@SuppressWarnings("unchecked")
-			MutablePage response = ((ConfluenceResourceBuilder<MutablePage>)MutablePage.builder()).fromJson(responseObject, new MutablePage());
-			return response;
-		} catch (JSONException e) {
-			logger.debug("Error parsing JSON page response data");
-			throw new Exception("Error parsing JSON page response data");
-		}
-	}
-
-	/**
-	 * <p>Creates a {@code MutableAttachment} object from the given entity returned by the server</p>
-	 * @param entity the {@code HttpEntity} to create the {@code MutableAttachment} from
-	 * @return the Confluence MutableAttachment instance
-	 * @throws Exception
-	 */
-	private MutableAttachment attachmentFromHttpEntity(HttpEntity entity)
-			throws Exception {
-		String stringEntity = EntityUtils.toString(entity);
-		JSONObject responseObject;
-		try {
-			responseObject = new JSONObject(stringEntity);
-			MutableAttachment response = (MutableAttachment) Attachment
-					.builder()
-					.fromJson(responseObject, new MutableAttachment());
-			return response;
-		} catch (JSONException e) {
-			logger.debug("Error parsing JSON page response data");
-			throw new Exception("Error parsing JSON page response data");
-		}
-	}
-
-	/**
-	 * <p>Method to check if basic authentication must be used</p>
-	 * @return {@code Boolean} indicating whether basic authentication must be used or not
-	 */
-	private boolean useBasicAuthentication() {
-		return this.username != null && !"".equals(username)
-				&& this.password != null;
-	}
-
-	/**
-	 * <p>
-	 * Sanitize the given url replacing the appearance of more than one slash by
-	 * only one slash
-	 * </p>
-	 * 
-	 * @param url
-	 *            The url to sanitize
-	 * @return the sanitized url
-	 */
-	private String sanitizeUrl(String url) {
-		int colonIndex = url.indexOf(":");
-		String urlWithoutProtocol = url.startsWith("http") ? url.substring(colonIndex+3) : url;
-		String sanitizedUrl = urlWithoutProtocol.replaceAll("\\/+", "/");
-		return url.substring(0,colonIndex) + "://" + sanitizedUrl;
-	}
-	
-	private Spaces getSpaces() throws Exception {
-		String url = String.format("%s://%s:%s%s%sgetSpaces", protocol, host,
-				port, path, AUTHORITY_PATH);
-
-		logger.debug(
-				"[Processing] Hitting url for getting Confluence spaces : {}",
-				url);
-
-		HttpPost httpPost = createPostRequest(url);
-		httpPost.setEntity(new StringEntity("[]"));
-		HttpResponse response = httpClient.execute(httpPost);
-		if (response.getStatusLine().getStatusCode() != 200) {
-			throw new ConfluenceException("Confluence error. "
-					+ response.getStatusLine().getStatusCode() + " "
-					+ response.getStatusLine().getReasonPhrase());
-		}
-		HttpEntity entity = response.getEntity();
-		Spaces spaces = spacesFromHttpEntity(entity);
-		EntityUtils.consume(entity);
-		return spaces;
-	}
-	
-	private List<String> getSpacePermissionsForUser(Space space, String username) throws Exception {
-		String url = String.format("%s://%s:%s%s%sgetPermissionsForUser", protocol, host,
-				port, path, AUTHORITY_PATH);
-
-		logger.debug(
-				"[Processing] Hitting url {} for getting Confluence permissions for user {} in space {}",
-				url, username, space.getKey());
-
-		HttpPost httpPost = createPostRequest(url);
-		JSONArray jsonArray = new JSONArray();
-		jsonArray.put(space.getKey());
-		jsonArray.put(username);
-		StringEntity stringEntity = new StringEntity(jsonArray.toString());
-		httpPost.setEntity(stringEntity);
-		HttpResponse response = httpClient.execute(httpPost);
-		if (response.getStatusLine().getStatusCode() != 200) {
-			throw new ConfluenceException("Confluence error. "
-					+ response.getStatusLine().getStatusCode() + " "
-					+ response.getStatusLine().getReasonPhrase());
-		}
-		HttpEntity entity = response.getEntity();
-		List<String> permissions = permissionsFromHttpEntity(entity);
-		EntityUtils.consume(entity);
-		return permissions;
-	}
-
-	private Spaces spacesFromHttpEntity(HttpEntity entity) throws Exception {
-		String stringEntity = EntityUtils.toString(entity);
-
-		JSONArray responseObject;
-		try {
-			responseObject = new JSONArray(stringEntity);
-			Spaces response = Spaces.fromJson(responseObject);
-
-			return response;
-		} catch (JSONException e) {
-			logger.debug("Error parsing JSON spaces response data");
-			throw new Exception("Error parsing JSON spaces response data");
-		}
-
-	}
-	
-	private List<String> permissionsFromHttpEntity(HttpEntity entity) throws Exception {
-		String stringEntity = EntityUtils.toString(entity);
-
-		JSONArray responseObject;
-		List<String> permissions = Lists.newArrayList();
-		try {
-			responseObject = new JSONArray(stringEntity);
-			for(int i=0,len=responseObject.length();i<len;i++) {
-				permissions.add(responseObject.getString(i));
-			}
-
-			return permissions;
-		} catch (JSONException e) {
-			logger.debug("Error parsing JSON space permissions response data");
-			throw new Exception("Error parsing JSON space permissions respnse data");
-		}
+  private static final String VIEW_PERMISSION = "view";
+  
+  private static final String CONTENT_PATH = "/rest/api/content";
+  private static final String AUTHORITY_PATH = "/rpc/json-rpc/confluenceservice-v2/";
+  private static final String EXPANDABLE_PARAMETERS = "expand=body.view,metadata.labels,space,history,version";
+  private static final String CHILD_ATTACHMENTS_PATH = "/child/attachment/";
+  private static final String LABEL_PATH = "/label";
+
+  private Logger logger = LoggerFactory.getLogger(ConfluenceClient.class);
+
+  private String protocol;
+  private Integer port;
+  private String host;
+  private String path;
+  private String username;
+  private String password;
+
+  private CloseableHttpClient httpClient;
+  private HttpClientContext httpContext;
+
+  /**
+   * <p>Creates a new client instance using the given parameters</p>
+   * @param protocol the protocol
+   * @param host the host
+   * @param port the port
+   * @param path the path to Confluence instance
+   * @param username the username used to make the requests. Null or empty to use anonymous user
+   * @param password the password
+   * @throws ManifoldCFException 
+   */
+  public ConfluenceClient(String protocol, String host, Integer port,
+      String path, String username, String password) throws ManifoldCFException {
+    this.protocol = protocol;
+    this.host = host;
+    this.port = port;
+    this.path = path;
+    this.username = username;
+    this.password = password;
+
+    connect();
+  }
+
+  /**
+   * <p>Connect methods used to initialize the underlying client</p>
+   * @throws ManifoldCFException 
+   */
+  private void connect() throws ManifoldCFException {
+
+    int socketTimeout = 900000;
+      int connectionTimeout = 60000;
+
+      javax.net.ssl.SSLSocketFactory httpsSocketFactory = KeystoreManagerFactory.getTrustingSecureSocketFactory();
+      SSLConnectionSocketFactory myFactory = new SSLConnectionSocketFactory(new InterruptibleSocketFactory(httpsSocketFactory,connectionTimeout),
+        NoopHostnameVerifier.INSTANCE);
+
+      PoolingHttpClientConnectionManager poolingConnectionManager = new PoolingHttpClientConnectionManager(RegistryBuilder.<ConnectionSocketFactory>create()
+          .register("http", PlainConnectionSocketFactory.getSocketFactory())
+          .register("https", myFactory)
+          .build());
+      poolingConnectionManager.setDefaultMaxPerRoute(1);
+      poolingConnectionManager.setValidateAfterInactivity(60000);
+      poolingConnectionManager.setDefaultSocketConfig(SocketConfig.custom()
+        .setTcpNoDelay(true)
+        .setSoTimeout(socketTimeout)
+        .build());
+
+
+      RequestConfig.Builder requestBuilder = RequestConfig.custom()
+        .setCircularRedirectsAllowed(true)
+        .setSocketTimeout(socketTimeout)
+        .setExpectContinueEnabled(true)
+        .setConnectTimeout(connectionTimeout)
+        .setConnectionRequestTimeout(socketTimeout);
+
+
+      httpClient = HttpClients.custom()
+        .setConnectionManager(poolingConnectionManager)
+        .disableAutomaticRetries()
+        .setDefaultRequestConfig(requestBuilder.build())
+        .setRequestExecutor(new HttpRequestExecutor(socketTimeout))
+        .setRedirectStrategy(new DefaultRedirectStrategy())
+        .build();
+      
+     }
+
+  /**
+   * <p>Close the client. No further requests can be done</p>
+   */
+  public void close() {
+    if (httpClient != null) {
+      try {
+        httpClient.close();
+      } catch (IOException e) {
+        logger.debug("Error closing http connection. Reason: {}",
+            e.getMessage());
+        e.printStackTrace();
+      }
+    }
+  }
+
+  /**
+   * <p>Check method used to test if Confluence instance is up and running</p>
+   * 
+   * @return a {@code Boolean} indicating whether the Confluence instance is alive or not
+   * 
+   * @throws Exception
+   */
+  public boolean check() throws Exception {
+    HttpResponse response;
+    try {
+      if (httpClient == null) {
+        connect();
+      }
+
+      String url = String.format("%s://%s:%s/%s/%s?limit=1", protocol, host,
+          port, path, CONTENT_PATH);
+      logger.debug(
+          "[Processing] Hitting url: {} for confluence status check fetching : ",
+          "Confluence URL", sanitizeUrl(url));
+      HttpGet httpGet = createGetRequest(url);
+      response = httpClient.execute(httpGet);
+      int statusCode = response.getStatusLine().getStatusCode();
+      if (statusCode != 200)
+        throw new Exception(
+            "[Checking connection] Confluence server appears to be down");
+      else
+        return true;
+    } catch (IOException e) {
+      logger.warn(
+          "[Checking connection] Confluence server appears to be down",
+          e);
+      throw new Exception("Confluence appears to be down", e);
+    }
+  }
+
+  /**
+   * <p>Check method used to test if Confluence instance is up and running when using Authority connector (JSON-RPC API)</p>
+   * <p>This method will be deleted when all JSON-RPC methods are available through the REST API
+   * 
+   * @return a {@code Boolean} indicating whether the Confluence instance is alive or not
+   * 
+   * @throws Exception
+   */
+  public boolean checkAuth() throws Exception {
+    try {
+      if (httpClient == null) {
+        connect();
+      }
+      getSpaces();
+      return true;
+    } catch (Exception e) {
+      logger.warn(
+          "[Checking connection] Confluence server appears to be down",
+          e);
+      throw e;
+    }
+  }
+  /**
+   * <p>
+   * Create a get request for the given url
+   * </p>
+   * 
+   * @param url
+   *            the url
+   * @return the created {@code HttpGet} instance
+   */
+  private HttpGet createGetRequest(String url) {
+    String finalUrl = useBasicAuthentication() ? url + "&os_authType=basic": url;
+    String sanitizedUrl = sanitizeUrl(finalUrl);
+    HttpGet httpGet = new HttpGet(sanitizedUrl);
+    httpGet.addHeader("Accept", "application/json");
+    if (useBasicAuthentication()) {
+      httpGet.addHeader(
+          "Authorization",
+          "Basic "
+              + Base64.encodeBase64String(String.format("%s:%s",
+                  this.username, this.password).getBytes(
+                  Charset.forName("UTF-8"))));
+    }
+    return httpGet;
+  }
+
+  /**
+   * <p>
+   * Get a list of Confluence pages
+   * </p>
+   * 
+   * @return a {@code ConfluenceResponse} containing the result pages and
+   *         some pagination values
+   * @throws Exception
+   */
+  public ConfluenceResponse<Page> getPages() throws Exception {
+    return getPages(0, 50, Optional.<String> absent());
+  }
+
+  /**
+   * <p>
+   * Get a list of Confluence pages using pagination
+   * </p>
+   * 
+   * @param start The start value to get pages from
+   * @param limit The number of pages to get from start
+   * @return a {@code ConfluenceResponse} containing the result pages and
+   *         some pagination values
+   * @throws Exception
+   */
+  @SuppressWarnings("unchecked")
+  public ConfluenceResponse<Page> getPages(int start, int limit,
+      Optional<String> space) throws Exception {
+    String url = String.format("%s://%s:%s/%s/%s?limit=%s&start=%s", protocol,
+        host, port, path, CONTENT_PATH, limit, start);
+    if (space.isPresent()) {
+      url = String.format("%s&spaceKey=%s", url, space.get());
+    }
+    return (ConfluenceResponse<Page>) getConfluenceResources(url, Page.builder());
+  }
+
+  /**
+   * <p>Get the {@code ConfluenceResources} from the given url</p>
+   * @param url The url identifying the REST resource to get the documents
+   * @param builder The builder used to build the resources contained in the response
+   * @return a {@code ConfluenceResponse} containing the page results
+   * @throws Exception
+   */
+  private ConfluenceResponse<? extends ConfluenceResource> getConfluenceResources(String url, ConfluenceResourceBuilder<? extends ConfluenceResource> builder) throws Exception {
+    logger.debug("[Processing] Hitting url for get confluence resources: {}", sanitizeUrl(url));
+
+    try {
+      HttpGet httpGet = createGetRequest(url);
+      HttpResponse response = executeRequest(httpGet);
+      ConfluenceResponse<? extends ConfluenceResource> confluenceResponse = responseFromHttpEntity(response
+          .getEntity(), builder);
+      EntityUtils.consume(response.getEntity());
+      return confluenceResponse;
+    } catch (IOException e) {
+      logger.error("[Processing] Failed to get page(s)", e);
+      throw new Exception("Confluence appears to be down", e);
+    }
+  }
+
+  /**
+   * <p>Creates a ConfluenceResponse from the entity returned in the HttpResponse</p>
+   * @param entity the {@code HttpEntity} to extract the response from
+   * @return a {@code ConfluenceResponse} with the requested information
+   * @throws Exception
+   */
+  private <T extends ConfluenceResource> ConfluenceResponse<T> responseFromHttpEntity(HttpEntity entity, ConfluenceResourceBuilder<T> builder)
+      throws Exception {
+    String stringEntity = EntityUtils.toString(entity);
+
+    JSONObject responseObject;
+    try {
+      responseObject = new JSONObject(stringEntity);
+      ConfluenceResponse<T> response = ConfluenceResponse
+          .fromJson(responseObject, builder);
+      if (response.getResults().size() == 0) {
+        logger.debug("[Processing] No {} found in the Confluence response", builder.getType().getSimpleName());
+      }
+
+      return response;
+    } catch (JSONException e) {
+      logger.debug("Error parsing JSON response");
+      throw new Exception();
+    }
+
+  }
+  
+  /**
+   * <p>Get the attachments of the given page</p>
+   * @param pageId the page id
+   * @return a {@code ConfluenceResponse} instance containing the attachment results and some pagination values</p>
+   * @throws Exception
+   */
+  public ConfluenceResponse<Attachment> getPageAttachments(String pageId)
+      throws Exception {
+    return getPageAttachments(pageId, 0, 50);
+  }
+
+  /**
+   * <p>Get the attachments of the given page using pagination</p>
+   * @param pageId the page id
+   * @param start The start value to get attachments from
+   * @param limit The number of attachments to get from start
+   * @return a {@code ConfluenceResponse} instance containing the attachment results and some pagination values</p>
+   * @throws Exception
+   */
+  public ConfluenceResponse<Attachment> getPageAttachments(String pageId, int start,
+      int limit) throws Exception {
+    String url = String.format("%s://%s:%s/%s/%s/%s%s?limit=%s&start=%s",
+        protocol, host, port, path, CONTENT_PATH, pageId, CHILD_ATTACHMENTS_PATH,
+        limit, start);
+    @SuppressWarnings("unchecked")
+    ConfluenceResponse<Attachment> confluenceResources = (ConfluenceResponse<Attachment>) getConfluenceResources(url, Attachment.builder());
+    return confluenceResources;
+  }
+  
+  /**
+   * <p>
+   * Gets a specific attachment contained in the specific page
+   * </p>
+   * 
+   * @param attachmentId
+   * @param pageId
+   * @return the {@code Attachment} instance
+   */
+  public Attachment getAttachment(String attachmentId) {
+    String url = String
+        .format("%s://%s:%s/%s/%s/%s?%s",
+            protocol, host, port, path, CONTENT_PATH, attachmentId, EXPANDABLE_PARAMETERS);
+    logger.debug(
+        "[Processing] Hitting url for getting document content : {}",
+        sanitizeUrl(url));
+    try {
+      HttpGet httpGet = createGetRequest(url);
+      HttpResponse response = executeRequest(httpGet);
+      HttpEntity entity = response.getEntity();
+      MutableAttachment attachment = attachmentFromHttpEntity(entity);
+      EntityUtils.consume(entity);
+      retrieveAndSetAttachmentContent(attachment);
+      return attachment;
+    } catch (Exception e) {
+      logger.error("[Processing] Failed to get attachment {}. Error: {}",
+          url, e.getMessage());
+    }
+
+    return new Attachment();
+  }
+
+  /**
+   * <p>
+   * Downloads and retrieves the attachment content, setting it in the given
+   * {@code Attachment} instance
+   * </p>
+   * 
+   * @param attachment
+   *            the {@code Attachment} instance to download and set the
+   *            content
+   * @throws Exception
+   */
+  private void retrieveAndSetAttachmentContent(MutableAttachment attachment)
+      throws Exception {
+    StringBuilder sb = new StringBuilder();
+    sb.append(attachment.getBaseUrl()).append(attachment.getUrlContext())
+        .append(attachment.getDownloadUrl());
+    String url = sanitizeUrl(sb.toString());
+    logger.debug(
+        "[Processing] Hitting url for getting attachment content : {}",
+        url);
+    try {
+      HttpGet httpGet = createGetRequest(url);
+      HttpResponse response = executeRequest(httpGet);
+      attachment.setLength(response.getEntity().getContentLength());
+      byte[] byteContent = IOUtils.toByteArray(response.getEntity()
+          .getContent());
+      EntityUtils.consumeQuietly(response.getEntity());
+      attachment.setContentStream(new ByteArrayInputStream(byteContent));
+    } catch (Exception e) {
+
+      logger.error(
+          "[Processing] Failed to get attachment content from {}. Error: {}",
+          url, e.getMessage());
+      throw e;
+    }
+
+  }
+
+
+  /**
+   * <p>Get a Confluence page identified by its id</p>
+   * @param pageId the page id
+   * @return the Confluence page
+   */
+  public Page getPage(String pageId) {
+    String url = String
+        .format("%s://%s:%s/%s/%s/%s?%s",
+            protocol, host, port, path, CONTENT_PATH, pageId, EXPANDABLE_PARAMETERS);
+    url = sanitizeUrl(url);
+    logger.debug(
+        "[Processing] Hitting url for getting document content : {}",
+        url);
+    try {
+      HttpGet httpGet = createGetRequest(url);
+      HttpResponse response = executeRequest(httpGet);
+      HttpEntity entity = response.getEntity();
+      MutablePage page = pageFromHttpEntity(entity);
+      EntityUtils.consume(entity);
+      List<Label> labels = getLabels(pageId);
+      page.setLabels(labels);
+      return page;
+    } catch (Exception e) {
+      logger.error("[Processing] Failed to get page {0}. Error: {1}",
+          url, e.getMessage());
+    }
+
+    return new Page();
+  }
+
+  /**
+   * <p>Get the labels of a specific page</p> 
+   * @param pageId The pageId to get the labels
+   * @return a {@code List<Label>} of labels
+   */
+  public List<Label> getLabels(String pageId) {
+        
+    List<Label> labels = Lists.newArrayList();
+    int lastStart = 0;
+    int limit = 50;
+    boolean isLast = false;
+    do {
+      String url = String
+          .format("%s://%s:%s/%s/%s/%s/%s?start=%s&limit=%s",
+              protocol, host, port, path, CONTENT_PATH, pageId, LABEL_PATH, lastStart, limit);
+      url = sanitizeUrl(url);
+      logger.debug(
+          "[Processing] Hitting url for getting page labels : {}",
+          url);
+      try {
+        @SuppressWarnings("unchecked")
+        ConfluenceResponse<Label> response = (ConfluenceResponse<Label>) getConfluenceResources(url, Label.builder());
+        labels.addAll(response.getResults());
+        lastStart += response.getResults().size();
+        isLast = response.isLast();
+      } catch (Exception e) {
+        logger.debug("Error getting labels for page {}. Reason: {}", pageId, e.getMessage());
+      }
+    }
+    while(!isLast);
+    
+    return labels;
+  }
+  
+  /**
+   * 
+   * @param username
+   * @return
+   * @throws Exception
+   */
+  public ConfluenceUser getUserAuthorities(String username) throws Exception {
+    List<String> authorities = Lists.<String>newArrayList();
+    Spaces spaces = getSpaces();
+    for(Space space: spaces) {
+      List<String> permissions = getSpacePermissionsForUser(space, username);
+      if(permissions.contains(VIEW_PERMISSION)) {
+        authorities.add(space.getKey());
+      }
+    }
+    
+    return new ConfluenceUser(username, authorities);
+  
+  }
+  
+  private HttpPost createPostRequest(String url) {
+    HttpPost httpPost = new HttpPost(url);
+    httpPost.addHeader("Accept", "application/json");
+    httpPost.addHeader("Content-Type", "application/json");
+    if (useBasicAuthentication()) {
+      httpPost.addHeader(
+          "Authorization",
+          "Basic "
+              + Base64.encodeBase64String(String.format("%s:%s",
+                  this.username, this.password).getBytes(
+                  Charset.forName("UTF-8"))));
+    }
+    return httpPost;
+  }
+  
+  /**
+   * <p>Execute the given {@code HttpUriRequest} using the configured client</p> 
+   * @param request the {@code HttpUriRequest} to be executed
+   * @return the {@code HttpResponse} object returned from the server
+   * @throws Exception
+   */
+  private HttpResponse executeRequest(HttpUriRequest request)
+      throws Exception {
+    String url = request.getURI().toString();
+    logger.debug(
+        "[Processing] Hitting url for getting document content : {}",
+        url);
+
+    try {
+      HttpResponse response = httpClient.execute(request, httpContext);
+      if (response.getStatusLine().getStatusCode() != 200) {
+        throw new Exception("Confluence error. "
+            + response.getStatusLine().getStatusCode() + " "
+            + response.getStatusLine().getReasonPhrase());
+      }
+      return response;
+    } catch (Exception e) {
+      logger.error("[Processing] Failed to get page {}. Error: {}",
+          url, e.getMessage());
+      throw e;
+    }
+  }
+
+  /**
+   * <p>Creates a Confluence page object from the given entity returned by the server</p>
+   * @param entity the {@code HttpEntity} to create the {@code MutablePage} from
+   * @return the Confluence page instance
+   * @throws Exception
+   */
+  private MutablePage pageFromHttpEntity(HttpEntity entity) throws Exception {
+    String stringEntity = EntityUtils.toString(entity);
+
+    JSONObject responseObject;
+    try {
+      responseObject = new JSONObject(stringEntity);
+      @SuppressWarnings("unchecked")
+      MutablePage response = ((ConfluenceResourceBuilder<MutablePage>)MutablePage.builder()).fromJson(responseObject, new MutablePage());
+      return response;
+    } catch (JSONException e) {
+      logger.debug("Error parsing JSON page response data");
+      throw new Exception("Error parsing JSON page response data");
+    }
+  }
+
+  /**
+   * <p>Creates a {@code MutableAttachment} object from the given entity returned by the server</p>
+   * @param entity the {@code HttpEntity} to create the {@code MutableAttachment} from
+   * @return the Confluence MutableAttachment instance
+   * @throws Exception
+   */
+  private MutableAttachment attachmentFromHttpEntity(HttpEntity entity)
+      throws Exception {
+    String stringEntity = EntityUtils.toString(entity);
+    JSONObject responseObject;
+    try {
+      responseObject = new JSONObject(stringEntity);
+      MutableAttachment response = (MutableAttachment) Attachment
+          .builder()
+          .fromJson(responseObject, new MutableAttachment());
+      return response;
+    } catch (JSONException e) {
+      logger.debug("Error parsing JSON page response data");
+      throw new Exception("Error parsing JSON page response data");
+    }
+  }
+
+  /**
+   * <p>Method to check if basic authentication must be used</p>
+   * @return {@code Boolean} indicating whether basic authentication must be used or not
+   */
+  private boolean useBasicAuthentication() {
+    return this.username != null && !"".equals(username)
+        && this.password != null;
+  }
+
+  /**
+   * <p>
+   * Sanitize the given url replacing the appearance of more than one slash by
+   * only one slash
+   * </p>
+   * 
+   * @param url
+   *            The url to sanitize
+   * @return the sanitized url
+   */
+  private String sanitizeUrl(String url) {
+    int colonIndex = url.indexOf(":");
+    String urlWithoutProtocol = url.startsWith("http") ? url.substring(colonIndex+3) : url;
+    String sanitizedUrl = urlWithoutProtocol.replaceAll("\\/+", "/");
+    return url.substring(0,colonIndex) + "://" + sanitizedUrl;
+  }
+  
+  private Spaces getSpaces() throws Exception {
+    String url = String.format("%s://%s:%s%s%sgetSpaces", protocol, host,
+        port, path, AUTHORITY_PATH);
+
+    logger.debug(
+        "[Processing] Hitting url for getting Confluence spaces : {}",
+        url);
+
+    HttpPost httpPost = createPostRequest(url);
+    httpPost.setEntity(new StringEntity("[]"));
+    HttpResponse response = httpClient.execute(httpPost);
+    if (response.getStatusLine().getStatusCode() != 200) {
+      throw new ConfluenceException("Confluence error. "
+          + response.getStatusLine().getStatusCode() + " "
+          + response.getStatusLine().getReasonPhrase());
+    }
+    HttpEntity entity = response.getEntity();
+    Spaces spaces = spacesFromHttpEntity(entity);
+    EntityUtils.consume(entity);
+    return spaces;
+  }
+  
+  private List<String> getSpacePermissionsForUser(Space space, String username) throws Exception {
+    String url = String.format("%s://%s:%s%s%sgetPermissionsForUser", protocol, host,
+        port, path, AUTHORITY_PATH);
+
+    logger.debug(
+        "[Processing] Hitting url {} for getting Confluence permissions for user {} in space {}",
+        url, username, space.getKey());
+
+    HttpPost httpPost = createPostRequest(url);
+    JSONArray jsonArray = new JSONArray();
+    jsonArray.put(space.getKey());
+    jsonArray.put(username);
+    StringEntity stringEntity = new StringEntity(jsonArray.toString());
+    httpPost.setEntity(stringEntity);
+    HttpResponse response = httpClient.execute(httpPost);
+    if (response.getStatusLine().getStatusCode() != 200) {
+      throw new ConfluenceException("Confluence error. "
+          + response.getStatusLine().getStatusCode() + " "
+          + response.getStatusLine().getReasonPhrase());
+    }
+    HttpEntity entity = response.getEntity();
+    List<String> permissions = permissionsFromHttpEntity(entity);
+    EntityUtils.consume(entity);
+    return permissions;
+  }
+
+  private Spaces spacesFromHttpEntity(HttpEntity entity) throws Exception {
+    String stringEntity = EntityUtils.toString(entity);
+
+    JSONArray responseObject;
+    try {
+      responseObject = new JSONArray(stringEntity);
+      Spaces response = Spaces.fromJson(responseObject);
+
+      return response;
+    } catch (JSONException e) {
+      logger.debug("Error parsing JSON spaces response data");
+      throw new Exception("Error parsing JSON spaces response data");
+    }
+
+  }
+  
+  private List<String> permissionsFromHttpEntity(HttpEntity entity) throws Exception {
+    String stringEntity = EntityUtils.toString(entity);
+
+    JSONArray responseObject;
+    List<String> permissions = Lists.newArrayList();
+    try {
+      responseObject = new JSONArray(stringEntity);
+      for(int i=0,len=responseObject.length();i<len;i++) {
+        permissions.add(responseObject.getString(i));
+      }
+
+      return permissions;
+    } catch (JSONException e) {
+      logger.debug("Error parsing JSON space permissions response data");
+      throw new Exception("Error parsing JSON space permissions respnse data");
+    }
 
-	}
+  }
 }