diff --git a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/core/oldAPI/BaseApi.java b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/core/oldAPI/BaseApi.java new file mode 100644 index 0000000000..2d0616248f --- /dev/null +++ b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/core/oldAPI/BaseApi.java @@ -0,0 +1,439 @@ +/* + * #%L + * Alfresco Records Management Module + * %% + * Copyright (C) 2005 - 2017 Alfresco Software Limited + * %% + * This file is part of the Alfresco software. + * - + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * - + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * - + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * - + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + * #L% + */ +package org.alfresco.rest.core.oldAPI; + +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.URI; +import java.net.URISyntaxException; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.alfresco.dataprep.AlfrescoHttpClient; +import org.alfresco.dataprep.AlfrescoHttpClientFactory; +import org.apache.http.HttpResponse; +import org.apache.http.HttpStatus; +import org.apache.http.NameValuePair; +import org.apache.http.ParseException; +import org.apache.http.client.methods.HttpDelete; +import org.apache.http.client.methods.HttpEntityEnclosingRequestBase; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.client.methods.HttpPut; +import org.apache.http.client.methods.HttpRequestBase; +import org.apache.http.client.utils.URLEncodedUtils; +import org.apache.http.entity.StringEntity; +import org.apache.http.util.EntityUtils; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; + +public abstract class BaseApi +{ + // logger + private static final Logger LOGGER = LoggerFactory.getLogger(BaseApi.class); + + /** exception key in JSON response body */ + private static final String EXCEPTION_KEY = "exception"; + + @Autowired + private AlfrescoHttpClientFactory alfrescoHttpClientFactory; + + /** + * Helper method to extract list of properties values from result. + * + * @param result + * @return list of specified property values in result + * @throws RuntimeException for malformed response + */ + public List getPropertyValues(JSONObject result, String propertyName) + { + ArrayList results = new ArrayList(); + try + { + JSONArray items = result.getJSONArray("items"); + + for (int i = 0; i < items.length(); i++) + { + results.add(items.getJSONObject(i).getString(propertyName)); + } + } + catch (JSONException error) + { + throw new RuntimeException("Unable to parse result", error); + } + + return results; + } + + /** + * Helper method to extract property values from request result and put them in map as a list that corresponds to a unique property value. + * + * @param requestResult + * @return a map containing information about multiple properties values that correspond to a unique one + * @throws RuntimeException for malformed response + */ + public Map> getPropertyValuesByUniquePropertyValue(JSONObject requestResult, String uniqueProperty, List otherProperties) + { + Map> valuesByUniqueProperty = new HashMap<>(); + try + { + JSONArray items = requestResult.getJSONArray("items"); + + for (int i = 0; i < items.length(); i++) + { + List otherPropertiesValues = new ArrayList<>(); + + for (int j = 0; j < otherProperties.size(); j++) + { + otherPropertiesValues.add(items.getJSONObject(i).get(otherProperties.get(j)).toString()); + } + valuesByUniqueProperty.put(items.getJSONObject(i).getString(uniqueProperty), otherPropertiesValues); + } + } + catch (JSONException error) + { + throw new RuntimeException("Unable to parse result", error); + } + + return valuesByUniqueProperty; + } + + /** + * Generic faceted request. + * + * @param username + * @param password + * @param parameters if the request has parameters + * @return result object (see API reference for more details), null for any errors + */ + public JSONObject facetedRequest(String username, String password, List parameters, String requestURI) + { + String requestURL; + AlfrescoHttpClient client = alfrescoHttpClientFactory.getObject(); + + if (parameters == null || parameters.isEmpty()) + { + requestURL = MessageFormat.format( + requestURI, + client.getAlfrescoUrl()); + } + else + { + requestURL = MessageFormat.format( + requestURI, + client.getAlfrescoUrl(), + URLEncodedUtils.format(parameters, "UTF-8")); + } + client.close(); + return doGetRequest(username, password, requestURL); + } + + /** + * Helper method for GET requests + * @param adminUser user with administrative privileges + * @param adminPassword password for adminUser + * @param urlTemplate request URL template + * @param urlTemplateParams zero or more parameters used with urlTemplate + */ + public JSONObject doGetRequest(String adminUser, + String adminPassword, + String urlTemplate, + String ... urlTemplateParams) + { + AlfrescoHttpClient client = alfrescoHttpClientFactory.getObject(); + String requestUrl = MessageFormat.format( + urlTemplate, + client.getApiUrl(), + urlTemplateParams); + client.close(); + + try + { + return doRequest(HttpGet.class, requestUrl, adminUser, adminPassword, null); + } + catch (InstantiationException | IllegalAccessException error) + { + throw new IllegalArgumentException("doGetRequest failed", error); + } + } + + /** + * Helper method for Delete requests + * @param adminUser user with administrative privileges + * @param adminPassword password for adminUser + * @param urlTemplate request URL template + * @param urlTemplateParams zero or more parameters used with urlTemplate + */ + public JSONObject doDeleteRequest(String adminUser, + String adminPassword, + String urlTemplate, + String ... urlTemplateParams) + { + AlfrescoHttpClient client = alfrescoHttpClientFactory.getObject(); + String requestUrl = MessageFormat.format( + urlTemplate, + client.getApiUrl(), + urlTemplateParams); + client.close(); + + try + { + return doRequest(HttpDelete.class, requestUrl, adminUser, adminPassword, null); + } + catch (InstantiationException | IllegalAccessException error) + { + throw new IllegalArgumentException("doDeleteRequest failed", error); + } + } + + /** + * Helper method for PUT requests + * @param adminUser user with administrative privileges + * @param adminPassword password for adminUser + * @param requestParams zero or more endpoint specific request parameters + * @param urlTemplate request URL template + * @param urlTemplateParams zero or more parameters used with urlTemplate + */ + public JSONObject doPutRequest(String adminUser, + String adminPassword, + JSONObject requestParams, + String urlTemplate, + String ... urlTemplateParams) + { + AlfrescoHttpClient client = alfrescoHttpClientFactory.getObject(); + String requestUrl = MessageFormat.format( + urlTemplate, + client.getApiUrl(), + urlTemplateParams); + client.close(); + + try + { + return doRequest(HttpPut.class, requestUrl, adminUser, adminPassword, requestParams); + } + catch (InstantiationException | IllegalAccessException error) + { + throw new IllegalArgumentException("doPutRequest failed", error); + } + } + + /** + * Helper method for POST requests + * @param adminUser user with administrative privileges + * @param adminPassword password for adminUser + * @param requestParams zero or more endpoint specific request parameters + * @param urlTemplate request URL template + * @param urlTemplateParams zero or more parameters used with urlTemplate + */ + public JSONObject doPostRequest(String adminUser, + String adminPassword, + JSONObject requestParams, + String urlTemplate, + String ... urlTemplateParams) + { + AlfrescoHttpClient client = alfrescoHttpClientFactory.getObject(); + String requestUrl = MessageFormat.format( + urlTemplate, + client.getApiUrl(), + urlTemplateParams); + client.close(); + + try + { + return doRequest(HttpPost.class, requestUrl, adminUser, adminPassword, requestParams); + } + catch (InstantiationException | IllegalAccessException error) + { + throw new IllegalArgumentException("doPostRequest failed", error); + } + } + + /** + * Helper method for POST requests + * + * @param adminUser user with administrative privileges + * @param adminPassword password for adminUser + * @param requestParams zero or more endpoint specific request parameters + * @param urlTemplate request URL template + * @param urlTemplateParams zero or more parameters used with urlTemplate + */ + public boolean doPostJsonRequest(String adminUser, + String adminPassword, + JSONObject requestParams, + String urlTemplate, + String... urlTemplateParams) + { + AlfrescoHttpClient client = alfrescoHttpClientFactory.getObject(); + String requestUrl = MessageFormat.format( + urlTemplate, + client.getApiUrl(), + urlTemplateParams); + client.close(); + + try + { + return doRequestJson(HttpPost.class, requestUrl, adminUser, adminPassword, requestParams); + } + catch (InstantiationException | IllegalAccessException error) + { + throw new IllegalArgumentException("doPostRequest failed", error); + } + } + + /** + * Helper method for handling generic HTTP requests + * @param requestType request type (a subclass of {@link HttpRequestBase}) + * @param requestUrl URL the request is to be sent to + * @param adminUser user with administrative privileges + * @param adminPassword password for adminUser + * @param requestParams endpoint specific request parameters + * @return response body + * @throws IllegalAccessException for invalid requestType + * @throws InstantiationException for invalid requestType + */ + private JSONObject doRequest( + Class requestType, + String requestUrl, + String adminUser, + String adminPassword, + JSONObject requestParams) throws InstantiationException, IllegalAccessException + { + AlfrescoHttpClient client = alfrescoHttpClientFactory.getObject(); + T request = requestType.newInstance(); + + HttpResponse response = null; + JSONObject responseBody = null; + JSONObject returnValues = null; + + try + { + request.setURI(new URI(requestUrl)); + + if (requestParams != null && request instanceof HttpEntityEnclosingRequestBase) + { + ((HttpEntityEnclosingRequestBase) request).setEntity(new StringEntity(requestParams.toString())); + } + response = client.execute(adminUser, adminPassword, request); + + try + { + responseBody = new JSONObject(EntityUtils.toString(response.getEntity())); + } + catch (ParseException | IOException | JSONException error) + { + LOGGER.error("Parsing message body failed", error); + } + + switch (response.getStatusLine().getStatusCode()) + { + case HttpStatus.SC_OK: + case HttpStatus.SC_CREATED: + // request successful + if (responseBody != null) + { + returnValues = responseBody; + } + break; + + case HttpStatus.SC_INTERNAL_SERVER_ERROR: + case HttpStatus.SC_BAD_REQUEST: + if (responseBody != null && responseBody.has(EXCEPTION_KEY)) + { + LOGGER.error("Request failed: " + responseBody.getString(EXCEPTION_KEY)); + } + break; + + default: + LOGGER.error("Request returned unexpected HTTP status " + response.getStatusLine().getStatusCode()); + break; + } + } + catch (JSONException error) + { + LOGGER.error("Unable to extract response parameter", error); + } + catch (UnsupportedEncodingException | URISyntaxException error1) + { + LOGGER.error("Unable to construct request", error1); + } + finally + { + if (request != null) + { + request.releaseConnection(); + } + client.close(); + } + + return returnValues; + } + + private boolean doRequestJson( + Class requestType, + String requestUrl, + String adminUser, + String adminPassword, + JSONObject requestParams) throws InstantiationException, IllegalAccessException + { + AlfrescoHttpClient client = alfrescoHttpClientFactory.getObject(); + T request = requestType.newInstance(); + + try + { + request.setURI(new URI(requestUrl)); + request.setHeader("Content-Type", "application/json"); + + if (requestParams != null && request instanceof HttpEntityEnclosingRequestBase) + { + ((HttpEntityEnclosingRequestBase) request).setEntity(new StringEntity(requestParams.toString())); + } + + return client.execute(adminUser, adminPassword, request).getStatusLine().getStatusCode() == HttpStatus.SC_OK; + } + catch (UnsupportedEncodingException | URISyntaxException error1) + { + LOGGER.error("Unable to construct request", error1); + } + finally + { + if (request != null) + { + request.releaseConnection(); + } + client.close(); + } + + return false; + } +} diff --git a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/oldAPI/SearchApi.java b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/oldAPI/SearchApi.java new file mode 100644 index 0000000000..b67475a6c9 --- /dev/null +++ b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/oldAPI/SearchApi.java @@ -0,0 +1,176 @@ +/* + * #%L + * Alfresco Records Management Module + * %% + * Copyright (C) 2005 - 2017 Alfresco Software Limited + * %% + * This file is part of the Alfresco software. + * - + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * - + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * - + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * - + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + * #L% + */ +package org.alfresco.rest.rm.community.oldAPI; + +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.alfresco.dataprep.AlfrescoHttpClientFactory; +import org.alfresco.rest.core.oldAPI.BaseApi; +import org.apache.http.NameValuePair; +import org.apache.http.client.utils.URLEncodedUtils; +import org.apache.http.message.BasicNameValuePair; +import org.json.JSONObject; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * Helper methods for performing search using various Alfresco search APIs. + * @author Kristijan Conkas + * @since 2.5 + */ +@Component +public class SearchApi extends BaseApi +{ + /** http client factory */ + @Autowired private AlfrescoHttpClientFactory alfrescoHttpClientFactory; + + /** faceted search API endpoint */ + private static final String FACETED_SEARCH_ENDPOINT = "{0}alfresco/s/slingshot/rmsearch/faceted/rmsearch?{1}"; + + /** RM search URL template */ + private static final String RM_SEARCH_ENDPOINT = "{0}alfresco/s/slingshot/rmsearch/{1}?{2}"; + + /** RM document search filters */ + private static final String RM_DEFAULT_RECORD_FILTERS = + "records/true,undeclared/true,vital/false,folders/false,categories/false,frozen/false,cutoff/false"; + + /** + * Perform search request on search endpoint as a user. + *

+ * This method is applicable only to endpoints that support HTTP GET requests and return JSON body as response. + * @param searchEndpoint + * @param searchUser + * @param searchPassword + * @return search results as a {@link JSONObject}, please refer to API documentation for details + */ + private JSONObject doSearch( + String searchEndpoint, + String searchUser, + String searchPassword) + { + return facetedRequest(searchUser, searchPassword, null, searchEndpoint); + } + + /** + * Generic rm search. + * @param username + * @param password + * @param site + * @param query + * @param filters + * @return search results (see API reference for more details), null for any errors + */ + public JSONObject rmSearch( + String username, + String password, + String site, + String query, + String filters) + { + List searchParameters = new ArrayList(); + searchParameters.add(new BasicNameValuePair("query", query)); + searchParameters.add(new BasicNameValuePair("filters", filters)); + + String requestURL = MessageFormat.format( + RM_SEARCH_ENDPOINT, + alfrescoHttpClientFactory.getObject().getAlfrescoUrl(), + (site != null) ? site : "rm", + URLEncodedUtils.format(searchParameters, "UTF-8")); + + return doSearch(requestURL, username, password); + } + + /** + * Search as a user for records on site "rm" matching query, using RM_DEFAULT_RECORD_FILTERS. + *
+ * If more fine-grained control of search parameters is required, use rmSearch() directly. + * @param username + * @param password + * @param query + * @return list of record names + */ + public List searchForRecordsAsUser( + String username, + String password, + String query) + { + return getItemNames(rmSearch(username, password, "rm", query, RM_DEFAULT_RECORD_FILTERS)); + } + + /** + * Generic faceted search. + * @param username + * @param password + * @param parameters + * @return search results (see API reference for more details), null for any errors + */ + public JSONObject facetedSearch(String username, String password, List parameters) + { + return facetedRequest(username, password, parameters, FACETED_SEARCH_ENDPOINT); + } + + /** + * Execute faceted search for term. + * @param searchUser + * @param searchPassword + * @param searchTerm + * @return search results (see API reference for more details) + */ + public JSONObject facetedSearchForTerm(String searchUser, String searchPassword, String searchTerm) + { + return facetedSearch( + searchUser, + searchPassword, + Arrays.asList(new BasicNameValuePair("term", searchTerm))); + } + + /** + * Helper method to search for documents as a user using faceted search. + * @param username to search as + * @param password for username + * @param term search term + * @return list of document names found + */ + public List searchForDocumentsAsUser(String username, String password, String term) + { + return getItemNames(facetedSearchForTerm(username, password, term)); + } + + /** + * Helper method to extract list of names from search result. + * @param searchResult + * @return list of document or record names in search result + * @throws RuntimeException for malformed search response + */ + private List getItemNames(JSONObject searchResult) + { + return getPropertyValues(searchResult, "name"); + } +}