
com.capitalone.dashboard.client.story.StoryDataClientImpl Maven / Gradle / Ivy
/*************************DA-BOARD-LICENSE-START*********************************
* Copyright 2014 CapitalOne, LLC.
*
* 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.
*************************DA-BOARD-LICENSE-END*********************************/
package com.capitalone.dashboard.client.story;
import com.atlassian.jira.rest.client.api.domain.BasicProject;
import com.atlassian.jira.rest.client.api.domain.Issue;
import com.atlassian.jira.rest.client.api.domain.IssueField;
import com.atlassian.jira.rest.client.api.domain.IssueType;
import com.atlassian.jira.rest.client.api.domain.User;
import com.capitalone.dashboard.datafactory.jira.JiraDataFactoryImpl;
import com.capitalone.dashboard.model.Feature;
import com.capitalone.dashboard.model.FeatureStatus;
import com.capitalone.dashboard.repository.FeatureCollectorRepository;
import com.capitalone.dashboard.repository.FeatureRepository;
import com.capitalone.dashboard.util.ClientUtil;
import com.capitalone.dashboard.util.FeatureCollectorConstants;
import com.capitalone.dashboard.util.CoreFeatureSettings;
import com.capitalone.dashboard.util.FeatureSettings;
import com.capitalone.dashboard.util.FeatureWidgetQueries;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/**
* This is the primary implemented/extended data collector for the feature
* collector. This will get data from the source system, but will grab the
* majority of needed data and aggregate it in a single, flat MongoDB collection
* for consumption.
*
* @author kfk884
*
*/
public class StoryDataClientImpl extends FeatureDataClientSetupImpl implements StoryDataClient {
private static final Logger LOGGER = LoggerFactory.getLogger(StoryDataClientImpl.class);
private final CoreFeatureSettings coreFeatureSettings;
private final FeatureSettings featureSettings;
private final FeatureWidgetQueries featureWidgetQueries;
private final FeatureRepository featureRepo;
private final static ClientUtil TOOLS = new ClientUtil();
/**
* Extends the constructor from the super class.
*/
public StoryDataClientImpl(CoreFeatureSettings coreFeatureSettings,
FeatureSettings featureSettings, FeatureRepository featureRepository,
FeatureCollectorRepository featureCollectorRepository) {
super(featureSettings, featureRepository, featureCollectorRepository);
LOGGER.debug("Constructing data collection for the feature widget, story-level data...");
this.coreFeatureSettings = coreFeatureSettings;
this.featureSettings = featureSettings;
this.featureRepo = featureRepository;
this.featureWidgetQueries = new FeatureWidgetQueries(this.featureSettings);
}
/**
* Updates the MongoDB with a JSONArray received from the source system
* back-end with story-based data.
*
* @param currentPagedJiraRs
* A list response of Jira issues from the source system
*/
@Override
@SuppressWarnings({ "PMD.ExcessiveMethodLength", "PMD.NcssMethodCount", "PMD.NPathComplexity",
"PMD.AvoidDeeplyNestedIfStmts" })
protected void updateMongoInfo(List currentPagedJiraRs) {
LOGGER.debug("Size of paged Jira response: ", currentPagedJiraRs.size());
if ((currentPagedJiraRs != null) && !(currentPagedJiraRs.isEmpty())) {
Iterator globalResponseItr = currentPagedJiraRs.iterator();
while (globalResponseItr.hasNext()) {
try {
/*
* Initialize DOMs
*/
Feature feature = new Feature();
Issue issue = globalResponseItr.next();
Iterable rawFields = issue.getFields();
HashMap fields = new LinkedHashMap();
if (rawFields != null) {
Iterator itr = rawFields.iterator();
while (itr.hasNext()) {
IssueField field = itr.next();
fields.put(field.getId(), field);
}
}
IssueType issueType = issue.getIssueType();
BasicProject project = issue.getProject();
User assignee = issue.getAssignee();
String status = this.toCanonicalFeatureStatus(issue.getStatus().getName());
String estimate = String.valueOf(issue.getTimeTracking()
.getRemainingEstimateMinutes());
IssueField epic = fields.get(super.featureSettings.getJiraEpicIdFieldName());
String changeDate = issue.getUpdateDate().toString();
IssueField sprint = fields.get(super.featureSettings
.getJiraSprintDataFieldName());
/*
* Removing any existing entities where they exist in the
* local DB store...
*/
@SuppressWarnings("unused")
boolean deleted = this.removeExistingEntity(TOOLS.sanitizeResponse(issue
.getId()));
if (TOOLS.sanitizeResponse(issueType.getName()).equalsIgnoreCase(
super.featureSettings.getJiraIssueTypeId())) {
// collectorId
feature.setCollectorId(featureCollectorRepository
.findByName(FeatureCollectorConstants.JIRA).getId());
// ID
feature.setsId(TOOLS.sanitizeResponse(issue.getId()));
// sNumber
feature.setsNumber(TOOLS.sanitizeResponse(issue.getKey()));
// sName
feature.setsName(TOOLS.sanitizeResponse(issue.getSummary()));
// sStatus
feature.setsStatus(TOOLS.sanitizeResponse(status));
// sState
feature.setsState(TOOLS.sanitizeResponse(status));
// sEstimate,
feature.setsEstimate(TOOLS.toHours(estimate));
// sChangeDate
feature.setChangeDate(TOOLS.toCanonicalDate(TOOLS
.sanitizeResponse(changeDate)));
// IsDeleted - does not exist for Jira
feature.setIsDeleted("False");
// sProjectID
feature.setsProjectID(TOOLS.sanitizeResponse(project.getKey()));
// sProjectName
feature.setsProjectName(TOOLS.sanitizeResponse(project.getName()));
// sProjectBeginDate - does not exist in Jira
feature.setsProjectBeginDate("");
// sProjectEndDate - does not exist in Jira
feature.setsProjectEndDate("");
// sProjectChangeDate - does not exist for this asset
// level in Jira
feature.setsProjectChangeDate("");
// sProjectState - does not exist in Jira
feature.setsProjectState("");
// sProjectIsDeleted - does not exist in Jira
feature.setsProjectIsDeleted("False");
// sProjectPath - does not exist in Jira
feature.setsProjectPath("");
/*
* Epic Data - Note: Will only grab first epic
* associated
*/
String blankLiteral = "";
if ((epic.getValue() != null)
&& !(epic.getValue().toString().isEmpty() && !blankLiteral
.equalsIgnoreCase(TOOLS.sanitizeResponse(epic.getValue())))) {
List epicData = this.getEpicData(TOOLS.sanitizeResponse(epic
.getValue()));
if (!epicData.isEmpty()) {
Iterable rawEpicFields = epicData.get(0).getFields();
HashMap epicFields = new LinkedHashMap();
if (rawEpicFields != null) {
Iterator itr = rawFields.iterator();
while (itr.hasNext()) {
IssueField epicField = itr.next();
epicFields.put(epicField.getId(), epicField);
}
}
String epicId = epicData.get(0).getId().toString();
String epicNumber = epicData.get(0).getKey().toString();
String epicName = epicData.get(0).getSummary().toString();
String epicBeginDate = epicData.get(0).getCreationDate().toString();
IssueField epicEndDate = epicFields.get("duedate");
String epicStatus = epicData.get(0).getStatus().getName();
// sEpicID
feature.setsEpicID(TOOLS.sanitizeResponse(epicId));
// sEpicNumber
feature.setsEpicNumber(TOOLS.sanitizeResponse(epicNumber));
// sEpicName
feature.setsEpicName(TOOLS.sanitizeResponse(epicName));
// sEpicBeginDate - mapped to create date
if ((epicBeginDate != null) && !(epicBeginDate.isEmpty())) {
feature.setsEpicBeginDate(TOOLS.toCanonicalDate(TOOLS
.sanitizeResponse(epicBeginDate)));
} else {
feature.setsEpicBeginDate("");
}
// sEpicEndDate
if (epicEndDate != null) {
feature.setsEpicEndDate(TOOLS.toCanonicalDate(TOOLS
.sanitizeResponse(epicEndDate.getValue())));
} else {
feature.setsEpicEndDate("");
}
// sEpicAssetState
if (epicStatus != null) {
feature.setsEpicAssetState(TOOLS.sanitizeResponse(epicStatus));
} else {
feature.setsEpicAssetState("");
}
} else {
feature.setsEpicID("");
feature.setsEpicNumber("");
feature.setsEpicName("");
feature.setsEpicBeginDate("");
feature.setsEpicEndDate("");
feature.setsEpicType("");
feature.setsEpicAssetState("");
feature.setsEpicChangeDate("");
}
} else {
feature.setsEpicID("");
feature.setsEpicNumber("");
feature.setsEpicName("");
feature.setsEpicBeginDate("");
feature.setsEpicEndDate("");
feature.setsEpicType("");
feature.setsEpicAssetState("");
feature.setsEpicChangeDate("");
}
// sEpicType - does not exist in jira
feature.setsEpicType("");
// sEpicChangeDate - does not exist in jira
feature.setsEpicChangeDate("");
// sEpicIsDeleted - does not exist in Jira
feature.setsEpicIsDeleted("False");
/*
* Sprint Data
*/
if (sprint.getValue() != null) {
Map canonicalSprint = TOOLS
.toCanonicalSprintPOJO(sprint.getValue().toString());
// sSprintID
if (canonicalSprint.get("id") != null) {
feature.setsSprintID(canonicalSprint.get("id").toString());
} else {
feature.setsSprintID("");
}
// sSprintName
if (canonicalSprint.get("name") != null) {
feature.setsSprintName(canonicalSprint.get("name").toString());
} else {
feature.setsSprintName("");
}
// sSprintBeginDate
if (canonicalSprint.get("startDate") != null) {
feature.setsSprintBeginDate(TOOLS.toCanonicalDate(canonicalSprint
.get("startDate").toString()));
} else {
feature.setsSprintBeginDate("");
}
// sSprintEndDate
if (canonicalSprint.get("endDate") != null) {
feature.setsSprintEndDate(TOOLS.toCanonicalDate(canonicalSprint
.get("endDate").toString()));
} else {
feature.setsSprintEndDate("");
}
// sSprintAssetState
if (canonicalSprint.get("state") != null) {
feature.setsSprintAssetState(canonicalSprint.get("state")
.toString());
} else {
feature.setsSprintAssetState("");
}
} else {
feature.setsSprintID("");
feature.setsSprintName("");
feature.setsSprintBeginDate("");
feature.setsSprintEndDate("");
feature.setsSprintAssetState("");
}
// sSprintChangeDate - does not exist in Jira
feature.setsSprintChangeDate("");
// sSprintIsDeleted - does not exist in Jira
feature.setsSprintIsDeleted("False");
// sTeamID
feature.setsTeamID(TOOLS.sanitizeResponse(project.getId()));
// sTeamName
feature.setsTeamName(TOOLS.sanitizeResponse(project.getName()));
// sTeamChangeDate - not able to retrieve at this asset
// level
// from Jira
feature.setsTeamChangeDate("");
// sTeamAssetState
feature.setsTeamAssetState("");
// sTeamIsDeleted
feature.setsTeamIsDeleted("False");
if (assignee != null) {
// sOwnersID
List assigneeKey = new ArrayList();
// sOwnersShortName
// sOwnersUsername
List assigneeName = new ArrayList();
if (!assignee.getName().isEmpty() && (assignee.getName() != null)) {
assigneeKey.add(TOOLS.sanitizeResponse(assignee.getName()));
assigneeName.add(TOOLS.sanitizeResponse(assignee.getName()));
} else {
assigneeKey = new ArrayList();
assigneeName = new ArrayList();
}
feature.setsOwnersShortName(assigneeName);
feature.setsOwnersUsername(assigneeName);
feature.setsOwnersID(assigneeKey);
// sOwnersFullName
List assigneeDisplayName = new ArrayList();
if (!assignee.getDisplayName().isEmpty()
&& (assignee.getDisplayName() != null)) {
assigneeDisplayName.add(TOOLS.sanitizeResponse(assignee
.getDisplayName()));
} else {
assigneeDisplayName.add("");
}
feature.setsOwnersFullName(assigneeDisplayName);
} else {
feature.setsOwnersUsername(new ArrayList());
feature.setsOwnersShortName(new ArrayList());
feature.setsOwnersID(new ArrayList());
feature.setsOwnersFullName(new ArrayList());
}
// sOwnersState - does not exist in Jira at this level
List assigneeActive = new ArrayList();
assigneeActive.add("Active");
feature.setsOwnersState(assigneeActive);
// sOwnersChangeDate - does not exist in Jira
feature.setsOwnersChangeDate(TOOLS.toCanonicalList(new ArrayList()));
// sOwnersIsDeleted - does not exist in Jira
feature.setsOwnersIsDeleted(TOOLS.toCanonicalList(new ArrayList()));
}
// Saving back to MongoDB
featureRepo.save(feature);
} catch (ArrayIndexOutOfBoundsException | IllegalArgumentException e) {
LOGGER.error(
"Unexpected error caused while mapping data from source system to local data store:\n"
+ e.getMessage() + " : " + e.getCause(), e);
}
}
}
}
/**
* ETL for converting any number of custom Jira statuses to a reduced list
* of generally logical statuses used by Hygieia
*
* @param nativeStatus
* The status label as native to Jira
* @return A Hygieia-canonical status, as defined by a Core enum
*/
private String toCanonicalFeatureStatus(String nativeStatus) {
List todo = coreFeatureSettings.getTodoStatuses();
List doing = coreFeatureSettings.getDoingStatuses();
List done = coreFeatureSettings.getDoneStatuses();
boolean alreadySet = false;
String canonicalStatus = null;
if (!nativeStatus.isEmpty()) {
// Map todo
for (String status : todo) {
if (status.equalsIgnoreCase(nativeStatus)) {
canonicalStatus = FeatureStatus.BACKLOG.getStatus();
alreadySet = true;
break;
}
}
// Map doing
if (!alreadySet) {
for (String status : doing) {
if (status.equalsIgnoreCase(nativeStatus)) {
canonicalStatus = FeatureStatus.IN_PROGRESS.getStatus();
alreadySet = true;
break;
}
}
}
// Map done
if (!alreadySet) {
for (String status : done) {
if (status.equalsIgnoreCase(nativeStatus)) {
canonicalStatus = FeatureStatus.DONE.getStatus();
alreadySet = true;
break;
}
}
}
if (!alreadySet) {
canonicalStatus = FeatureStatus.BACKLOG.getStatus();
}
} else {
canonicalStatus = FeatureStatus.BACKLOG.getStatus();
}
return canonicalStatus;
}
/**
* Retrieves the related Epic to the current issue from Jira. To make this
* thread-safe, please synchronize and lock on the result of this method.
*
* @param epicKey
* A given Epic Key
* @return A valid Jira Epic issue object
*/
protected List getEpicData(String epicKey) {
List epicRs = new ArrayList();
JiraDataFactoryImpl jiraConnect = null;
String jiraCredentials = this.featureSettings.getJiraCredentials();
String jiraBaseUrl = this.featureSettings.getJiraBaseUrl();
String query = this.featureWidgetQueries.getEpicQuery(epicKey, "epic");
String proxyUri = null;
String proxyPort = null;
try {
if (!this.featureSettings.getJiraProxyUrl().isEmpty()
&& (this.featureSettings.getJiraProxyPort() != null)) {
proxyUri = this.featureSettings.getJiraProxyUrl();
proxyPort = this.featureSettings.getJiraProxyPort();
}
jiraConnect = new JiraDataFactoryImpl(jiraCredentials, jiraBaseUrl, proxyUri, proxyPort);
jiraConnect.setQuery(query);
epicRs = jiraConnect.getJiraIssues();
} catch (Exception e) {
LOGGER.error(
"There was a problem connecting to Jira while getting sub-relationships to epics:"
+ e.getMessage() + " : " + e.getCause(), e);
epicRs = new ArrayList();
} finally {
jiraConnect.destroy();
}
return epicRs;
}
/**
* Explicitly updates queries for the source system, and initiates the
* update to MongoDB from those calls.
*/
public void updateStoryInformation() {
super.objClass = Feature.class;
super.returnDate = this.featureSettings.getDeltaStartDate();
if (super.getMaxChangeDate() != null) {
super.returnDate = super.getMaxChangeDate();
}
super.returnDate = getChangeDateMinutePrior(super.returnDate);
super.returnDate = TOOLS.toNativeDate(super.returnDate);
String queryName = this.featureSettings.getStoryQuery();
super.query = this.featureWidgetQueries.getStoryQuery(returnDate,
super.featureSettings.getJiraIssueTypeId(), queryName);
LOGGER.debug("updateStoryInformation: queryName = " + query + "; query = " + query);
updateObjectInformation();
}
/**
* Validates current entry and removes new entry if an older item exists in
* the repo
*
* @param localId repository item ID (not the precise mongoID)
*/
protected Boolean removeExistingEntity(String localId) {
boolean deleted = false;
try {
List listOfFeature = featureRepo.getFeatureIdById(localId);
for (Feature f : listOfFeature) {
featureRepo.delete(f.getId());
deleted = true;
LOGGER.debug("Removed existing entities that will be replaced by newer instances");
}
} catch (IndexOutOfBoundsException ioobe) {
LOGGER.debug("Nothing matched the redundancy checking from the database", ioobe);
} catch (Exception e) {
LOGGER.error("There was a problem validating the redundancy of the data model", e);
}
return deleted;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy