Java tutorial
/* * Copyright 2017 Hewlett-Packard Development Company, L.P. * Licensed 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.hp.mqm.client; import com.hp.mqm.client.exception.*; import com.hp.mqm.client.exception.FileNotFoundException; import com.hp.mqm.client.model.*; import net.sf.json.JSONArray; import net.sf.json.JSONException; import net.sf.json.JSONNull; import net.sf.json.JSONObject; import org.apache.commons.codec.binary.Base64; import org.apache.commons.io.IOUtils; import org.apache.commons.lang.StringUtils; import org.apache.http.HttpResponse; import org.apache.http.HttpStatus; import org.apache.http.client.entity.GzipCompressingEntity; import org.apache.http.client.methods.HttpDelete; 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.utils.HttpClientUtils; import org.apache.http.client.utils.URIBuilder; import org.apache.http.entity.ByteArrayEntity; import org.apache.http.entity.ContentType; import org.apache.http.entity.InputStreamEntity; import org.apache.http.entity.StringEntity; import org.apache.http.protocol.HTTP; import java.io.*; import java.net.URI; import java.net.URISyntaxException; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.*; import java.util.logging.Level; import java.util.logging.Logger; import java.util.zip.GZIPOutputStream; public class MqmRestClientImpl extends AbstractMqmRestClient implements MqmRestClient { private static final Logger logger = Logger.getLogger(MqmRestClientImpl.class.getName()); private static final String DATETIME_FORMAT = "yyyy-MM-dd'T'HH:mm:ssZ"; private static final String PREFIX_CI = "analytics/ci/"; private static final String PREFIX_BDI = "analytics/bdi/"; private static final String URI_TEST_RESULT_PUSH = PREFIX_CI + "test-results?skip-errors={0}"; private static final String URI_TEST_RESULT_STATUS = PREFIX_CI + "test-results/{0}"; private static final String URI_TEST_RESULT_LOG = URI_TEST_RESULT_STATUS + "/log"; private static final String URI_JOB_CONFIGURATION = "analytics/ci/servers/{0}/jobs/{1}/configuration"; private static final String URI_DELETE_NODES_TESTS = "analytics/ci/pipelines/{0}/jobs/{1}/tests"; private static final String URI_PREFLIGHT = "analytics/ci/servers/{0}/jobs/{1}/tests-result-preflight"; private static final String URI_BASE64SUPPORT = "analytics/ci/servers/tests-result-preflight-base64"; private static final String URI_WORKSPACE_BY_JOB_AND_SERVER = PREFIX_CI + "servers/{0}/jobs/{1}/workspaceId"; private static final String URI_BDI_CONFIGURATION = PREFIX_BDI + "configuration"; private static final String URI_BDI_ACCESS_TOKEN = PREFIX_BDI + "token"; private static final String URI_RELEASES = "releases"; private static final String URI_WORKSPACES = "workspaces"; private static final String URI_LIST_ITEMS = "list_nodes"; private static final String URI_METADATA_FIELDS = "metadata/fields"; private static final String URI_PUT_EVENTS = "analytics/ci/events"; private static final String URI_GET_ABRIDGED_TASKS = "analytics/ci/servers/{0}/tasks?self-type={1}&self-url={2}&api-version={3}&sdk-version={4}&plugin-version={5}&client-id={6}&ci-server-user={7}&suspended={8}"; private static final String URI_PUT_ABRIDGED_RESULT = "analytics/ci/servers/{0}/tasks/{1}/result"; private static final String URI_POST_LOGS = "analytics/ci/{0}/{1}/{2}/logs"; private static final String URI_POST_COVERAGE_REPORTS = "analytics/ci/coverage?ci-server-identity={0}&ci-job-id={1}&ci-build-id={2}&file-type={3}"; private static final String URI_TAXONOMY_NODES = "taxonomy_nodes"; private static final String HEADER_ACCEPT = "Accept"; private static final int DEFAULT_OFFSET = 0; private static final int DEFAULT_LIMIT = 100; private static final int MAX_GET_LIMIT = 1000; private static final String CONTENT_ENCODING_GZIP = "gzip"; private static final String UNCOMPRESSED_CONTENT_LENGTH = "Uncompressed-Content-Length"; /** * Constructor for AbstractMqmRestClient. * * @param connectionConfig MQM connection configuration, Fields 'location', 'domain', 'project' and 'clientType' must not be null or empty. */ public MqmRestClientImpl(MqmConnectionConfig connectionConfig) { super(connectionConfig); } @Override public long postTestResult(InputStreamSource inputStreamSource, boolean skipErrors) { return postTestResult(createGZipEntity(inputStreamSource.getInputStream()), skipErrors); } @Override public long postTestResult(File testResultReport, boolean skipErrors) { try { return postTestResult(createGZipEntity(new FileInputStream(testResultReport)), skipErrors); } catch (java.io.FileNotFoundException fnfe) { logger.severe("file " + testResultReport + " not found"); return -1; } } @Override public Boolean isTestResultRelevant(String serverIdentity, String jobName) { URI supportsBase64Uri = createSharedSpaceInternalApiUri(URI_BASE64SUPPORT); HttpGet request = new HttpGet(supportsBase64Uri); HttpResponse response = null; String jobNameForSending = jobName; try { response = execute(request); if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) { logger.log(Level.INFO, "Octane supports base64 encoding"); jobNameForSending = Base64.encodeBase64String(jobName.getBytes()); } } catch (IOException ex) { logger.log(Level.INFO, "Octane does not support base64 encoding"); } logger.log(Level.INFO, String.format("Job name before encoding: %s, after encoding : %s", jobName, jobNameForSending)); URI getUri = createSharedSpaceInternalApiUri(URI_PREFLIGHT, serverIdentity, jobNameForSending); try { URIBuilder uriPreflight = new URIBuilder( createSharedSpaceInternalApiUri(URI_PREFLIGHT, serverIdentity, jobNameForSending)) .addParameter("isBase64", "true"); logger.log(Level.INFO, String.format("test preflight URI: %s", uriPreflight.build().getPath())); getUri = uriPreflight.build(); } catch (URISyntaxException ex) { logger.log(Level.SEVERE, "Error creating uri for test preflight!", ex); } request = new HttpGet(getUri); response = null; try { response = execute(request); if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) { throw createRequestException("Result status retrieval failed", response); } return Boolean.parseBoolean(IOUtils.toString(response.getEntity().getContent(), "UTF-8")); } catch (IOException e) { throw new RequestErrorException("Cannot obtain status.", e); } finally { HttpClientUtils.closeQuietly(response); } } @Override public JSONObject getBdiConfiguration() { HttpGet request = new HttpGet(createSharedSpaceInternalApiUri(URI_BDI_CONFIGURATION)); HttpResponse response = null; try { response = execute(request); int statusCode = response.getStatusLine().getStatusCode(); if (statusCode == HttpStatus.SC_NO_CONTENT) { logger.config("BDI is not configured in Octane"); return null; } if (statusCode != HttpStatus.SC_OK) { throw createRequestException("BDI configuration retrieval failed", response); } String bdiConfiguration = IOUtils.toString(response.getEntity().getContent(), "UTF-8"); return JSONObject.fromObject(bdiConfiguration); } catch (IOException e) { throw new RequestErrorException("Cannot obtain status.", e); } finally { HttpClientUtils.closeQuietly(response); } } @Override public String getBdiTokenData() { HttpGet request = new HttpGet(createSharedSpaceInternalApiUri(URI_BDI_ACCESS_TOKEN)); HttpResponse response = null; try { response = execute(request); if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) { return IOUtils.toString(response.getEntity().getContent(), "UTF-8"); } else { throw createRequestException("BDI token retrieval failed", response); } } catch (IOException e) { throw new RequestErrorException("failed to parse token data response", e); } finally { HttpClientUtils.closeQuietly(response); } } @Override public List<String> getJobWorkspaceId(String ciServerId, String ciJobName) { HttpGet request = new HttpGet( createSharedSpaceInternalApiUri(URI_WORKSPACE_BY_JOB_AND_SERVER, ciServerId, ciJobName)); HttpResponse response = null; try { response = execute(request); int statusCode = response.getStatusLine().getStatusCode(); if (statusCode == HttpStatus.SC_NO_CONTENT) { logger.info("Job " + ciJobName + " has no build context in Octane"); return new ArrayList<>(); } if (statusCode != HttpStatus.SC_OK) { throw createRequestException("workspace retrieval failed", response); } JSONArray workspaces = JSONArray .fromObject(IOUtils.toString(response.getEntity().getContent(), "UTF-8")); return workspaces.subList(0, workspaces.size()); } catch (IOException e) { throw new RequestErrorException("Cannot obtain status.", e); } finally { HttpClientUtils.closeQuietly(response); } } @Override public TestResultStatus getTestResultStatus(long id) { HttpGet request = new HttpGet(createSharedSpaceInternalApiUri(URI_TEST_RESULT_STATUS, id)); HttpResponse response = null; try { response = execute(request); if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) { throw createRequestException("Result status retrieval failed", response); } String json = IOUtils.toString(response.getEntity().getContent(), "UTF-8"); JSONObject jsonObject = JSONObject.fromObject(json); Date until = null; if (jsonObject.has("until")) { try { until = parseDatetime(jsonObject.getString("until")); } catch (ParseException e) { throw new RequestErrorException("Cannot obtain status", e); } } return new TestResultStatus(jsonObject.getString("status"), until); } catch (IOException e) { throw new RequestErrorException("Cannot obtain status.", e); } finally { HttpClientUtils.closeQuietly(response); } } @Override public void getTestResultLog(long id, LogOutput output) { HttpGet request = new HttpGet(createSharedSpaceInternalApiUri(URI_TEST_RESULT_LOG, id)); HttpResponse response = null; try { response = execute(request); if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) { throw createRequestException("Log retrieval failed", response); } output.setContentType(response.getFirstHeader("Content-type").getValue()); InputStream is = response.getEntity().getContent(); IOUtils.copy(is, output.getOutputStream()); IOUtils.closeQuietly(is); } catch (IOException e) { throw new RequestErrorException("Cannot obtain log.", e); } finally { HttpClientUtils.closeQuietly(response); } } @Override public JobConfiguration getJobConfiguration(String serverIdentity, String jobName) { HttpGet request = new HttpGet( createSharedSpaceInternalApiUri(URI_JOB_CONFIGURATION, serverIdentity, jobName)); HttpResponse response = null; try { response = execute(request); if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) { throw createRequestException("Job configuration retrieval failed", response); } String json = IOUtils.toString(response.getEntity().getContent(), "UTF-8"); try { JSONObject jsonObject = JSONObject.fromObject(json); List<Pipeline> pipelines = new LinkedList<>(); for (JSONObject relatedContext : getJSONObjectCollection(jsonObject, "data")) { if ("pipeline".equals(relatedContext.getString("contextEntityType"))) { pipelines.add(toPipeline(relatedContext)); } else { logger.info( "Context type '" + relatedContext.get("contextEntityType") + "' is not supported"); } } return new JobConfiguration(pipelines); } catch (JSONException e) { throw new RequestErrorException("Failed to obtain job configuration", e); } } catch (IOException e) { throw new RequestErrorException("Cannot retrieve job configuration from MQM.", e); } finally { HttpClientUtils.closeQuietly(response); } } @Override public Pipeline createPipeline(String serverIdentity, String projectName, String pipelineName, long workspaceId, Long releaseId, String structureJson, String serverJson) { HttpPost request = new HttpPost( createSharedSpaceInternalApiUri(URI_JOB_CONFIGURATION, serverIdentity, projectName)); JSONObject pipelineObject = new JSONObject(); pipelineObject.put("contextEntityType", "pipeline"); pipelineObject.put("contextEntityName", pipelineName); pipelineObject.put("workspaceId", workspaceId); pipelineObject.put("releaseId", releaseId); pipelineObject.put("server", JSONObject.fromObject(serverJson)); pipelineObject.put("structure", JSONObject.fromObject(structureJson)); request.setEntity(new StringEntity(pipelineObject.toString(), ContentType.APPLICATION_JSON)); HttpResponse response = null; try { response = execute(request); if (response.getStatusLine().getStatusCode() != HttpStatus.SC_CREATED) { throw createRequestException("Pipeline creation failed", response); } String json = IOUtils.toString(response.getEntity().getContent(), "UTF-8"); return getPipelineByName(json, pipelineName, workspaceId); } catch (IOException e) { throw new RequestErrorException("Cannot create pipeline in MQM.", e); } finally { HttpClientUtils.closeQuietly(response); } } @Override public Pipeline updatePipeline(String serverIdentity, String jobName, Pipeline pipeline) { HttpPut request = new HttpPut( createSharedSpaceInternalApiUri(URI_JOB_CONFIGURATION, serverIdentity, jobName)); JSONObject pipelineObject = new JSONObject(); pipelineObject.put("contextEntityType", "pipeline"); pipelineObject.put("contextEntityId", pipeline.getId()); pipelineObject.put("workspaceId", pipeline.getWorkspaceId()); if (pipeline.getName() != null) { pipelineObject.put("contextEntityName", pipeline.getName()); } if (pipeline.getReleaseId() != null) { if (pipeline.getReleaseId() == -1) { pipelineObject.put("releaseId", JSONNull.getInstance()); } else { pipelineObject.put("releaseId", pipeline.getReleaseId()); } } if (pipeline.getIgnoreTests() != null) { pipelineObject.put("ignoreTests", pipeline.getIgnoreTests()); } if (pipeline.getTaxonomies() != null) { JSONArray taxonomies = taxonomiesArray(pipeline.getTaxonomies()); pipelineObject.put("taxonomies", taxonomies); } if (pipeline.getFields() != null) { JSONObject listFields = listFieldsObject(pipeline.getFields()); pipelineObject.put("listFields", listFields); } JSONArray data = new JSONArray(); data.add(pipelineObject); JSONObject payload = new JSONObject(); payload.put("data", data); request.setEntity(new StringEntity(payload.toString(), ContentType.APPLICATION_JSON)); request.setHeader(HEADER_ACCEPT, ContentType.APPLICATION_JSON.getMimeType()); HttpResponse response = null; try { response = execute(request); if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) { throw createRequestException("Pipeline update failed", response); } String json = IOUtils.toString(response.getEntity().getContent(), "UTF-8"); return getPipelineById(json, pipeline.getId()); } catch (IOException e) { throw new RequestErrorException("Cannot update pipeline.", e); } finally { HttpClientUtils.closeQuietly(response); } } @Override public void deleteTestsFromPipelineNodes(String jobName, Long pipelineId, Long workspaceId) { HttpDelete request = new HttpDelete( createWorkspaceInternalApiUriMap(URI_DELETE_NODES_TESTS, workspaceId, pipelineId, jobName)); HttpResponse response = null; try { response = execute(request); if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) { throw createRequestException("delete tests failed", response); } } catch (IOException e) { throw new RequestErrorException("Cannot delete tests.", e); } finally { HttpClientUtils.closeQuietly(response); } } private Date parseDatetime(String datetime) throws ParseException { return new SimpleDateFormat(DATETIME_FORMAT).parse(datetime); } private JSONArray taxonomiesArray(List<Taxonomy> taxonomies) { JSONArray ret = new JSONArray(); for (Taxonomy taxonomy : taxonomies) { ret.add(fromTaxonomy(taxonomy)); } return ret; } private JSONObject listFieldsObject(List<ListField> fields) { JSONObject ret = new JSONObject(); for (ListField field : fields) { putListField(ret, field); } return ret; } private void putListField(JSONObject ret, ListField listField) { JSONArray valArray = new JSONArray(); for (ListItem value : listField.getValues()) { JSONObject val = new JSONObject(); if (value.getId() != null) { val.put("id", value.getId()); } else { val.put("name", value.getName()); } valArray.add(val); } ret.put(listField.getName(), valArray); } private Taxonomy toTaxonomy(JSONObject t) { JSONObject parent = t.optJSONObject("parent"); String name = t.has("name") ? t.getString("name") : null; if (parent != null) { return new Taxonomy(t.getLong("id"), name, toTaxonomy(parent)); } else { return new Taxonomy(t.getLong("id"), name, null); } } private JSONObject fromTaxonomy(Taxonomy taxonomy) { JSONObject t = new JSONObject(); if (taxonomy.getId() != null && taxonomy.getId() != 0) { t.put("id", taxonomy.getId()); } if (taxonomy.getName() != null) { //todo seems that name can be ommited in case that id exists t.put("name", taxonomy.getName()); } if (taxonomy.getRoot() != null) { t.put("parent", fromTaxonomy(taxonomy.getRoot())); } else { t.put("parent", JSONNull.getInstance()); } return t; } private Pipeline getPipelineByName(String json, String pipelineName, long workspaceId) { try { for (JSONObject item : getJSONObjectCollection(JSONObject.fromObject(json), "data")) { if (!"pipeline".equals(item.getString("contextEntityType"))) { continue; } if (!item.getBoolean("pipelineRoot")) { continue; } if (!pipelineName.equals(item.getString("contextEntityName"))) { continue; } if (workspaceId != item.getLong("workspaceId")) { continue; } return toPipeline(item); } throw new RequestErrorException("Failed to obtain pipeline: item not found"); } catch (JSONException e) { throw new RequestErrorException("Failed to obtain pipeline", e); } } private Pipeline getPipelineById(String json, long pipelineId) { try { for (JSONObject item : getJSONObjectCollection(JSONObject.fromObject(json), "data")) { if (!"pipeline".equals(item.getString("contextEntityType"))) { continue; } if (pipelineId != item.getLong("contextEntityId")) { continue; } return toPipeline(item); } throw new RequestErrorException("Failed to obtain pipeline: item not found"); } catch (JSONException e) { throw new RequestErrorException("Failed to obtain pipeline", e); } } private ListItem toListItem(JSONObject field) { String id = null; String name = null; if (field.has("id")) { id = field.getString("id"); } if (field.has("name")) { name = field.getString("name"); } return new ListItem(id, null, name, null); } private Pipeline toPipeline(JSONObject pipelineObject) { List<Taxonomy> taxonomies = new LinkedList<>(); List<ListField> fields = new LinkedList<>(); if (pipelineObject.has("taxonomies")) { for (JSONObject taxonomy : getJSONObjectCollection(pipelineObject, "taxonomies")) { taxonomies.add(toTaxonomy(taxonomy)); } } if (pipelineObject.has("listFields")) { JSONObject listFields = pipelineObject.getJSONObject("listFields"); Iterator<?> keys = listFields.keys(); while (keys.hasNext()) { String key = (String) keys.next(); if (listFields.get(key) instanceof JSONArray) { List<ListItem> fieldValues = new LinkedList<>(); for (JSONObject field : getJSONObjectCollection(listFields, key)) { fieldValues.add(toListItem(field)); } fields.add(new ListField(key, fieldValues)); } } } return new Pipeline(pipelineObject.getLong("contextEntityId"), pipelineObject.getString("contextEntityName"), pipelineObject.getBoolean("pipelineRoot"), pipelineObject.getLong("workspaceId"), pipelineObject.has("releaseId") && !pipelineObject.get("releaseId").equals(JSONNull.getInstance()) ? pipelineObject.getLong("releaseId") : null, taxonomies, fields, pipelineObject.has("ignoreTests") && !pipelineObject.get("ignoreTests").equals(JSONNull.getInstance()) ? pipelineObject.getBoolean("ignoreTests") : null); } @Override public PagedList<Release> queryReleases(String name, long workspaceId, int offset, int limit) { List<String> conditions = new LinkedList<>(); if (!StringUtils.isEmpty(name)) { conditions.add(QueryHelper.condition("name", "*" + name + "*")); } return getEntities(getEntityURI(URI_RELEASES, conditions, workspaceId, offset, limit, "name"), offset, new ReleaseEntityFactory()); } @Override public Release getRelease(long releaseId, long workspaceId) { int offset = 0; int limit = 1; List<String> conditions = new LinkedList<>(); conditions.add(QueryHelper.condition("id", String.valueOf(releaseId))); List<Release> releases = getEntities( getEntityURI(URI_RELEASES, conditions, workspaceId, offset, limit, null), offset, new ReleaseEntityFactory()).getItems(); if (releases.size() != 1) { if (releases.size() == 0) { return null; } if (releases.size() > 1) { throw new RequestErrorException("More than one releases returned for releaseId: " + releaseId + " in workspaceId: " + workspaceId); } } return releases.get(0); } @Override public PagedList<Workspace> queryWorkspaces(String name, int offset, int limit) { List<String> conditions = new LinkedList<>(); if (!StringUtils.isEmpty(name)) { conditions.add(QueryHelper.condition("name", "*" + name + "*")); } return getEntities(getEntityURI(URI_WORKSPACES, conditions, null, offset, limit, "name"), offset, new WorkspaceEntityFactory()); } @Override public List<Workspace> getWorkspaces(List<Long> workspaceIds) { if (workspaceIds == null || workspaceIds.size() == 0) { return new LinkedList<>(); } if (workspaceIds.size() > DEFAULT_LIMIT) { throw new IllegalArgumentException( "List of workspaceIds is too long. Only " + DEFAULT_LIMIT + " values are allowed."); } Set<Long> workspaceIdsSet = new LinkedHashSet<>(workspaceIds); StringBuilder conditionBuilder = new StringBuilder(); for (Long workspaceId : workspaceIdsSet) { if (conditionBuilder.length() > 0) { conditionBuilder.append("||"); } conditionBuilder.append("id=").append(workspaceId); } return getEntities(getEntityURI(URI_WORKSPACES, Collections.singletonList(conditionBuilder.toString()), null, DEFAULT_OFFSET, DEFAULT_LIMIT, null), DEFAULT_OFFSET, new WorkspaceEntityFactory()) .getItems(); } @Override public PagedList<Taxonomy> queryTaxonomies(String name, long workspaceId, int offset, int limit) { List<String> conditions = new LinkedList<>(); conditions.add("!category={null}"); if (!StringUtils.isEmpty(name)) { conditions.add("(" + QueryHelper.condition("name", "*" + name + "*") + "||" + QueryHelper.conditionRef("category", "name", "*" + name + "*") + ")"); } return getEntities(getEntityURI(URI_TAXONOMY_NODES, conditions, workspaceId, offset, limit, null), offset, new TaxonomyEntityFactory()); } @Override public List<Taxonomy> getTaxonomies(List<Long> taxonomyIds, long workspaceId) { if (taxonomyIds == null || taxonomyIds.size() == 0) { return new LinkedList<>(); } if (taxonomyIds.size() > DEFAULT_LIMIT) { throw new IllegalArgumentException( "List of taxonomyIds is too long. Only " + DEFAULT_LIMIT + " values are allowed."); } Set<Long> taxonomyIdsSet = new LinkedHashSet<>(taxonomyIds); StringBuilder conditionBuilder = new StringBuilder(); for (Long taxonomyId : taxonomyIdsSet) { if (conditionBuilder.length() > 0) { conditionBuilder.append("||"); } conditionBuilder.append("id=").append(taxonomyId); } return getEntities( getEntityURI(URI_TAXONOMY_NODES, Collections.singletonList(conditionBuilder.toString()), workspaceId, DEFAULT_OFFSET, DEFAULT_LIMIT, null), DEFAULT_OFFSET, new TaxonomyEntityFactory()).getItems(); } @Override public PagedList<ListItem> queryListItems(String logicalListName, String name, long workspaceId, int offset, int limit) { List<String> conditions = new LinkedList<>(); if (!StringUtils.isEmpty(name)) { conditions.add(QueryHelper.condition("name", "*" + name + "*")); } if (!StringUtils.isEmpty(logicalListName)) { conditions.add(QueryHelper.conditionRef("list_root", "logical_name", logicalListName)); } return getEntities(getEntityURI(URI_LIST_ITEMS, conditions, workspaceId, offset, limit, null), offset, new ListItemEntityFactory()); } @Override public List<ListItem> getListItems(List<String> itemIds, long workspaceId) { if (itemIds == null || itemIds.size() == 0) { return new LinkedList<>(); } if (itemIds.size() > DEFAULT_LIMIT) { throw new IllegalArgumentException( "List of itemIds is too long. Only " + DEFAULT_LIMIT + " values are allowed."); } Set<String> itemIdsSet = new LinkedHashSet<>(itemIds); StringBuilder conditionBuilder = new StringBuilder(); for (String itemId : itemIdsSet) { if (conditionBuilder.length() > 0) { conditionBuilder.append("||"); } conditionBuilder.append("id=").append(itemId); } return getEntities(getEntityURI(URI_LIST_ITEMS, Collections.singletonList(conditionBuilder.toString()), workspaceId, DEFAULT_OFFSET, DEFAULT_LIMIT, null), DEFAULT_OFFSET, new ListItemEntityFactory()) .getItems(); } @Override public List<FieldMetadata> getFieldsMetadata(long workspaceId) { List<FieldMetadata> ret = new LinkedList<>(); List<String> conditions = new LinkedList<>(); conditions.add(QueryHelper.condition("entity_name", "pipeline_node")); //loading all metadata fields PagedList<FieldMetadata> allFieldMetadata = getEntities( getEntityURI(URI_METADATA_FIELDS, conditions, workspaceId, DEFAULT_OFFSET, DEFAULT_LIMIT, null), DEFAULT_OFFSET, new FieldMetadataFactory()); //filtering metadata fields to only values which we are interested in for (FieldMetadata fieldMetadata : allFieldMetadata.getItems()) { if (fieldMetadata.isValid()) { ret.add(fieldMetadata); } } return ret; } private long postTestResult(ByteArrayEntity entity, boolean skipErrors) { HttpPost request = new HttpPost(createSharedSpaceInternalApiUri(URI_TEST_RESULT_PUSH, skipErrors)); request.setHeader(HTTP.CONTENT_ENCODING, CONTENT_ENCODING_GZIP); request.setEntity(entity); HttpResponse response = null; try { response = execute(request); int statusCode = response.getStatusLine().getStatusCode(); if (statusCode == HttpStatus.SC_SERVICE_UNAVAILABLE) { throw new TemporarilyUnavailableException("Service not available"); } if (statusCode != HttpStatus.SC_ACCEPTED) { throw createRequestException("Test result post failed", response); } String json = IOUtils.toString(response.getEntity().getContent()); JSONObject jsonObject = JSONObject.fromObject(json); return jsonObject.getLong("id"); } catch (java.io.FileNotFoundException e) { throw new FileNotFoundException("Cannot find test result file.", e); } catch (IOException e) { throw new RequestErrorException("Cannot post test results to MQM.", e); } finally { HttpClientUtils.closeQuietly(response); } } @Override public JSONObject postEntities(Long workspaceId, String entityCollectionName, String entityJson) { URI uri = getEntityURI(entityCollectionName, null, null, workspaceId, null, null, null); HttpPost request = new HttpPost(uri); request.setHeader(HTTP.CONTENT_TYPE, "application/json"); request.setHeader("Accept", "application/json"); request.setEntity(new StringEntity(entityJson, ContentType.APPLICATION_JSON)); HttpResponse response; try { response = execute(request); int statusCode = response.getStatusLine().getStatusCode(); if (statusCode == HttpStatus.SC_SERVICE_UNAVAILABLE) { throw new TemporarilyUnavailableException("Service not available"); } if (statusCode != HttpStatus.SC_CREATED) { throw createRequestException("Post failed", response); } String json = IOUtils.toString(response.getEntity().getContent()); return JSONObject.fromObject(json); } catch (IOException e) { throw new RequestErrorException("Cannot post entities", e); } } public List<Entity> getEntities(Long workspaceId, String entityCollectionName, Collection<String> conditions, Collection<String> fields) { List<Entity> result = new ArrayList<>(); int limit = MAX_GET_LIMIT; int offset = DEFAULT_OFFSET; boolean fetchedAll = false; while (!fetchedAll) { URI uri = getEntityURI(entityCollectionName, conditions, fields, workspaceId, offset, limit, null); PagedList<Entity> found = getEntities(uri, offset, new GeneralEntityFactory()); result.addAll(found.getItems()); offset = offset + found.getItems().size(); fetchedAll = found.getItems().isEmpty() || found.getTotalCount() == 0 || found.getTotalCount() == result.size(); } return result; } @Override public JSONObject updateEntity(Long workspaceId, String entityCollectionName, long entityId, String entityJson) { URI uri = getEntityIdURI(entityCollectionName, entityId, workspaceId); return updateEntities(uri, entityJson); } @Override public JSONObject updateEntities(Long workspaceId, String entityCollectionName, String entityJson) { URI uri = getEntityURI(entityCollectionName, null, null, workspaceId, null, null, null); return updateEntities(uri, entityJson); } private JSONObject updateEntities(URI uri, String entityJson) { HttpPut request = new HttpPut(uri); request.setHeader(HTTP.CONTENT_TYPE, "application/json"); request.setHeader("Accept", "application/json"); request.setEntity(new StringEntity(entityJson, ContentType.APPLICATION_JSON)); HttpResponse response; try { response = execute(request); int statusCode = response.getStatusLine().getStatusCode(); if (statusCode == HttpStatus.SC_SERVICE_UNAVAILABLE) { throw new TemporarilyUnavailableException("Service not available"); } if (statusCode != HttpStatus.SC_OK) { throw createRequestException("Put failed", response); } String json = IOUtils.toString(response.getEntity().getContent()); return JSONObject.fromObject(json); } catch (IOException e) { throw new RequestErrorException("Cannot put entities to MQM.", e); } } @Override public PagedList<Entity> deleteEntities(Long workspaceId, String entityCollectionName, Collection<Long> entitiesIds) { //query="id=3011||id=3012" if (entitiesIds == null || entitiesIds.isEmpty()) { return null; } List<String> idConditions = new ArrayList<>(); for (Long id : entitiesIds) { idConditions.add(QueryHelper.condition("id", id)); } String finalCondition = StringUtils.join(idConditions, "||"); URI uri = getEntityURI(entityCollectionName, Arrays.asList(finalCondition), null, workspaceId, null, null, null); PagedList<Entity> tests = deleteEntities(uri, new GeneralEntityFactory()); return tests; } private ByteArrayEntity createGZipEntity(InputStream inputStream) { try { ByteArrayOutputStream arr = new ByteArrayOutputStream(); OutputStream zipper = new GZIPOutputStream(arr); byte[] buffer = new byte[1024]; int len; while ((len = inputStream.read(buffer)) > 0) { zipper.write(buffer, 0, len); } try { inputStream.close(); } catch (IOException ioe) { logger.warning("failed to close silently input stream of tests result"); } try { zipper.close(); } catch (IOException ioe) { logger.warning("failed to close silently zip stream of tests result"); } return new ByteArrayEntity(arr.toByteArray(), ContentType.APPLICATION_XML); } catch (IOException ex) { throw new RequestErrorException("Failed to create GZip entity.", ex); } } @Override public boolean putEvents(String eventsJSON) { HttpPut request; HttpResponse response = null; boolean result = true; try { request = new HttpPut(createSharedSpaceInternalApiUri(URI_PUT_EVENTS)); request.setEntity( new GzipCompressingEntity(new StringEntity(eventsJSON, ContentType.APPLICATION_JSON))); response = execute(request); if (response.getStatusLine().getStatusCode() == HttpStatus.SC_TEMPORARY_REDIRECT) { // ad-hoc handling as requested by Jenkins Insight team HttpClientUtils.closeQuietly(response); login(); response = execute(request); } if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) { logger.severe( "put request failed while sending events: " + response.getStatusLine().getStatusCode()); result = false; } } catch (Exception e) { logger.severe("put request failed while sending events: " + e.getClass().getName()); result = false; } finally { HttpClientUtils.closeQuietly(response); } return result; } @Override public boolean postLogs(long workspaceId, String selfIdentity, String ciJobId, String ciBuildId, InputStream inputStream, Long contentLength) { HttpPost request; HttpResponse response = null; boolean result = true; try { request = new HttpPost( createWorkspaceInternalApiUriMap(URI_POST_LOGS, workspaceId, selfIdentity, ciJobId, ciBuildId)); request.setHeader(UNCOMPRESSED_CONTENT_LENGTH, String.valueOf(contentLength)); request.setEntity(this.createGZipEntity(inputStream)); response = execute(request); int statusCode = response.getStatusLine().getStatusCode(); if (statusCode == HttpStatus.SC_SERVICE_UNAVAILABLE || statusCode == HttpStatus.SC_INTERNAL_SERVER_ERROR) { result = false; logger.severe("post request failed while sending logs: " + statusCode); } else if (statusCode != HttpStatus.SC_OK) { logger.severe("Logs post failed" + statusCode); throw createRequestException("Logs post failed", response); } logger.info(IOUtils.toString(response.getEntity().getContent(), "UTF-8")); } catch (IOException e) { throw new RequestErrorException("Cannot post logs to MQM.", e); } finally { HttpClientUtils.closeQuietly(response); } return result; } @Override public boolean postCoverageReports(String selfIdentity, String ciJobId, String ciBuildId, InputStream inputStream, Long contentLength, String reportType) { HttpPut request; HttpResponse response = null; boolean result = true; try { request = new HttpPut(createSharedSpaceInternalApiUri(URI_POST_COVERAGE_REPORTS, selfIdentity, ciJobId, ciBuildId, reportType)); request.setEntity(new GzipCompressingEntity(new InputStreamEntity(inputStream))); response = execute(request); int statusCode = response.getStatusLine().getStatusCode(); if (statusCode == HttpStatus.SC_SERVICE_UNAVAILABLE || statusCode == HttpStatus.SC_INTERNAL_SERVER_ERROR) { result = false; logger.severe("post request failed while sending coverage reports: " + statusCode); } else if (statusCode != HttpStatus.SC_OK) { logger.severe("coverage reports post failed" + statusCode); throw createRequestException("coverage reports post failed", response); } logger.info(IOUtils.toString(response.getEntity().getContent(), "UTF-8")); } catch (IOException e) { throw new RequestErrorException("Cannot post coverage reports to MQM.", e); } finally { HttpClientUtils.closeQuietly(response); } return result; } @Override public String getAbridgedTasks(AbridgedTaskPluginInfo info) { HttpGet request; HttpResponse response = null; String responseBody; try { request = new HttpGet(createSharedSpaceInternalApiUri(URI_GET_ABRIDGED_TASKS, info.getSelfIdentity(), info.getSelfType(), info.getSelfLocation(), info.getApiVersion(), info.getSdkVersion(), info.getPluginVersion(), info.getOctaneUser(), info.getCiServerUser(), info.isSuspend())); response = execute(request); responseBody = IOUtils.toString(response.getEntity().getContent(), "UTF-8"); if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) { return responseBody; } else { if (response.getStatusLine().getStatusCode() == HttpStatus.SC_REQUEST_TIMEOUT) { logger.config("expected timeout disconnection on retrieval of abridged tasks"); return null; } else if (response.getStatusLine().getStatusCode() == HttpStatus.SC_UNAUTHORIZED) { throw new AuthenticationException(); } else if (response.getStatusLine().getStatusCode() == HttpStatus.SC_NOT_FOUND) { throw new TemporarilyUnavailableException(""); } else { logger.info("unexpected response; status: " + response.getStatusLine().getStatusCode() + "; content: " + responseBody); throw new ServerException("Server failed to process the request with status " + response.getStatusLine().getStatusCode()); } } } catch (IOException ioe) { logger.severe("failed to retrieve abridged tasks: " + ioe.getMessage()); throw new RequestErrorException(ioe); } finally { HttpClientUtils.closeQuietly(response); } } @Override public int putAbridgedResult(String selfIdentity, String taskId, String contentJSON) { HttpPut request; HttpResponse response = null; try { request = new HttpPut(createSharedSpaceInternalApiUri(URI_PUT_ABRIDGED_RESULT, selfIdentity, taskId)); request.setEntity( new GzipCompressingEntity(new StringEntity(contentJSON, ContentType.APPLICATION_JSON))); response = execute(request); return response.getStatusLine().getStatusCode(); } catch (Exception e) { logger.severe("failed to submit abridged task's result: " + e.getMessage()); throw new RuntimeException(e); } finally { HttpClientUtils.closeQuietly(response); } } private static class ListItemEntityFactory extends AbstractEntityFactory<ListItem> { @Override public ListItem doCreate(JSONObject entityObject) { JSONObject list_root = entityObject.optJSONObject("list_root"); if (list_root != null) { return new ListItem(entityObject.getString("id"), entityObject.getString("logical_name"), entityObject.getString("name"), doCreate(list_root)); } else { return new ListItem(entityObject.getString("id"), entityObject.getString("logical_name"), entityObject.getString("name"), null); } } } private static class TaxonomyEntityFactory extends AbstractEntityFactory<Taxonomy> { @Override public Taxonomy doCreate(JSONObject entityObject) { JSONObject taxonomy_root = entityObject.optJSONObject("category"); if (taxonomy_root != null) { return new Taxonomy(entityObject.getLong("id"), entityObject.getString("name"), doCreate(taxonomy_root)); } else { return new Taxonomy(entityObject.getLong("id"), entityObject.getString("name"), null); } } } private static class ReleaseEntityFactory extends AbstractEntityFactory<Release> { @Override public Release doCreate(JSONObject entityObject) { return new Release(entityObject.getLong("id"), entityObject.getString("name")); } } private static class GeneralEntityFactory extends AbstractEntityFactory<Entity> { @Override public Entity doCreate(JSONObject entityObject) { Entity entity = new Entity(entityObject); return entity; } } private static class WorkspaceEntityFactory extends AbstractEntityFactory<Workspace> { @Override public Workspace doCreate(JSONObject entityObject) { return new Workspace(entityObject.getLong("id"), entityObject.getString("name")); } } private static class FieldMetadataFactory extends AbstractEntityFactory<FieldMetadata> { @Override public FieldMetadata doCreate(JSONObject entityObject) { String name = null; String label = null; String logicalName = null; boolean multiple = false; boolean isExtensible = false; int order = 0; int mandatoryElementsFound = 0; if (entityObject.has("field_features")) { JSONArray fieldFeaturesArray = entityObject.getJSONArray("field_features"); for (int i = 0; i < fieldFeaturesArray.size(); i++) { JSONObject fieldFeature = fieldFeaturesArray.getJSONObject(i); if (fieldFeature.has("name") && fieldFeature.getString("name").equals("pipeline_tagging") && fieldFeature.has("extensibility") && fieldFeature.has("order")) { order = fieldFeature.getInt("order"); isExtensible = fieldFeature.getBoolean("extensibility"); mandatoryElementsFound++; break; } } } if (entityObject.has("name") && entityObject.has("label")) { name = entityObject.getString("name"); label = entityObject.getString("label"); mandatoryElementsFound++; } if (entityObject.has("field_type_data")) { JSONObject fieldTypeData = entityObject.getJSONObject("field_type_data"); if (fieldTypeData.has("multiple") && fieldTypeData.has("targets")) { multiple = fieldTypeData.getBoolean("multiple"); JSONArray targets = fieldTypeData.getJSONArray("targets"); for (int i = 0; i < targets.size(); i++) { if (targets.getJSONObject(i).has("logical_name")) { logicalName = targets.getJSONObject(i).getString("logical_name"); mandatoryElementsFound++; } } } } if (mandatoryElementsFound != 3) { return new FieldMetadata(null, null, null, false, false, 0); } return new FieldMetadata(name, label, logicalName, isExtensible, multiple, order); } } static abstract class AbstractEntityFactory<E> implements EntityFactory<E> { @Override public E create(String json) { JSONObject jsonObject = JSONObject.fromObject(json); return doCreate(jsonObject); } public abstract E doCreate(JSONObject entityObject); } }