Java tutorial
/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.github.maoo.indexer.client; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.commons.codec.binary.Base64; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.util.EntityUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.base.Strings; import com.google.common.io.CharStreams; import com.google.common.net.MediaType; import com.google.gson.Gson; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonPrimitive; public class WebScriptsAlfrescoClient implements AlfrescoClient { private static final String FIELD_PROPERTIES = "properties"; private static final String LAST_TXN_ID = "last_txn_id"; private static final String DOCS = "docs"; private static final String LAST_ACL_CS_ID = "last_acl_changeset_id"; private static final String URL_PARAM_LAST_TXN_ID = "lastTxnId"; private static final String URL_PARAM_LAST_ACL_CS_ID = "lastAclChangesetId"; private static final String URL_PARAM_INDEXING_FILTERS = "indexingFilters"; private static final String STORE_ID = "store_id"; private static final String STORE_PROTOCOL = "store_protocol"; private static final String USERNAME = "username"; private static final String AUTHORITIES = "authorities"; // private static final String UUIDS = "uuids"; private final Gson gson = new Gson(); private final String changesUrl; // private final String uuidsUrl; private final String actionsUrl; private final String metadataUrl; private final String authoritiesUrl; private final String username; private final String password; private final Logger logger = LoggerFactory.getLogger(WebScriptsAlfrescoClient.class); public WebScriptsAlfrescoClient(String protocol, String hostname, String endpoint, String storeProtocol, String storeId) { this(protocol, hostname, endpoint, storeProtocol, storeId, null, null); } public WebScriptsAlfrescoClient(String protocol, String hostname, String endpoint, String storeProtocol, String storeId, String username, String password) { changesUrl = String.format("%s://%s%s/node/changes/%s/%s", protocol, hostname, endpoint, storeProtocol, storeId); // uuidsUrl = String.format("%s://%s%s/node/uuids/%s/%s", protocol, hostname, endpoint, storeProtocol, storeId); actionsUrl = String.format("%s://%s%s/node/actions/%s/%s", protocol, hostname, endpoint, storeProtocol, storeId); metadataUrl = String.format("%s://%s%s/node/details/%s/%s", protocol, hostname, endpoint, storeProtocol, storeId); authoritiesUrl = String.format("%s://%s%s/auth/resolve/", protocol, hostname, endpoint); this.username = username; this.password = password; } @Override public AlfrescoResponse fetchNodes(long lastTransactionId, long lastAclChangesetId, AlfrescoFilters filters) { String urlWithParameter = String.format("%s?%s", changesUrl, urlParameters(lastTransactionId, lastAclChangesetId, filters)); return getDocumentsActions(urlWithParameter); } @Override public AlfrescoResponse fetchNode(String nodeUuid) throws AlfrescoDownException { String urlWithParameter = String.format("%s/%s", actionsUrl, nodeUuid); return getDocumentsActions(urlWithParameter); } private AlfrescoResponse getDocumentsActions(String url) { CloseableHttpClient httpClient = HttpClients.createDefault(); logger.debug("Hitting url: {}", url); try { HttpGet httpGet = createGetRequest(url); CloseableHttpResponse response = httpClient.execute(httpGet); HttpEntity entity = response.getEntity(); AlfrescoResponse afResponse = fromHttpEntity(entity); EntityUtils.consume(entity); response.close(); httpClient.close(); return afResponse; } catch (IOException e) { logger.warn("Failed to fetch nodes.", e); throw new AlfrescoDownException("Alfresco appears to be down", e); } } private HttpGet createGetRequest(String url) { HttpGet httpGet = new HttpGet(url); httpGet.addHeader("Accept", "application/json"); if (useBasicAuthentication()) { httpGet.addHeader("Authorization", "Basic " + Base64.encodeBase64String( String.format("%s:%s", username, password).getBytes(Charset.forName("UTF-8")))); } return httpGet; } private boolean useBasicAuthentication() { return username != null && !"".equals(username) && password != null; } private String urlParameters(long lastTransactionId, long lastAclChangesetId, AlfrescoFilters filters) { String urlParameters = null; if (filters != null && !filters.isEmpty()) { String indexingFilters = null; try { indexingFilters = URLEncoder.encode(filters.toJSONString(), "UTF-8"); } catch (UnsupportedEncodingException e) { indexingFilters = filters.toJSONString(); } urlParameters = String.format("%s=%d&%s=%d&%s=%s", URL_PARAM_LAST_TXN_ID, lastTransactionId, URL_PARAM_LAST_ACL_CS_ID, lastAclChangesetId, URL_PARAM_INDEXING_FILTERS, indexingFilters); } else urlParameters = String.format("%s=%d&%s=%d", URL_PARAM_LAST_TXN_ID, lastTransactionId, URL_PARAM_LAST_ACL_CS_ID, lastAclChangesetId); return urlParameters; } private AlfrescoResponse fromHttpEntity(HttpEntity entity) throws IOException { Reader entityReader = new InputStreamReader(entity.getContent()); JsonObject responseObject = gson.fromJson(entityReader, JsonObject.class); ArrayList<Map<String, Object>> documents = new ArrayList<Map<String, Object>>(); long lastTransactionId = getStringAsLong(responseObject, LAST_TXN_ID, 0L); long lastAclChangesetId = getStringAsLong(responseObject, LAST_ACL_CS_ID, 0L); String storeId = getString(responseObject, STORE_ID); String storeProtocol = getString(responseObject, STORE_PROTOCOL); if (responseObject.has(DOCS) && responseObject.get(DOCS).isJsonArray()) { JsonArray docsArray = responseObject.get(DOCS).getAsJsonArray(); for (JsonElement documentElement : docsArray) { Map<String, Object> document = createDocument(documentElement); document.put(STORE_ID, storeId); document.put(STORE_PROTOCOL, storeProtocol); documents.add(document); } } else { logger.warn("No documents found in response!"); } return new AlfrescoResponse(lastTransactionId, lastAclChangesetId, storeId, storeProtocol, documents); } // private Collection<String> extractIDs(HttpEntity entity) throws IOException { // Collection<String> uuids = Sets.newHashSet(); // Reader entityReader = new InputStreamReader(entity.getContent()); // JsonObject responseObject = gson.fromJson(entityReader, JsonObject.class); // JsonArray array = responseObject.getAsJsonArray(UUIDS); // for(JsonElement nextId:array) // uuids.add(nextId.getAsString()); // return uuids; // } private long getStringAsLong(JsonObject responseObject, String key, long defaultValue) { String string = getString(responseObject, key); if (Strings.isNullOrEmpty(string)) { return defaultValue; } return Long.parseLong(string); } private String getString(JsonObject responseObject, String key) { if (responseObject.has(key)) { JsonElement element = responseObject.get(key); if (element.isJsonPrimitive() && element.getAsJsonPrimitive().isString()) { return element.getAsString(); } else { logger.warn("The {} property (={}) is not a string in document: {}", new Object[] { key, element, responseObject }); } } else { logger.warn("The key {} is missing from document: {}", key, responseObject); } return ""; } @SuppressWarnings("unchecked") private Map<String, Object> createDocument(JsonElement documentElement) { if (documentElement.isJsonObject()) { JsonObject documentObject = documentElement.getAsJsonObject(); return (Map<String, Object>) gson.fromJson(documentObject, Map.class); } return new HashMap<String, Object>(); } @Override public Map<String, Object> fetchMetadata(String nodeUuid) throws AlfrescoDownException { String json = fetchMetadataJson(nodeUuid); @SuppressWarnings("unchecked") Map<String, Object> map = gson.fromJson(json, Map.class); List<Map<String, String>> properties = extractPropertiesFieldFromMap(nodeUuid, map); for (Map<String, String> e : properties) { map.put(e.get("name"), e.get("value")); } return map; } private String fetchMetadataJson(String nodeUuid) { String fullUrl = String.format("%s/%s", metadataUrl, nodeUuid); logger.debug("url: {}", fullUrl); try { CloseableHttpClient httpClient = HttpClients.createDefault(); HttpGet httpGet = createGetRequest(fullUrl); CloseableHttpResponse response = httpClient.execute(httpGet); HttpEntity entity = response.getEntity(); String result = CharStreams.toString(new InputStreamReader(entity.getContent(), "UTF-8")); response.close(); httpClient.close(); return result; } catch (IOException e) { throw new AlfrescoDownException(e); } } @SuppressWarnings("unchecked") private List<Map<String, String>> extractPropertiesFieldFromMap(String nodeUuid, Map<String, Object> map) { Object properties = map.remove(FIELD_PROPERTIES); if (properties == null) { throw new AlfrescoDownException("No Properties Fetched for the Node " + nodeUuid); } if (!(properties instanceof List)) { throw new AlfrescoDownException( FIELD_PROPERTIES + " is not of type List, it is of type " + properties.getClass()); } return (List<Map<String, String>>) properties; } private AlfrescoUser userFromHttpEntity(HttpEntity entity) throws IOException { Reader entityReader = new InputStreamReader(entity.getContent()); JsonElement responseObject = gson.fromJson(entityReader, JsonElement.class); if (responseObject instanceof JsonObject) { return getUser((JsonObject) responseObject); } else if (responseObject instanceof JsonArray) { return getUser(((JsonArray) responseObject).get(0).getAsJsonObject()); } else { return getUser(responseObject.getAsJsonObject()); } } private AlfrescoUser getUser(JsonObject responseObject) { String username = getUsername(responseObject); List<String> authorities = getAuthorities(responseObject); return new AlfrescoUser(username, authorities); } private String getUsername(JsonObject userObject) { if (!userObject.has(USERNAME)) { throw new AlfrescoParseException("Json response is missing username."); } JsonElement usernameElement = userObject.get(USERNAME); if (!usernameElement.isJsonPrimitive() || !usernameElement.getAsJsonPrimitive().isString()) { throw new AlfrescoParseException("Username must be a string. It was: " + usernameElement.toString()); } return usernameElement.getAsString(); } private List<String> getAuthorities(JsonObject userObject) { List<String> authorities = new ArrayList<String>(); if (!userObject.has(AUTHORITIES)) { throw new AlfrescoParseException("Json response is authorities."); } JsonElement authoritiesElement = userObject.get(AUTHORITIES); if (!authoritiesElement.isJsonArray()) { throw new AlfrescoParseException( "Authorities must be a json array. It was: " + authoritiesElement.toString()); } JsonArray authoritiesArray = authoritiesElement.getAsJsonArray(); for (JsonElement authorityElement : authoritiesArray) { if (!authorityElement.isJsonPrimitive()) { throw new AlfrescoParseException( "Authority entry must be a string. It was: " + authoritiesElement.toString()); } JsonPrimitive authorityPrimitive = authorityElement.getAsJsonPrimitive(); if (!authorityPrimitive.isString()) { throw new AlfrescoParseException( "Authority entry must be a string. It was: " + authoritiesElement.toString()); } authorities.add(authorityPrimitive.getAsString()); } return authorities; } @Override public AlfrescoUser fetchUserAuthorities(String username) throws AlfrescoDownException { CloseableHttpResponse response = null; CloseableHttpClient httpClient = HttpClients.createDefault(); try { String url = String.format("%s%s", authoritiesUrl, username); if (logger.isDebugEnabled()) { logger.debug("Hitting url: " + url); } HttpGet httpGet = createGetRequest(url); response = httpClient.execute(httpGet); HttpEntity entity = response.getEntity(); AlfrescoUser afResponse = userFromHttpEntity(entity); EntityUtils.consume(entity); return afResponse; } catch (IOException e) { if (logger.isDebugEnabled()) { logger.warn("Failed to fetch nodes.", e); } throw new AlfrescoDownException("Alfresco appears to be down", e); } finally { try { if (response != null) response.close(); httpClient.close(); } catch (IOException e) { // Nothing to do } } } @Override public List<AlfrescoUser> fetchAllUsersAuthorities() throws AlfrescoDownException { HttpResponse response; try { CloseableHttpClient httpClient = HttpClients.createDefault(); if (logger.isDebugEnabled()) { logger.debug("Hitting url: " + authoritiesUrl); } HttpGet httpGet = createGetRequest(authoritiesUrl); response = httpClient.execute(httpGet); HttpEntity entity = response.getEntity(); List<AlfrescoUser> users = usersFromHttpEntity(entity); EntityUtils.consume(entity); return users; } catch (IOException e) { if (logger.isDebugEnabled()) { logger.warn("Failed to fetch nodes.", e); } throw new AlfrescoDownException("Alfresco appears to be down", e); } } private List<AlfrescoUser> usersFromHttpEntity(HttpEntity entity) throws IOException { Reader entityReader = new InputStreamReader(entity.getContent()); JsonElement responseObject = gson.fromJson(entityReader, JsonElement.class); if (!responseObject.isJsonArray()) { throw new AlfrescoParseException("Users must be a json array."); } List<AlfrescoUser> users = new ArrayList<AlfrescoUser>(); JsonArray usersArray = responseObject.getAsJsonArray(); for (JsonElement userElement : usersArray) { if (!userElement.isJsonObject()) { throw new AlfrescoParseException("User must be a json object."); } AlfrescoUser user = getUser(userElement.getAsJsonObject()); users.add(user); } return users; } @Override public InputStream fetchContent(String contentUrlPath) { HttpGet httpGet = new HttpGet(contentUrlPath); httpGet.addHeader("Accept", MediaType.APPLICATION_BINARY.toString()); if (useBasicAuthentication()) { httpGet.addHeader("Authorization", "Basic " + Base64.encodeBase64String( String.format("%s:%s", username, password).getBytes(Charset.forName("UTF-8")))); } CloseableHttpClient httpClient = HttpClients.createDefault(); try { HttpResponse response = httpClient.execute(httpGet); InputStream stream = response.getEntity().getContent(); return stream; } catch (Exception e) { throw new AlfrescoDownException("Alfresco appears to be down", e); } } }