diff --git a/api/src/main/java/com/capitalone/dashboard/service/FeatureServiceImpl.java b/api/src/main/java/com/capitalone/dashboard/service/FeatureServiceImpl.java index 139629bd3b..c6c21f2af2 100644 --- a/api/src/main/java/com/capitalone/dashboard/service/FeatureServiceImpl.java +++ b/api/src/main/java/com/capitalone/dashboard/service/FeatureServiceImpl.java @@ -1,443 +1,340 @@ package com.capitalone.dashboard.service; -import com.capitalone.dashboard.model.*; +import com.capitalone.dashboard.model.Collector; +import com.capitalone.dashboard.model.CollectorItem; +import com.capitalone.dashboard.model.CollectorType; +import com.capitalone.dashboard.model.Component; +import com.capitalone.dashboard.model.DataResponse; +import com.capitalone.dashboard.model.Feature; +import com.capitalone.dashboard.model.QScopeOwner; import com.capitalone.dashboard.repository.CollectorRepository; import com.capitalone.dashboard.repository.ComponentRepository; import com.capitalone.dashboard.repository.FeatureRepository; import com.capitalone.dashboard.util.SuperFeatureComparator; +import com.google.common.collect.Iterables; import com.mysema.query.BooleanBuilder; - import org.bson.types.ObjectId; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; +import org.springframework.util.StringUtils; +import javax.xml.bind.DatatypeConverter; import java.util.ArrayList; import java.util.Calendar; import java.util.Collections; import java.util.List; -import java.util.ListIterator; -import java.util.NoSuchElementException; import java.util.TimeZone; -import javax.xml.bind.DatatypeConverter; - @Service public class FeatureServiceImpl implements FeatureService { - private final ComponentRepository componentRepository; - private final FeatureRepository featureRepository; - private final CollectorRepository collectorRepository; - - /** - * Default autowired constructor for repositories - * - * @param componentRepository - * Repository containing components used by the UI (populated by - * UI) - * @param collectorRepository - * Repository containing all registered collectors - * @param featureRepository - * Repository containing all features - */ - @Autowired - public FeatureServiceImpl(ComponentRepository componentRepository, - CollectorRepository collectorRepository, FeatureRepository featureRepository) { - this.componentRepository = componentRepository; - this.featureRepository = featureRepository; - this.collectorRepository = collectorRepository; - } - - /** - * Retrieves a single story based on a back-end story number - * - * @param componentId - * The ID of the related UI component that will reference - * collector item content from this collector - * @param storyNumber - * A back-end story ID used by a source system - * - * @return A data response list of type Feature containing a single story - */ - @Override - @SuppressWarnings("PMD.AvoidCatchingNPE") // TODO:... - public DataResponse> getStory(ObjectId componentId, String storyNumber) { - Component component = componentRepository.findOne(componentId); - DataResponse> rs; - try { - CollectorItem item = component.getCollectorItems().get(CollectorType.ScopeOwner).get(0); - QScopeOwner team = new QScopeOwner("team"); - BooleanBuilder builder = new BooleanBuilder(); - - builder.and(team.collectorItemId.eq(item.getId())); - - // Get one story based on story number, based on component - List story = featureRepository.getStoryByNumber(storyNumber); - - Collector collector = collectorRepository.findOne(item.getCollectorId()); - rs = new DataResponse<>(story, collector.getLastExecuted()); - } catch (NullPointerException e) { - long x = 0; - Feature f = new Feature(); - List l = new ArrayList(); - l.add(f); - rs = new DataResponse<>(l, x); - } - - return rs; - } - - /** - * Retrieves all stories for a given team and their current sprint - * - * @param componentId - * The ID of the related UI component that will reference - * collector item content from this collector - * @param teamId - * A given scope-owner's source-system ID - * - * @return A data response list of type Feature containing all features for - * the given team and current sprint - */ - @SuppressWarnings("PMD.AvoidCatchingNPE") // TODO: Avoid catching NullPointerException; consider removing the cause of the NPE - @Override - public DataResponse> getRelevantStories(ObjectId componentId, String teamId) { - Component component = componentRepository.findOne(componentId); - DataResponse> rs; - try { - CollectorItem item = component.getCollectorItems().get(CollectorType.ScopeOwner).get(0); - QScopeOwner team = new QScopeOwner("team"); - BooleanBuilder builder = new BooleanBuilder(); - - builder.and(team.collectorItemId.eq(item.getId())); - - // Get teamId first from available collector item, based on - // component - List relevantStories = featureRepository.queryByOrderBySStatusDesc(teamId, - getCurrentISODateTime()); - - Collector collector = collectorRepository.findOne(item.getCollectorId()); - - rs = new DataResponse<>(relevantStories, collector.getLastExecuted()); - } catch (NullPointerException e) { - long x = 0; - Feature f = new Feature(); - List l = new ArrayList(); - l.add(f); - rs = new DataResponse<>(l, x); - } - return rs; - } - - /** - * Retrieves all unique super features and their total sub feature estimates - * for a given team and their current sprint - * - * @param componentId - * The ID of the related UI component that will reference - * collector item content from this collector - * @param teamId - * A given scope-owner's source-system ID - * - * @return A data response list of type Feature containing the unique - * features plus their sub features' estimates associated to the - * current sprint and team - */ - @SuppressWarnings("PMD.AvoidCatchingNPE") // TODO: Avoid catching NullPointerException; consider removing the cause of the NPE - @Override - public DataResponse> getFeatureEstimates(ObjectId componentId, String teamId) { - Component component = componentRepository.findOne(componentId); - CollectorItem item = component.getCollectorItems().get(CollectorType.ScopeOwner).get(0); - QScopeOwner team = new QScopeOwner("team"); - BooleanBuilder builder = new BooleanBuilder(); - - builder.and(team.collectorItemId.eq(item.getId())); - - // Get teamId first from available collector item, based on component - List relevantFeatureEstimates = featureRepository - .getInProgressFeaturesEstimatesByTeamId(teamId, getCurrentISODateTime()); - Collections.sort(relevantFeatureEstimates, new SuperFeatureComparator()); - - List relevantSuperFeatureEstimates = new ArrayList(); - String lastEpicID = ""; - int lineTotalEstimate = 0; - try { - for (ListIterator iter = relevantFeatureEstimates.listIterator(); iter - .hasNext();) { - Feature f = new Feature(); - Feature tempRs = iter.next(); - - if (!tempRs.getsEpicID().isEmpty()) { - try { - if (tempRs.getsEpicID().equalsIgnoreCase(lastEpicID)) { - try { - lineTotalEstimate += Integer.valueOf((tempRs.getsEstimate())); - } catch (NumberFormatException | ArrayIndexOutOfBoundsException - | NullPointerException e) { - lineTotalEstimate += 0; - } - - try { - relevantSuperFeatureEstimates.get( - relevantSuperFeatureEstimates.size() - 1).setsEstimate( - Integer.toString(lineTotalEstimate)); - } catch (ArrayIndexOutOfBoundsException | NullPointerException e) { - relevantSuperFeatureEstimates.get(0).setsEstimate( - Integer.toString(lineTotalEstimate)); - } - } else { - lastEpicID = tempRs.getsEpicID(); - lineTotalEstimate = 0; - try { - lineTotalEstimate += Integer.valueOf((tempRs.getsEstimate())); - } catch (NumberFormatException | ArrayIndexOutOfBoundsException - | NullPointerException e) { - lineTotalEstimate += 0; - } - - f.setId(tempRs.getId()); - f.setsEpicID(tempRs.getsEpicID()); - f.setsEpicNumber(tempRs.getsEpicNumber()); - f.setsEpicName(tempRs.getsEpicName()); - f.setsEstimate(Integer.toString(lineTotalEstimate)); - - relevantSuperFeatureEstimates.add(f); - } - } catch (ArrayIndexOutOfBoundsException | NullPointerException e) { - // Error case - this is an unexpected scenario - relevantSuperFeatureEstimates.add(f); - } - } - } - } catch (NoSuchElementException nsee) { - Feature f = new Feature(); - relevantSuperFeatureEstimates.add(f); - } - - Collector collector = collectorRepository.findOne(item.getCollectorId()); - - return new DataResponse<>(relevantSuperFeatureEstimates, collector.getLastExecuted()); - } - - /** - * Retrieves estimate total of all features in the current sprint and for - * the current team. - * - * @param componentId - * The ID of the related UI component that will reference - * collector item content from this collector - * @param teamId - * A given scope-owner's source-system ID - * - * @return A data response list of type Feature containing the total - * estimate number for all features - */ - @SuppressWarnings("PMD.AvoidCatchingNPE") // TODO: Avoid catching NullPointerException; consider removing the cause of the NPE - @Override - public DataResponse> getTotalEstimate(ObjectId componentId, String teamId) { - Component component = componentRepository.findOne(componentId); - CollectorItem item = component.getCollectorItems().get(CollectorType.ScopeOwner).get(0); - QScopeOwner team = new QScopeOwner("team"); - BooleanBuilder builder = new BooleanBuilder(); - - builder.and(team.collectorItemId.eq(item.getId())); - - // Get teamId first from available collector item, based on component - List storyEstimates = featureRepository.getSprintBacklogTotal(teamId, - getCurrentISODateTime()); - - List cumulativeEstimate = new ArrayList(); - Feature f = new Feature(); - int lineTotalEstimate = 0; - try { - for (ListIterator iter = storyEstimates.listIterator(); iter.hasNext();) { - Feature tempRs = iter.next(); - - if (!tempRs.getsEstimate().isEmpty()) { - try { - lineTotalEstimate += Integer.parseInt(tempRs.getsEstimate()); - } catch (NumberFormatException | ArrayIndexOutOfBoundsException - | NullPointerException e) { - lineTotalEstimate += 0; - } - } - } - } catch (NoSuchElementException nsee) { - // Do nothing - } - f.setsEstimate(Integer.toString(lineTotalEstimate)); - cumulativeEstimate.add(f); - - Collector collector = collectorRepository.findOne(item.getCollectorId()); - - return new DataResponse<>(cumulativeEstimate, collector.getLastExecuted()); - } - - /** - * Retrieves estimate in-progress of all features in the current sprint and - * for the current team. - * - * @param componentId - * The ID of the related UI component that will reference - * collector item content from this collector - * @param teamId - * A given scope-owner's source-system ID - * - * @return A data response list of type Feature containing the in-progress - * estimate number for all features - */ - @SuppressWarnings("PMD.AvoidCatchingNPE") // TODO: Avoid catching NullPointerException; consider removing the cause of the NPE - @Override - public DataResponse> getInProgressEstimate(ObjectId componentId, String teamId) { - Component component = componentRepository.findOne(componentId); - CollectorItem item = component.getCollectorItems().get(CollectorType.ScopeOwner).get(0); - QScopeOwner team = new QScopeOwner("team"); - BooleanBuilder builder = new BooleanBuilder(); - - builder.and(team.collectorItemId.eq(item.getId())); - - // Get teamId first from available collector item, based on component - List storyEstimates = featureRepository.getSprintBacklogInProgress(teamId, - getCurrentISODateTime()); - - List cumulativeEstimate = new ArrayList(); - Feature f = new Feature(); - int lineTotalEstimate = 0; - try { - for (ListIterator iter = storyEstimates.listIterator(); iter.hasNext();) { - Feature tempRs = iter.next(); - - if (!tempRs.getsEstimate().isEmpty()) { - try { - lineTotalEstimate += Integer.parseInt(tempRs.getsEstimate()); - } catch (NumberFormatException | ArrayIndexOutOfBoundsException - | NullPointerException e) { - lineTotalEstimate += 0; - } - } - } - } catch (NoSuchElementException nsee) { - // Do nothing - } - f.setsEstimate(Integer.toString(lineTotalEstimate)); - cumulativeEstimate.add(f); - - Collector collector = collectorRepository.findOne(item.getCollectorId()); - - return new DataResponse<>(cumulativeEstimate, collector.getLastExecuted()); - } - - /** - * Retrieves estimate done of all features in the current sprint and for the - * current team. - * - * @param componentId - * The ID of the related UI component that will reference - * collector item content from this collector - * @param teamId - * A given scope-owner's source-system ID - * - * @return A data response list of type Feature containing the done estimate - * number for all features - */ - @SuppressWarnings("PMD.AvoidCatchingNPE") // TODO: Avoid catching NullPointerException; consider removing the cause of the NPE - @Override - public DataResponse> getDoneEstimate(ObjectId componentId, String teamId) { - Component component = componentRepository.findOne(componentId); - CollectorItem item = component.getCollectorItems().get(CollectorType.ScopeOwner).get(0); - QScopeOwner team = new QScopeOwner("team"); - BooleanBuilder builder = new BooleanBuilder(); - - builder.and(team.collectorItemId.eq(item.getId())); - - // Get teamId first from available collector item, based on component - List storyEstimates = featureRepository.getSprintBacklogDone(teamId, - getCurrentISODateTime()); - - List cumulativeEstimate = new ArrayList(); - Feature f = new Feature(); - int lineTotalEstimate = 0; - try { - for (ListIterator iter = storyEstimates.listIterator(); iter.hasNext();) { - Feature tempRs = iter.next(); - - if (!tempRs.getsEstimate().isEmpty()) { - try { - lineTotalEstimate += Integer.parseInt(tempRs.getsEstimate()); - } catch (NumberFormatException | ArrayIndexOutOfBoundsException - | NullPointerException e) { - lineTotalEstimate += 0; - } - } - } - } catch (NoSuchElementException nsee) { - // Do nothing - } - f.setsEstimate(Integer.toString(lineTotalEstimate)); - cumulativeEstimate.add(f); - - Collector collector = collectorRepository.findOne(item.getCollectorId()); - - return new DataResponse<>(cumulativeEstimate, collector.getLastExecuted()); - } - - /** - * Retrieves the current sprint's detail for a given team. - * - * @param componentId - * The ID of the related UI component that will reference - * collector item content from this collector - * @param teamId - * A given scope-owner's source-system ID - * - * @return A data response list of type Feature containing several relevant - * sprint fields for the current team's sprint - */ - @SuppressWarnings("PMD.AvoidCatchingNPE") // TODO: Avoid catching NullPointerException; consider removing the cause of the NPE - @Override - public DataResponse> getCurrentSprintDetail(ObjectId componentId, String teamId) { - Component component = componentRepository.findOne(componentId); - CollectorItem item = component.getCollectorItems().get(CollectorType.ScopeOwner).get(0); - QScopeOwner team = new QScopeOwner("team"); - BooleanBuilder builder = new BooleanBuilder(); - - builder.and(team.collectorItemId.eq(item.getId())); - - // Get teamId first from available collector item, based on component - List sprintResponse = featureRepository.getCurrentSprintDetail(teamId, - getCurrentISODateTime()); - - List sprintDetail = new ArrayList(); - Feature f = new Feature(); - int i = 0; - try { - for (ListIterator iter = sprintResponse.listIterator(); i < 1; i++) { - Feature tempRs = iter.next(); - f.setsSprintID(tempRs.getsSprintID()); - f.setsSprintName(tempRs.getsSprintName()); - f.setsSprintBeginDate(tempRs.getsSprintBeginDate()); - f.setsSprintEndDate(tempRs.getsSprintEndDate()); - sprintDetail.add(f); - } - } catch (NoSuchElementException | NumberFormatException | ArrayIndexOutOfBoundsException - | NullPointerException e) { - sprintDetail.add(f); - } - - Collector collector = collectorRepository.findOne(item.getCollectorId()); - - return new DataResponse<>(sprintDetail, collector.getLastExecuted()); - } - - /** - * Retrieves the current system time stamp in ISO date time format. Because - * this is not using SimpleTimeFormat, this should be thread safe. - * - * @return A string representation of the current date time stamp in ISO - * format from the current time zone - */ - private String getCurrentISODateTime() { - String currentISODateTime = DatatypeConverter.printDateTime(Calendar.getInstance(TimeZone - .getTimeZone("UTC"))); - return currentISODateTime; - } + private final ComponentRepository componentRepository; + private final FeatureRepository featureRepository; + private final CollectorRepository collectorRepository; + + private enum Status { + TOTAL, DONE, InProgress + } + + /** + * Default autowired constructor for repositories + * + * @param componentRepository Repository containing components used by the UI (populated by + * UI) + * @param collectorRepository Repository containing all registered collectors + * @param featureRepository Repository containing all features + */ + @Autowired + public FeatureServiceImpl(ComponentRepository componentRepository, + CollectorRepository collectorRepository, FeatureRepository featureRepository) { + this.componentRepository = componentRepository; + this.featureRepository = featureRepository; + this.collectorRepository = collectorRepository; + } + + /** + * Retrieves a single story based on a back-end story number + * + * @param componentId The ID of the related UI component that will reference + * collector item content from this collector + * @param storyNumber A back-end story ID used by a source system + * @return A data response list of type Feature containing a single story + */ + @Override + public DataResponse> getStory(ObjectId componentId, String storyNumber) { + Component component = componentRepository.findOne(componentId); + if ((component == null) || CollectionUtils.isEmpty(component.getCollectorItems()) || + CollectionUtils.isEmpty(component.getCollectorItems().get(CollectorType.ScopeOwner)) || + (component.getCollectorItems().get(CollectorType.ScopeOwner).get(0) == null)) { + return getEmptyDataResponse(); + } + + CollectorItem item = component.getCollectorItems().get(CollectorType.ScopeOwner).get(0); + + QScopeOwner team = new QScopeOwner("team"); + BooleanBuilder builder = new BooleanBuilder(); + builder.and(team.collectorItemId.eq(item.getId())); + + // Get one story based on story number, based on component + List story = featureRepository.getStoryByNumber(storyNumber); + Collector collector = collectorRepository.findOne(item.getCollectorId()); + return new DataResponse<>(story, collector.getLastExecuted()); + } + + private DataResponse> getEmptyDataResponse() { + Feature f = new Feature(); + List l = new ArrayList<>(); + l.add(f); + return new DataResponse<>(l, 0); + } + + /** + * Retrieves all stories for a given team and their current sprint + * + * @param componentId The ID of the related UI component that will reference + * collector item content from this collector + * @param teamId A given scope-owner's source-system ID + * @return A data response list of type Feature containing all features for + * the given team and current sprint + */ + @Override + public DataResponse> getRelevantStories(ObjectId componentId, String teamId) { + Component component = componentRepository.findOne(componentId); + if ((component == null) || CollectionUtils.isEmpty(component.getCollectorItems()) || + CollectionUtils.isEmpty(component.getCollectorItems().get(CollectorType.ScopeOwner)) || + (component.getCollectorItems().get(CollectorType.ScopeOwner).get(0) == null)) { + return getEmptyDataResponse(); + } + + CollectorItem item = component.getCollectorItems().get(CollectorType.ScopeOwner).get(0); + + + QScopeOwner team = new QScopeOwner("team"); + BooleanBuilder builder = new BooleanBuilder(); + builder.and(team.collectorItemId.eq(item.getId())); + + // Get teamId first from available collector item, based on + // component + List relevantStories = featureRepository.queryByOrderBySStatusDesc(teamId, + getCurrentISODateTime()); + + Collector collector = collectorRepository.findOne(item.getCollectorId()); + + return new DataResponse<>(relevantStories, collector.getLastExecuted()); + } + + /** + * Retrieves all unique super features and their total sub feature estimates + * for a given team and their current sprint + * + * @param componentId The ID of the related UI component that will reference + * collector item content from this collector + * @param teamId A given scope-owner's source-system ID + * @return A data response list of type Feature containing the unique + * features plus their sub features' estimates associated to the + * current sprint and team + */ + @Override + public DataResponse> getFeatureEstimates(ObjectId componentId, String teamId) { + Component component = componentRepository.findOne(componentId); + + if ((component == null) || CollectionUtils.isEmpty(component.getCollectorItems()) || + CollectionUtils.isEmpty(component.getCollectorItems().get(CollectorType.ScopeOwner)) || + (component.getCollectorItems().get(CollectorType.ScopeOwner).get(0) == null)) { + return getEmptyDataResponse(); + } + + CollectorItem item = component.getCollectorItems().get(CollectorType.ScopeOwner).get(0); + QScopeOwner team = new QScopeOwner("team"); + BooleanBuilder builder = new BooleanBuilder(); + builder.and(team.collectorItemId.eq(item.getId())); + + // Get teamId first from available collector item, based on component + List relevantFeatureEstimates = featureRepository + .getInProgressFeaturesEstimatesByTeamId(teamId, getCurrentISODateTime()); + Collections.sort(relevantFeatureEstimates, new SuperFeatureComparator()); + + List relevantSuperFeatureEstimates = new ArrayList<>(); + String lastEpicID = ""; + int lineTotalEstimate = 0; + + for (Feature tempRs : relevantFeatureEstimates) { + if (StringUtils.isEmpty(tempRs.getsEpicID())) continue; + + if (tempRs.getsEpicID().equalsIgnoreCase(lastEpicID)) { + + lineTotalEstimate += Integer.valueOf((tempRs.getsEstimate())); + Iterables.getLast(relevantSuperFeatureEstimates); + + if (!CollectionUtils.isEmpty(relevantSuperFeatureEstimates)) { + Iterables.getLast(relevantSuperFeatureEstimates).setsEstimate( + Integer.toString(lineTotalEstimate)); + } + + } else { + lastEpicID = tempRs.getsEpicID(); + lineTotalEstimate += Integer.valueOf((tempRs.getsEstimate())); + Feature f = new Feature(); + f.setId(tempRs.getId()); + f.setsEpicID(tempRs.getsEpicID()); + f.setsEpicNumber(tempRs.getsEpicNumber()); + f.setsEpicName(tempRs.getsEpicName()); + f.setsEstimate(Integer.toString(lineTotalEstimate)); + relevantSuperFeatureEstimates.add(f); + } + } + Collector collector = collectorRepository.findOne(item.getCollectorId()); + return new DataResponse<>(relevantSuperFeatureEstimates, collector.getLastExecuted()); + } + + + private DataResponse> getEstimate(ObjectId componentId, String teamId, Status status) { + Component component = componentRepository.findOne(componentId); + if ((component == null) || CollectionUtils.isEmpty(component.getCollectorItems()) || + CollectionUtils.isEmpty(component.getCollectorItems().get(CollectorType.ScopeOwner)) || + (component.getCollectorItems().get(CollectorType.ScopeOwner).get(0) == null)) { + return getEmptyDataResponse(); + } + + CollectorItem item = component.getCollectorItems().get(CollectorType.ScopeOwner).get(0); + QScopeOwner team = new QScopeOwner("team"); + BooleanBuilder builder = new BooleanBuilder(); + + builder.and(team.collectorItemId.eq(item.getId())); + + // Get teamId first from available collector item, based on component + List storyEstimates; + switch (status) { + case TOTAL: + storyEstimates = featureRepository.getSprintBacklogTotal(teamId, + getCurrentISODateTime()); + break; + + case DONE: + storyEstimates = featureRepository.getSprintBacklogDone(teamId, + getCurrentISODateTime()); + + break; + + case InProgress: + storyEstimates = featureRepository.getSprintBacklogInProgress(teamId, + getCurrentISODateTime()); + break; + + default: + storyEstimates = new ArrayList<>(); + + } + + List cumulativeEstimate = new ArrayList<>(); + Feature f = new Feature(); + int lineTotalEstimate = 0; + for (Feature tempRs : storyEstimates) { + if (StringUtils.isEmpty(tempRs.getsEstimate())) continue; + lineTotalEstimate += Integer.parseInt(tempRs.getsEstimate()); + } + f.setsEstimate(Integer.toString(lineTotalEstimate)); + cumulativeEstimate.add(f); + Collector collector = collectorRepository.findOne(item.getCollectorId()); + return new DataResponse<>(cumulativeEstimate, collector.getLastExecuted()); + } + + /** + * Retrieves estimate total of all features in the current sprint and for + * the current team. + * + * @param componentId The ID of the related UI component that will reference + * collector item content from this collector + * @param teamId A given scope-owner's source-system ID + * @return A data response list of type Feature containing the total + * estimate number for all features + */ + @Override + public DataResponse> getTotalEstimate(ObjectId componentId, String teamId) { + return getEstimate(componentId, teamId, Status.TOTAL); + } + + /** + * Retrieves estimate in-progress of all features in the current sprint and + * for the current team. + * + * @param componentId The ID of the related UI component that will reference + * collector item content from this collector + * @param teamId A given scope-owner's source-system ID + * @return A data response list of type Feature containing the in-progress + * estimate number for all features + */ + @Override + public DataResponse> getInProgressEstimate(ObjectId componentId, String teamId) { + return getEstimate(componentId, teamId, Status.InProgress); + } + + /** + * Retrieves estimate done of all features in the current sprint and for the + * current team. + * + * @param componentId The ID of the related UI component that will reference + * collector item content from this collector + * @param teamId A given scope-owner's source-system ID + * @return A data response list of type Feature containing the done estimate + * number for all features + */ + @Override + public DataResponse> getDoneEstimate(ObjectId componentId, String teamId) { + return getEstimate(componentId, teamId, Status.DONE); + } + + /** + * Retrieves the current sprint's detail for a given team. + * + * @param componentId The ID of the related UI component that will reference + * collector item content from this collector + * @param teamId A given scope-owner's source-system ID + * @return A data response list of type Feature containing several relevant + * sprint fields for the current team's sprint + */ + @Override + public DataResponse> getCurrentSprintDetail(ObjectId componentId, String teamId) { + Component component = componentRepository.findOne(componentId); + if ((component == null) || CollectionUtils.isEmpty(component.getCollectorItems()) || + CollectionUtils.isEmpty(component.getCollectorItems().get(CollectorType.ScopeOwner)) || + (component.getCollectorItems().get(CollectorType.ScopeOwner).get(0) == null)) { + return getEmptyDataResponse(); + } + + CollectorItem item = component.getCollectorItems().get(CollectorType.ScopeOwner).get(0); + QScopeOwner team = new QScopeOwner("team"); + BooleanBuilder builder = new BooleanBuilder(); + + builder.and(team.collectorItemId.eq(item.getId())); + + // Get teamId first from available collector item, based on component + List sprintResponse = featureRepository.getCurrentSprintDetail(teamId, + getCurrentISODateTime()); + + List sprintDetail = new ArrayList<>(); + Feature f = new Feature(); + for (Feature tempRs : sprintResponse) { + f.setsSprintID(tempRs.getsSprintID()); + f.setsSprintName(tempRs.getsSprintName()); + f.setsSprintBeginDate(tempRs.getsSprintBeginDate()); + f.setsSprintEndDate(tempRs.getsSprintEndDate()); + sprintDetail.add(f); + } + Collector collector = collectorRepository.findOne(item.getCollectorId()); + return new DataResponse<>(sprintDetail, collector.getLastExecuted()); + } + + /** + * Retrieves the current system time stamp in ISO date time format. Because + * this is not using SimpleTimeFormat, this should be thread safe. + * + * @return A string representation of the current date time stamp in ISO + * format from the current time zone + */ + private String getCurrentISODateTime() { + return DatatypeConverter.printDateTime(Calendar.getInstance(TimeZone + .getTimeZone("UTC"))); + } } diff --git a/versionone-feature-collector/src/main/java/com/capitalone/dashboard/client/BaseClient.java b/versionone-feature-collector/src/main/java/com/capitalone/dashboard/client/BaseClient.java deleted file mode 100644 index 787b003978..0000000000 --- a/versionone-feature-collector/src/main/java/com/capitalone/dashboard/client/BaseClient.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.capitalone.dashboard.client; - -import com.capitalone.dashboard.util.ClientUtil; -import org.json.simple.JSONObject; - -public class BaseClient { - - - - protected String getJSONDateString(JSONObject obj, String field) { - return ClientUtil.toCanonicalDate(getJSONString(obj, field)); - } - - protected String getJSONString(JSONObject obj, String field) { - return ClientUtil.sanitizeResponse((String) obj.get(field)); - } -} diff --git a/versionone-feature-collector/src/main/java/com/capitalone/dashboard/client/StoryDataClient.java b/versionone-feature-collector/src/main/java/com/capitalone/dashboard/client/StoryDataClient.java deleted file mode 100644 index e1fda19c58..0000000000 --- a/versionone-feature-collector/src/main/java/com/capitalone/dashboard/client/StoryDataClient.java +++ /dev/null @@ -1,319 +0,0 @@ -package com.capitalone.dashboard.client; - -import com.capitalone.dashboard.datafactory.versionone.VersionOneDataFactoryImpl; -import com.capitalone.dashboard.misc.HygieiaException; -import com.capitalone.dashboard.model.Collector; -import com.capitalone.dashboard.model.Feature; -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.DateUtil; -import com.capitalone.dashboard.util.FeatureSettings; -import com.capitalone.dashboard.util.FeatureWidgetQueries; -import org.json.simple.JSONArray; -import org.json.simple.JSONObject; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.util.CollectionUtils; -import org.springframework.util.StringUtils; - -import java.util.ArrayList; -import java.util.List; - -/** - * 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 StoryDataClient extends BaseClient { - private static final Logger LOGGER = LoggerFactory.getLogger(StoryDataClient.class); - - private final FeatureSettings featureSettings; - private final FeatureWidgetQueries featureWidgetQueries; - private final FeatureCollectorRepository featureCollectorRepository; - private final FeatureRepository featureRepo; - private final VersionOneDataFactoryImpl vOneApi; - - /** - * Extends the constructor from the super class. - */ - public StoryDataClient(FeatureSettings featureSettings, FeatureRepository featureRepository, - FeatureCollectorRepository featureCollectorRepository, - VersionOneDataFactoryImpl vOneApi) { - LOGGER.debug("Constructing data collection for the feature widget, story-level data..."); - - this.featureSettings = featureSettings; - this.featureRepo = featureRepository; - this.featureCollectorRepository = featureCollectorRepository; - this.featureWidgetQueries = new FeatureWidgetQueries(this.featureSettings); - this.vOneApi = vOneApi; - } - - /** - * Updates the MongoDB with a JSONArray received from the source system - * back-end with story-based data. - * - * @param tmpMongoDetailArray - * A JSON response in JSONArray format from the source system - * @return - */ - @SuppressWarnings({ "unchecked", "PMD.ExcessiveMethodLength", "PMD.NPathComplexity" }) - protected void updateMongoInfo(JSONArray tmpMongoDetailArray) { - for (Object obj : tmpMongoDetailArray) { - JSONObject dataMainObj = (JSONObject) obj; - Feature feature = new Feature(); - - removeExistingEntity(getJSONString(dataMainObj, "_oid")); - - // collectorId - feature.setCollectorId(featureCollectorRepository - .findByName(FeatureCollectorConstants.VERSIONONE).getId()); - - // ID - feature.setsId(getJSONString(dataMainObj, "_oid")); - - // sNumber - feature.setsNumber(getJSONString(dataMainObj, "Number")); - - // sName - feature.setsName(getJSONString(dataMainObj, "Name")); - - // sStatus - feature.setsStatus(getJSONString(dataMainObj, "Status.Name")); - - // sState - feature.setsState(getJSONString(dataMainObj, "AssetState")); - - // sEstimate - feature.setsEstimate(getJSONString(dataMainObj, "Estimate")); - - // sChangeDate - feature.setChangeDate(getJSONDateString(dataMainObj, "ChangeDate")); - - // IsDeleted - feature.setIsDeleted(getJSONString(dataMainObj, "IsDeleted")); - - // sProjectID - JSONObject tmpObj = (JSONObject) dataMainObj.get("Scope.ID"); - if (tmpObj.containsKey("_oid")) { - feature.setsProjectID(getJSONString(tmpObj, "_oid")); - } - - // sProjectName - feature.setsProjectName(getJSONString(dataMainObj, "Scope.Name")); - - // sProjectBeginDate - feature.setsProjectBeginDate(getJSONDateString(dataMainObj, "Scope.BeginDate")); - - // sProjectEndDate - feature.setsProjectEndDate(getJSONDateString(dataMainObj, "Scope.EndDate")); - - // sProjectChangeDate - feature.setsProjectChangeDate(getJSONDateString(dataMainObj, "Scope.ChangeDate")); - - // sProjectState - feature.setsProjectState(getJSONString(dataMainObj, "Scope.AssetState")); - - // sProjectIsDeleted - feature.setsProjectIsDeleted(getJSONString(dataMainObj, "Scope.IsDeleted")); - - // sProjectPath - String projPath = feature.getsProjectName(); - List projList = (List) dataMainObj.get("Scope.ParentAndUp.Name"); - if (!CollectionUtils.isEmpty(projList)) { - for (String proj : projList) { - projPath = proj + "-->" + projPath; - } - projPath = "All-->" + projPath; - } else { - projPath = "All-->" + projPath; - } - feature.setsProjectPath(ClientUtil.sanitizeResponse(projPath)); - - // sEpicID - tmpObj = (JSONObject) dataMainObj.get("Super.ID"); - if (tmpObj.containsKey("_oid")) { - feature.setsEpicID(getJSONString(tmpObj, "_oid")); - } - - // sEpicNumber - feature.setsEpicNumber(getJSONString(dataMainObj, "Super.Number")); - - // sEpicName - feature.setsEpicName(getJSONString(dataMainObj, "Super.Name")); - - // sEpicBeginDate - feature.setsEpicBeginDate(getJSONDateString(dataMainObj, "Super.PlannedStart")); - - // sEpicEndDate - feature.setsEpicEndDate(getJSONDateString(dataMainObj, "Super.PlannedEnd")); - - // sEpicType - feature.setsEpicType(getJSONString(dataMainObj, "Super.Category.Name")); - - // sEpicAssetState - feature.setsEpicAssetState(getJSONString(dataMainObj, "Super.AssetState")); - - // sEpicChangeDate - feature.setsEpicChangeDate(getJSONDateString(dataMainObj, "Super.ChangeDate")); - - // sEpicIsDeleted - feature.setsEpicIsDeleted(getJSONString(dataMainObj, "Super.IsDeleted")); - - // sSprintID - tmpObj = (JSONObject) dataMainObj.get("Timebox.ID"); - feature.setsSprintID(getJSONString(tmpObj, "_oid")); - - // sSprintName - feature.setsSprintName(getJSONString(dataMainObj, "Timebox.Name")); - - // sSprintBeginDate - feature.setsSprintBeginDate(getJSONDateString(dataMainObj, "Timebox.BeginDate")); - - // sSprintEndDate - feature.setsSprintEndDate(getJSONDateString(dataMainObj, "Timebox.EndDate")); - - // sSprintAssetState - feature.setsSprintAssetState(getJSONString(dataMainObj, "Timebox.AssetState")); - - // sSprintChangeDate - feature.setsSprintChangeDate(getJSONDateString(dataMainObj, "Timebox.ChangeDate")); - - // sSprintIsDeleted - feature.setsSprintIsDeleted(getJSONString(dataMainObj, "Timebox.IsDeleted")); - - // sTeamID - tmpObj = (JSONObject) dataMainObj.get("Team.ID"); - feature.setsTeamID(getJSONString(tmpObj, "_oid")); - - // sTeamName - feature.setsTeamName(getJSONString(dataMainObj, "Team.Name")); - - // sTeamChangeDate - feature.setsTeamChangeDate(getJSONDateString(dataMainObj, "Team.ChangeDate")); - - // sTeamAssetState - feature.setsTeamAssetState(getJSONString(dataMainObj, "Team.AssetState")); - - // sTeamIsDeleted - feature.setsTeamIsDeleted(getJSONString(dataMainObj, "Team.IsDeleted")); - - // sOwnersID - List ownersIdList = new ArrayList<>(); - for (Object ownersID : (JSONArray) dataMainObj.get("Owners.ID")) { - ownersIdList.add(getJSONString((JSONObject) ownersID, "_oid")); - } - feature.setsOwnersID(ownersIdList); - - // sOwnersShortName - feature.setsOwnersShortName( - ClientUtil.toCanonicalList((List) dataMainObj.get("Owners.Nickname"))); - - // sOwnersFullName - feature.setsOwnersFullName( - ClientUtil.toCanonicalList((List) dataMainObj.get("Owners.Name"))); - - // sOwnersUsername - feature.setsOwnersUsername( - ClientUtil.toCanonicalList((List) dataMainObj.get("Owners.Username"))); - - // sOwnersState - feature.setsOwnersState(ClientUtil - .toCanonicalList((List) dataMainObj.get("Owners.AssetState"))); - - // sOwnersChangeDate - feature.setsOwnersChangeDate(ClientUtil - .toCanonicalList((List) dataMainObj.get("Owners.ChangeDate"))); - - // sOwnersIsDeleted - feature.setsOwnersIsDeleted( - ClientUtil.toCanonicalList((List) dataMainObj.get("Owners.IsDeleted"))); - - featureRepo.save(feature); - } - } - - /** - * Explicitly updates queries for the source system, and initiates the - * update to MongoDB from those calls. - */ - public void updateStoryInformation() throws HygieiaException { - String returnDate = this.featureSettings.getDeltaStartDate(); - if (!StringUtils.isEmpty(getMaxChangeDate())) { - returnDate = getMaxChangeDate(); - } - returnDate = DateUtil.getChangeDateMinutePrior(returnDate, - this.featureSettings.getScheduledPriorMin()); - String queryName = this.featureSettings.getStoryQuery(); - updateObjectInformation(featureWidgetQueries.getQuery(returnDate, queryName)); - } - - /** - * Validates current entry and removes new entry if an older item exists in - * the repo - * - * @param localId - * local repository item ID (not the precise mongoID) - */ - protected void removeExistingEntity(String localId) { - if (StringUtils.isEmpty(localId)) - return; - List listOfFeature = featureRepo.getFeatureIdById(localId); - - if (CollectionUtils.isEmpty(listOfFeature)) - return; - featureRepo.delete(listOfFeature); - } - - public String getMaxChangeDate() { - Collector col = featureCollectorRepository.findByName(FeatureCollectorConstants.VERSIONONE); - if (col == null) - return ""; - if (StringUtils.isEmpty(featureSettings.getDeltaStartDate())) - return ""; - - List response = featureRepo - .findTopByCollectorIdAndChangeDateGreaterThanOrderByChangeDateDesc(col.getId(), - featureSettings.getDeltaStartDate()); - if (!CollectionUtils.isEmpty(response)) - return response.get(0).getChangeDate(); - return ""; - } - - public void updateObjectInformation(String query) throws HygieiaException { - long start = System.nanoTime(); - int pageIndex = 0; - int pageSize = this.featureSettings.getPageSize(); - vOneApi.setPageSize(pageSize); - vOneApi.buildBasicQuery(query); - vOneApi.buildPagingQuery(0); - JSONArray outPutMainArray = vOneApi.getPagingQueryResponse(); - if (!CollectionUtils.isEmpty(outPutMainArray)) { - JSONArray tmpDetailArray = (JSONArray) outPutMainArray.get(0); - while (!CollectionUtils.isEmpty(tmpDetailArray)) { - updateMongoInfo(tmpDetailArray); - pageIndex = pageIndex + pageSize; - vOneApi.buildPagingQuery(pageIndex); - outPutMainArray = vOneApi.getPagingQueryResponse(); - if (outPutMainArray == null) { - LOGGER.info("FAILED: Script Completed with Error"); - throw new HygieiaException( - "FAILED: Nothing to update from VersionOne's response", - HygieiaException.NOTHING_TO_UPDATE); - } - tmpDetailArray = (JSONArray) outPutMainArray.get(0); - } - } else { - throw new HygieiaException( - "FAILED: FAILED: VersionOne response included unexpected JSON format", - HygieiaException.JSON_FORMAT_ERROR); - } - - double elapsedTime = (System.nanoTime() - start) / 1000000000.0; - LOGGER.info("Process took :" + elapsedTime + " seconds to update"); - } -} diff --git a/versionone-feature-collector/src/main/java/com/capitalone/dashboard/collector/BaseClient.java b/versionone-feature-collector/src/main/java/com/capitalone/dashboard/collector/BaseClient.java new file mode 100644 index 0000000000..a1bc7d2207 --- /dev/null +++ b/versionone-feature-collector/src/main/java/com/capitalone/dashboard/collector/BaseClient.java @@ -0,0 +1,160 @@ +package com.capitalone.dashboard.collector; + +import com.capitalone.dashboard.datafactory.versionone.VersionOneDataFactoryImpl; +import com.capitalone.dashboard.misc.HygieiaException; +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.util.CollectionUtils; +import org.springframework.util.StringUtils; +import org.stringtemplate.v4.ST; +import org.stringtemplate.v4.STGroupDir; + +import java.nio.ByteBuffer; +import java.nio.charset.CharacterCodingException; +import java.nio.charset.CharsetDecoder; +import java.nio.charset.StandardCharsets; +import java.util.List; +import java.util.stream.Collectors; + +public abstract class BaseClient { + + private static final Logger LOGGER = LoggerFactory.getLogger(StoryDataClient.class); + private final VersionOneDataFactoryImpl vOneApi; + private final FeatureSettings featureSettings; + + protected BaseClient(VersionOneDataFactoryImpl vOneApi, FeatureSettings featureSettings) { + this.vOneApi = vOneApi; + this.featureSettings = featureSettings; + } + + protected String getJSONString(JSONObject obj, String field) { + return sanitizeResponse((String) obj.get(field)); + } + + + public void updateObjectInformation(String query) throws HygieiaException { + long start = System.nanoTime(); + int pageIndex = 0; + int pageSize = this.featureSettings.getPageSize(); + vOneApi.setPageSize(pageSize); + vOneApi.setBasicQuery(query); + vOneApi.buildPagingQuery(0); + JSONArray outPutMainArray = vOneApi.getPagingQueryResponse(); + if (CollectionUtils.isEmpty(outPutMainArray)) + throw new HygieiaException( + "FAILED: FAILED: VersionOne response included unexpected JSON format", + HygieiaException.JSON_FORMAT_ERROR); + + JSONArray tmpDetailArray = (JSONArray) outPutMainArray.get(0); + while (!CollectionUtils.isEmpty(tmpDetailArray)) { + updateMongoInfo(tmpDetailArray); + pageIndex = pageIndex + pageSize; + vOneApi.buildPagingQuery(pageIndex); + outPutMainArray = vOneApi.getPagingQueryResponse(); + if (outPutMainArray == null) { + LOGGER.info("FAILED: Script Completed with Error"); + throw new HygieiaException( + "FAILED: Nothing to update from VersionOne's response", + HygieiaException.NOTHING_TO_UPDATE); + } + tmpDetailArray = (JSONArray) outPutMainArray.get(0); + } + double elapsedTime = (System.nanoTime() - start) / 1000000000.0; + LOGGER.info("Process took :" + elapsedTime + " seconds to update"); + } + + protected abstract void updateMongoInfo(JSONArray tmpDetailArray); + + protected abstract String getMaxChangeDate(); + + public VersionOneDataFactoryImpl getvOneApi() { + return vOneApi; + } + + public FeatureSettings getFeatureSettings() { + return featureSettings; + } + + /** + * Utility method used to sanitize / canonicalize a String-based response + * artifact from a source system. This will return a valid UTF-8 strings, or + * a "" (blank) response for any of the following cases: + * "NULL";"Null";"null";null;"" + * + * @param nativeRs The string response artifact retrieved from the source system + * to be sanitized + * @return A UTF-8 sanitized response + */ + public static String sanitizeResponse(String nativeRs) { + if (StringUtils.isEmpty(nativeRs)) return ""; + + byte[] utf8Bytes; + CharsetDecoder cs = StandardCharsets.UTF_8.newDecoder(); + + if ("null".equalsIgnoreCase(nativeRs)) return ""; + utf8Bytes = nativeRs.getBytes(StandardCharsets.UTF_8); + try { + cs.decode(ByteBuffer.wrap(utf8Bytes)); + return new String(utf8Bytes, StandardCharsets.UTF_8); + } catch (CharacterCodingException e) { + return "[INVALID NON UTF-8 ENCODING]"; + } + } + + + /** + * Canonicalizes a given JSONArray to a basic List object to avoid the use of JSON parsers. + * + * @param list A given JSONArray object response from the source system + * @return The sanitized, canonical List + */ + public static List toCanonicalList(List list) { + return list.stream().map(BaseClient::sanitizeResponse).collect(Collectors.toList()); + } + + + /** + * Retrieves source system queries based on the query name (without the file + * type) and a specified change date parameter. + * + * @param changeDatePara + * The change date specified from which to pull data with a given + * query template. + * @param queryName + * The source system query name (without the file type). + * @return A given source system query, in String format. + */ + public String getQuery(String changeDatePara, String queryName) { + ST st = (new STGroupDir(featureSettings.getQueryFolder(), '$', '$')).getInstanceOf(queryName); + st.add("changeDate", changeDatePara); + return st.render(); + } + + /** + * Retrieves source system history/trending queries based on the query name + * (without the file type) and other parameters. + * + * @param sprintStartDate + * The sprint start data in ISO format. + * @param sprintEndDate + * The sprint end data in ISO format. + * @param sprintDeltaDate + * The delta date in ISO format. + * @param queryName + * The source system query name (without the file type). + * @return A given historical source system query, in String format. + */ + public String getTrendingQuery(String sprintStartDate, + String sprintEndDate, String sprintDeltaDate, String queryName) { + ST st = (new STGroupDir(featureSettings.getQueryFolder(), '$', '$')).getInstanceOf(queryName); + st.add("sprintStartDate", sprintStartDate); + st.add("sprintEndDate", sprintEndDate); + st.add("sprintDeltaDate", sprintDeltaDate); + + return st.render(); + } + + +} diff --git a/versionone-feature-collector/src/main/java/com/capitalone/dashboard/collector/FeatureCollectorTask.java b/versionone-feature-collector/src/main/java/com/capitalone/dashboard/collector/FeatureCollectorTask.java index 349ff46586..01f316d2d4 100644 --- a/versionone-feature-collector/src/main/java/com/capitalone/dashboard/collector/FeatureCollectorTask.java +++ b/versionone-feature-collector/src/main/java/com/capitalone/dashboard/collector/FeatureCollectorTask.java @@ -1,8 +1,5 @@ package com.capitalone.dashboard.collector; -import com.capitalone.dashboard.client.ProjectDataClient; -import com.capitalone.dashboard.client.StoryDataClient; -import com.capitalone.dashboard.client.TeamDataClient; import com.capitalone.dashboard.datafactory.versionone.VersionOneDataFactoryImpl; import com.capitalone.dashboard.misc.HygieiaException; import com.capitalone.dashboard.model.FeatureCollector; @@ -12,7 +9,6 @@ import com.capitalone.dashboard.repository.ScopeRepository; import com.capitalone.dashboard.repository.ScopeOwnerRepository; import com.capitalone.dashboard.util.FeatureCollectorConstants; -import com.capitalone.dashboard.util.FeatureSettings; import org.codehaus.plexus.util.StringUtils; import org.slf4j.Logger; @@ -26,117 +22,109 @@ /** * Collects {@link FeatureCollector} data from feature content source system. - * - * @author KFK884 */ @Component public class FeatureCollectorTask extends CollectorTask { - private static final Logger LOGGER = LoggerFactory.getLogger(FeatureCollectorTask.class); - - private final FeatureRepository featureRepository; - private final ScopeOwnerRepository teamRepository; - private final ScopeRepository projectRepository; - private final FeatureCollectorRepository featureCollectorRepository; - private final FeatureSettings featureSettings; - private final VersionOneDataFactoryImpl v1Connection; - - /** - * Default constructor for the collector task. This will construct this - * collector task with all repository, scheduling, and settings - * configurations custom to this collector. - * - * @param taskScheduler - * A task scheduler artifact - * @param teamRepository - * The repository being use for feature collection - * @param featureSettings - * The settings being used for feature collection from the source - * system - * @throws HygieiaException - */ - @Autowired - public FeatureCollectorTask(TaskScheduler taskScheduler, FeatureRepository featureRepository, - ScopeOwnerRepository teamRepository, ScopeRepository projectRepository, - FeatureCollectorRepository featureCollectorRepository, FeatureSettings featureSettings) - throws HygieiaException { - super(taskScheduler, FeatureCollectorConstants.VERSIONONE); - this.featureCollectorRepository = featureCollectorRepository; - this.teamRepository = teamRepository; - this.projectRepository = projectRepository; - this.featureRepository = featureRepository; - this.featureSettings = featureSettings; - - if (StringUtils.isNotEmpty(featureSettings.getVersionOneProxyUrl()) - || StringUtils.isNotEmpty(featureSettings.getVersionOneBaseUri()) - || StringUtils.isNotEmpty(featureSettings.getVersionOneAccessToken())) { - this.v1Connection = connectToPersistentClient(); - } else { - throw new HygieiaException("FAILED: VersionOne connection properties are not valid", - HygieiaException.INVALID_CONFIGURATION); - } - } - - /** - * Accessor method for the collector prototype object - */ - @Override - public FeatureCollector getCollector() { - return FeatureCollector.prototype(); - } - - /** - * Accessor method for the collector repository - */ - @Override - public BaseCollectorRepository getCollectorRepository() { - return featureCollectorRepository; - } - - /** - * Accessor method for the current chronology setting, for the scheduler - */ - @Override - public String getCron() { - return featureSettings.getCron(); - } - - /** - * The collection action. This is the task which will run on a schedule to - * gather data from the feature content source system and update the - * repository with retrieved data. - */ - @Override - public void collect(FeatureCollector collector) { - LOGGER.info("Starting Feature collection..."); - - try { - TeamDataClient teamData = new TeamDataClient(this.featureCollectorRepository, - this.featureSettings, this.teamRepository, this.v1Connection); - - teamData.updateTeamInformation(); - - ProjectDataClient projectData = new ProjectDataClient(this.featureSettings, - this.projectRepository, this.featureCollectorRepository, this.v1Connection); - projectData.updateProjectInformation(); - - StoryDataClient storyData = new StoryDataClient(this.featureSettings, - this.featureRepository, this.featureCollectorRepository, this.v1Connection); - storyData.updateStoryInformation(); - } catch (HygieiaException he) { - LOGGER.error("Error in collecting Version One Data: [" + he.getErrorCode() + "] " - + he.getMessage()); - } - - LOGGER.info("Feature Data Collection Finished"); - - } - - private VersionOneDataFactoryImpl connectToPersistentClient() throws HygieiaException { - Map auth = new HashMap<>(); - auth.put("v1ProxyUrl", this.featureSettings.getVersionOneProxyUrl()); - auth.put("v1BaseUri", this.featureSettings.getVersionOneBaseUri()); - auth.put("v1AccessToken", this.featureSettings.getVersionOneAccessToken()); - - return new VersionOneDataFactoryImpl(auth); - } + private static final Logger LOGGER = LoggerFactory.getLogger(FeatureCollectorTask.class); + + private final FeatureRepository featureRepository; + private final ScopeOwnerRepository teamRepository; + private final ScopeRepository projectRepository; + private final FeatureCollectorRepository featureCollectorRepository; + private final FeatureSettings featureSettings; + private final VersionOneDataFactoryImpl v1Connection; + + /** + * Default constructor for the collector task. This will construct this + * collector task with all repository, scheduling, and settings + * configurations custom to this collector. + * + * @param taskScheduler A task scheduler artifact + * @param teamRepository The repository being use for feature collection + * @param featureSettings The settings being used for feature collection from the source + * system + * @throws HygieiaException + */ + @Autowired + public FeatureCollectorTask(TaskScheduler taskScheduler, FeatureRepository featureRepository, + ScopeOwnerRepository teamRepository, ScopeRepository projectRepository, + FeatureCollectorRepository featureCollectorRepository, FeatureSettings featureSettings) + throws HygieiaException { + super(taskScheduler, FeatureCollectorConstants.VERSIONONE); + this.featureCollectorRepository = featureCollectorRepository; + this.teamRepository = teamRepository; + this.projectRepository = projectRepository; + this.featureRepository = featureRepository; + this.featureSettings = featureSettings; + this.v1Connection = connectToPersistentClient(); + } + + /** + * Accessor method for the collector prototype object + */ + @Override + public FeatureCollector getCollector() { + return FeatureCollector.prototype(); + } + + /** + * Accessor method for the collector repository + */ + @Override + public BaseCollectorRepository getCollectorRepository() { + return featureCollectorRepository; + } + + /** + * Accessor method for the current chronology setting, for the scheduler + */ + @Override + public String getCron() { + return featureSettings.getCron(); + } + + /** + * The collection action. This is the task which will run on a schedule to + * gather data from the feature content source system and update the + * repository with retrieved data. + */ + @Override + public void collect(FeatureCollector collector) { + LOGGER.info("Starting Feature collection..."); + + try { + TeamDataClient teamData = new TeamDataClient(this.featureCollectorRepository, + this.featureSettings, this.teamRepository, this.v1Connection); + + teamData.updateTeamInformation(); + + ProjectDataClient projectData = new ProjectDataClient(this.featureSettings, + this.projectRepository, this.featureCollectorRepository, this.v1Connection); + projectData.updateProjectInformation(); + + StoryDataClient storyData = new StoryDataClient(this.featureSettings, + this.featureRepository, this.featureCollectorRepository, this.v1Connection); + storyData.updateStoryInformation(); + } catch (HygieiaException he) { + LOGGER.error("Error in collecting Version One Data: [" + he.getErrorCode() + "] " + + he.getMessage()); + } + + LOGGER.info("Feature Data Collection Finished"); + + } + + private VersionOneDataFactoryImpl connectToPersistentClient() throws HygieiaException { + Map auth = new HashMap<>(); + + if (StringUtils.isEmpty(featureSettings.getVersionOneAccessToken()) || StringUtils.isEmpty(featureSettings.getVersionOneBaseUri())) + throw new HygieiaException("FAILED: VersionOne connection properties are not valid", + HygieiaException.INVALID_CONFIGURATION); + + auth.put("v1ProxyUrl", this.featureSettings.getVersionOneProxyUrl()); + auth.put("v1BaseUri", this.featureSettings.getVersionOneBaseUri()); + auth.put("v1AccessToken", this.featureSettings.getVersionOneAccessToken()); + + return new VersionOneDataFactoryImpl(auth); + } } diff --git a/versionone-feature-collector/src/main/java/com/capitalone/dashboard/util/FeatureSettings.java b/versionone-feature-collector/src/main/java/com/capitalone/dashboard/collector/FeatureSettings.java similarity index 99% rename from versionone-feature-collector/src/main/java/com/capitalone/dashboard/util/FeatureSettings.java rename to versionone-feature-collector/src/main/java/com/capitalone/dashboard/collector/FeatureSettings.java index 93fc387785..dd7db82237 100644 --- a/versionone-feature-collector/src/main/java/com/capitalone/dashboard/util/FeatureSettings.java +++ b/versionone-feature-collector/src/main/java/com/capitalone/dashboard/collector/FeatureSettings.java @@ -14,7 +14,7 @@ * limitations under the License. *************************DA-BOARD-LICENSE-END*********************************/ -package com.capitalone.dashboard.util; +package com.capitalone.dashboard.collector; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; diff --git a/versionone-feature-collector/src/main/java/com/capitalone/dashboard/client/ProjectDataClient.java b/versionone-feature-collector/src/main/java/com/capitalone/dashboard/collector/ProjectDataClient.java similarity index 58% rename from versionone-feature-collector/src/main/java/com/capitalone/dashboard/client/ProjectDataClient.java rename to versionone-feature-collector/src/main/java/com/capitalone/dashboard/collector/ProjectDataClient.java index fa958835ff..728376f959 100644 --- a/versionone-feature-collector/src/main/java/com/capitalone/dashboard/client/ProjectDataClient.java +++ b/versionone-feature-collector/src/main/java/com/capitalone/dashboard/collector/ProjectDataClient.java @@ -1,22 +1,5 @@ -/************************* - * 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; + +package com.capitalone.dashboard.collector; import com.capitalone.dashboard.datafactory.versionone.VersionOneDataFactoryImpl; import com.capitalone.dashboard.misc.HygieiaException; @@ -24,11 +7,8 @@ import com.capitalone.dashboard.model.Scope; import com.capitalone.dashboard.repository.FeatureCollectorRepository; import com.capitalone.dashboard.repository.ScopeRepository; -import com.capitalone.dashboard.util.ClientUtil; -import com.capitalone.dashboard.util.FeatureCollectorConstants; import com.capitalone.dashboard.util.DateUtil; -import com.capitalone.dashboard.util.FeatureSettings; -import com.capitalone.dashboard.util.FeatureWidgetQueries; +import com.capitalone.dashboard.util.FeatureCollectorConstants; import org.bson.types.ObjectId; import org.json.simple.JSONArray; import org.json.simple.JSONObject; @@ -44,17 +24,13 @@ * 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 ProjectDataClient extends BaseClient { private static final Logger LOGGER = LoggerFactory.getLogger(ProjectDataClient.class); private final FeatureSettings featureSettings; - private final FeatureWidgetQueries featureWidgetQueries; private final ScopeRepository projectRepo; private final FeatureCollectorRepository featureCollectorRepository; - private final VersionOneDataFactoryImpl vOneApi; /** * Extends the constructor from the super class. @@ -62,13 +38,12 @@ public class ProjectDataClient extends BaseClient { public ProjectDataClient(FeatureSettings featureSettings, ScopeRepository projectRepository, FeatureCollectorRepository featureCollectorRepository, VersionOneDataFactoryImpl vOneApi) { - LOGGER.debug("Constructing data collection for the feature widget, story-level data..."); + super(vOneApi, featureSettings); + LOGGER.debug("Constructing data collection for the feature widget, story-level data..."); this.featureSettings = featureSettings; this.projectRepo = projectRepository; this.featureCollectorRepository = featureCollectorRepository; - this.featureWidgetQueries = new FeatureWidgetQueries(this.featureSettings); - this.vOneApi = vOneApi; } /** @@ -78,6 +53,7 @@ public ProjectDataClient(FeatureSettings featureSettings, ScopeRepository projec * @param tmpMongoDetailArray * A JSON response in JSONArray format from the source system */ + @Override @SuppressWarnings("unchecked") protected void updateMongoInfo(JSONArray tmpMongoDetailArray) { for (Object obj : tmpMongoDetailArray) { @@ -85,26 +61,26 @@ protected void updateMongoInfo(JSONArray tmpMongoDetailArray) { Scope scope = new Scope(); - removeExistingEntity(getJSONDateString(dataMainObj, "_oid")); + removeExistingEntity(getJSONString(dataMainObj, "_oid")); // collectorId scope.setCollectorId( featureCollectorRepository.findByName(FeatureCollectorConstants.VERSIONONE).getId()); // ID; - scope.setpId(getJSONDateString(dataMainObj, "_oid")); + scope.setpId(getJSONString(dataMainObj, "_oid")); // name; - scope.setName(getJSONDateString(dataMainObj, "Name")); + scope.setName(getJSONString(dataMainObj, "Name")); // beginDate; - scope.setBeginDate(getJSONDateString(dataMainObj, "BeginDate")); + scope.setBeginDate(getJSONString(dataMainObj, "BeginDate")); // endDate; - scope.setEndDate(getJSONDateString(dataMainObj, "EndDate")); + scope.setEndDate(getJSONString(dataMainObj, "EndDate")); // changeDate; - scope.setChangeDate(getJSONDateString(dataMainObj, "ChangeDate")); + scope.setChangeDate(getJSONString(dataMainObj, "ChangeDate")); // assetState; scope.setAssetState(getJSONString(dataMainObj, "AssetState")); @@ -123,12 +99,13 @@ protected void updateMongoInfo(JSONArray tmpMongoDetailArray) { } else { projPath = "All-->" + projPath; } - scope.setProjectPath(ClientUtil.sanitizeResponse(projPath)); + scope.setProjectPath(sanitizeResponse(projPath)); projectRepo.save(scope); } } + @Override public String getMaxChangeDate() { Collector col = featureCollectorRepository.findByName(FeatureCollectorConstants.VERSIONONE); if (col == null) @@ -138,7 +115,7 @@ public String getMaxChangeDate() { List response = projectRepo .findTopByCollectorIdAndChangeDateGreaterThanOrderByChangeDateDesc(col.getId(), - featureSettings.getDeltaStartDate()); + featureSettings.getDeltaStartDate()); if (!CollectionUtils.isEmpty(response)) return response.get(0).getChangeDate(); return ""; @@ -152,42 +129,9 @@ public void updateProjectInformation() throws HygieiaException { returnDate = DateUtil.getChangeDateMinutePrior(returnDate, this.featureSettings.getScheduledPriorMin()); // getChangeDateMinutePrior(returnDate); String queryName = this.featureSettings.getProjectQuery(); - updateObjectInformation(featureWidgetQueries.getQuery(returnDate, queryName)); + updateObjectInformation(getQuery(returnDate, queryName)); } - public void updateObjectInformation(String query) throws HygieiaException { - long start = System.nanoTime(); - int pageIndex = 0; - int pageSize = this.featureSettings.getPageSize(); - vOneApi.setPageSize(pageSize); - - vOneApi.buildBasicQuery(query); - vOneApi.buildPagingQuery(0); - JSONArray outPutMainArray = vOneApi.getPagingQueryResponse(); - if (!CollectionUtils.isEmpty(outPutMainArray)) { - JSONArray tmpDetailArray = (JSONArray) outPutMainArray.get(0); - while (!CollectionUtils.isEmpty(tmpDetailArray)) { - updateMongoInfo(tmpDetailArray); - pageIndex = pageIndex + pageSize; - vOneApi.buildPagingQuery(pageIndex); - outPutMainArray = vOneApi.getPagingQueryResponse(); - if (outPutMainArray == null) { - LOGGER.info("FAILED: Script Completed with Error"); - throw new HygieiaException( - "FAILED: Nothing to update from VersionOne's response", - HygieiaException.NOTHING_TO_UPDATE); - } - tmpDetailArray = (JSONArray) outPutMainArray.get(0); - } - } else { - throw new HygieiaException( - "FAILED: FAILED: VersionOne response included unexpected JSON format", - HygieiaException.JSON_FORMAT_ERROR); - } - - double elapsedTime = (System.nanoTime() - start) / 1000000000.0; - LOGGER.info("Process took :" + elapsedTime + " seconds to update"); - } /** * Validates current entry and removes new entry if an older item exists in diff --git a/versionone-feature-collector/src/main/java/com/capitalone/dashboard/collector/RestOperationsSupplier.java b/versionone-feature-collector/src/main/java/com/capitalone/dashboard/collector/RestOperationsSupplier.java deleted file mode 100644 index 4d5ff1a3c8..0000000000 --- a/versionone-feature-collector/src/main/java/com/capitalone/dashboard/collector/RestOperationsSupplier.java +++ /dev/null @@ -1,43 +0,0 @@ -/*************************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.collector; - -import com.capitalone.dashboard.util.Supplier; -import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; -import org.springframework.stereotype.Component; -import org.springframework.web.client.RestOperations; -import org.springframework.web.client.RestTemplate; - -/** - * Supplier that returns a new {@link RestTemplate}. - */ -@Component -public class RestOperationsSupplier implements Supplier { - /** - * Handles the REST operation HTTP connection timeout behavior - * - * @return A configured REST template artifact - */ - @Override - public RestOperations get() { - HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(); - requestFactory.setConnectTimeout(40000); - requestFactory.setReadTimeout(40000); - - return new RestTemplate(requestFactory); - } -} diff --git a/versionone-feature-collector/src/main/java/com/capitalone/dashboard/collector/StoryDataClient.java b/versionone-feature-collector/src/main/java/com/capitalone/dashboard/collector/StoryDataClient.java new file mode 100644 index 0000000000..5c5ceeb0ea --- /dev/null +++ b/versionone-feature-collector/src/main/java/com/capitalone/dashboard/collector/StoryDataClient.java @@ -0,0 +1,274 @@ +package com.capitalone.dashboard.collector; + +import com.capitalone.dashboard.datafactory.versionone.VersionOneDataFactoryImpl; +import com.capitalone.dashboard.misc.HygieiaException; +import com.capitalone.dashboard.model.Collector; +import com.capitalone.dashboard.model.Feature; +import com.capitalone.dashboard.repository.FeatureCollectorRepository; +import com.capitalone.dashboard.repository.FeatureRepository; +import com.capitalone.dashboard.util.DateUtil; +import com.capitalone.dashboard.util.FeatureCollectorConstants; +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.util.CollectionUtils; +import org.springframework.util.StringUtils; + +import java.util.ArrayList; +import java.util.List; + +/** + * 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 StoryDataClient extends BaseClient { + private static final Logger LOGGER = LoggerFactory.getLogger(StoryDataClient.class); + + private final FeatureSettings featureSettings; + private final FeatureCollectorRepository featureCollectorRepository; + private final FeatureRepository featureRepo; + + /** + * Extends the constructor from the super class. + */ + public StoryDataClient(FeatureSettings featureSettings, FeatureRepository featureRepository, + FeatureCollectorRepository featureCollectorRepository, + VersionOneDataFactoryImpl vOneApi) { + super(vOneApi, featureSettings); + LOGGER.debug("Constructing data collection for the feature widget, story-level data..."); + + this.featureSettings = featureSettings; + this.featureRepo = featureRepository; + this.featureCollectorRepository = featureCollectorRepository; + } + + /** + * Updates the MongoDB with a JSONArray received from the source system + * back-end with story-based data. + * + * @param tmpMongoDetailArray A JSON response in JSONArray format from the source system + * + */ + @Override + @SuppressWarnings({"unchecked", "PMD.ExcessiveMethodLength", "PMD.NPathComplexity"}) + protected void updateMongoInfo(JSONArray tmpMongoDetailArray) { + for (Object obj : tmpMongoDetailArray) { + JSONObject dataMainObj = (JSONObject) obj; + Feature feature = new Feature(); + + removeExistingEntity(getJSONString(dataMainObj, "_oid")); + + // collectorId + feature.setCollectorId(featureCollectorRepository + .findByName(FeatureCollectorConstants.VERSIONONE).getId()); + + // ID + feature.setsId(getJSONString(dataMainObj, "_oid")); + + // sNumber + feature.setsNumber(getJSONString(dataMainObj, "Number")); + + // sName + feature.setsName(getJSONString(dataMainObj, "Name")); + + // sStatus + feature.setsStatus(getJSONString(dataMainObj, "Status.Name")); + + // sState + feature.setsState(getJSONString(dataMainObj, "AssetState")); + + // sEstimate + feature.setsEstimate(getJSONString(dataMainObj, "Estimate")); + + // sChangeDate + feature.setChangeDate(getJSONString(dataMainObj, "ChangeDate")); + + // IsDeleted + feature.setIsDeleted(getJSONString(dataMainObj, "IsDeleted")); + + // sProjectID + JSONObject tmpObj = (JSONObject) dataMainObj.get("Scope.ID"); + if (tmpObj.containsKey("_oid")) { + feature.setsProjectID(getJSONString(tmpObj, "_oid")); + } + + // sProjectName + feature.setsProjectName(getJSONString(dataMainObj, "Scope.Name")); + + // sProjectBeginDate + feature.setsProjectBeginDate(getJSONString(dataMainObj, "Scope.BeginDate")); + + // sProjectEndDate + feature.setsProjectEndDate(getJSONString(dataMainObj, "Scope.EndDate")); + + // sProjectChangeDate + feature.setsProjectChangeDate(getJSONString(dataMainObj, "Scope.ChangeDate")); + + // sProjectState + feature.setsProjectState(getJSONString(dataMainObj, "Scope.AssetState")); + + // sProjectIsDeleted + feature.setsProjectIsDeleted(getJSONString(dataMainObj, "Scope.IsDeleted")); + + // sProjectPath + String projPath = feature.getsProjectName(); + List projList = (List) dataMainObj.get("Scope.ParentAndUp.Name"); + if (!CollectionUtils.isEmpty(projList)) { + for (String proj : projList) { + projPath = proj + "-->" + projPath; + } + projPath = "All-->" + projPath; + } else { + projPath = "All-->" + projPath; + } + feature.setsProjectPath(sanitizeResponse(projPath)); + + // sEpicID + tmpObj = (JSONObject) dataMainObj.get("Super.ID"); + if (tmpObj.containsKey("_oid")) { + feature.setsEpicID(getJSONString(tmpObj, "_oid")); + } + + // sEpicNumber + feature.setsEpicNumber(getJSONString(dataMainObj, "Super.Number")); + + // sEpicName + feature.setsEpicName(getJSONString(dataMainObj, "Super.Name")); + + // sEpicBeginDate + feature.setsEpicBeginDate(getJSONString(dataMainObj, "Super.PlannedStart")); + + // sEpicEndDate + feature.setsEpicEndDate(getJSONString(dataMainObj, "Super.PlannedEnd")); + + // sEpicType + feature.setsEpicType(getJSONString(dataMainObj, "Super.Category.Name")); + + // sEpicAssetState + feature.setsEpicAssetState(getJSONString(dataMainObj, "Super.AssetState")); + + // sEpicChangeDate + feature.setsEpicChangeDate(getJSONString(dataMainObj, "Super.ChangeDate")); + + // sEpicIsDeleted + feature.setsEpicIsDeleted(getJSONString(dataMainObj, "Super.IsDeleted")); + + // sSprintID + tmpObj = (JSONObject) dataMainObj.get("Timebox.ID"); + feature.setsSprintID(getJSONString(tmpObj, "_oid")); + + // sSprintName + feature.setsSprintName(getJSONString(dataMainObj, "Timebox.Name")); + + // sSprintBeginDate + feature.setsSprintBeginDate(getJSONString(dataMainObj, "Timebox.BeginDate")); + + // sSprintEndDate + feature.setsSprintEndDate(getJSONString(dataMainObj, "Timebox.EndDate")); + + // sSprintAssetState + feature.setsSprintAssetState(getJSONString(dataMainObj, "Timebox.AssetState")); + + // sSprintChangeDate + feature.setsSprintChangeDate(getJSONString(dataMainObj, "Timebox.ChangeDate")); + + // sSprintIsDeleted + feature.setsSprintIsDeleted(getJSONString(dataMainObj, "Timebox.IsDeleted")); + + // sTeamID + tmpObj = (JSONObject) dataMainObj.get("Team.ID"); + feature.setsTeamID(getJSONString(tmpObj, "_oid")); + + // sTeamName + feature.setsTeamName(getJSONString(dataMainObj, "Team.Name")); + + // sTeamChangeDate + feature.setsTeamChangeDate(getJSONString(dataMainObj, "Team.ChangeDate")); + + // sTeamAssetState + feature.setsTeamAssetState(getJSONString(dataMainObj, "Team.AssetState")); + + // sTeamIsDeleted + feature.setsTeamIsDeleted(getJSONString(dataMainObj, "Team.IsDeleted")); + + // sOwnersID + List ownersIdList = new ArrayList<>(); + for (Object ownersID : (JSONArray) dataMainObj.get("Owners.ID")) { + ownersIdList.add(getJSONString((JSONObject) ownersID, "_oid")); + } + feature.setsOwnersID(ownersIdList); + + // sOwnersShortName + feature.setsOwnersShortName(toCanonicalList((List) dataMainObj.get("Owners.Nickname"))); + + // sOwnersFullName + feature.setsOwnersFullName(toCanonicalList((List) dataMainObj.get("Owners.Name"))); + + // sOwnersUsername + feature.setsOwnersUsername(toCanonicalList((List) dataMainObj.get("Owners.Username"))); + + // sOwnersState + feature.setsOwnersState(toCanonicalList((List) dataMainObj.get("Owners.AssetState"))); + + // sOwnersChangeDate + feature.setsOwnersChangeDate(toCanonicalList((List) dataMainObj.get("Owners.ChangeDate"))); + + // sOwnersIsDeleted + feature.setsOwnersIsDeleted(toCanonicalList((List) dataMainObj.get("Owners.IsDeleted"))); + + featureRepo.save(feature); + } + } + + /** + * Explicitly updates queries for the source system, and initiates the + * update to MongoDB from those calls. + */ + public void updateStoryInformation() throws HygieiaException { + String returnDate = this.featureSettings.getDeltaStartDate(); + if (!StringUtils.isEmpty(getMaxChangeDate())) { + returnDate = getMaxChangeDate(); + } + returnDate = DateUtil.getChangeDateMinutePrior(returnDate, + this.featureSettings.getScheduledPriorMin()); + String queryName = this.featureSettings.getStoryQuery(); + updateObjectInformation(getQuery(returnDate, queryName)); + } + + /** + * Validates current entry and removes new entry if an older item exists in + * the repo + * + * @param localId local repository item ID (not the precise mongoID) + */ + protected void removeExistingEntity(String localId) { + if (StringUtils.isEmpty(localId)) + return; + List listOfFeature = featureRepo.getFeatureIdById(localId); + + if (CollectionUtils.isEmpty(listOfFeature)) + return; + featureRepo.delete(listOfFeature); + } + + @Override + public String getMaxChangeDate() { + Collector col = featureCollectorRepository.findByName(FeatureCollectorConstants.VERSIONONE); + if (col == null) + return ""; + if (StringUtils.isEmpty(featureSettings.getDeltaStartDate())) + return ""; + + List response = featureRepo + .findTopByCollectorIdAndChangeDateGreaterThanOrderByChangeDateDesc(col.getId(), + featureSettings.getDeltaStartDate()); + if (!CollectionUtils.isEmpty(response)) + return response.get(0).getChangeDate(); + return ""; + } +} diff --git a/versionone-feature-collector/src/main/java/com/capitalone/dashboard/client/TeamDataClient.java b/versionone-feature-collector/src/main/java/com/capitalone/dashboard/collector/TeamDataClient.java similarity index 72% rename from versionone-feature-collector/src/main/java/com/capitalone/dashboard/client/TeamDataClient.java rename to versionone-feature-collector/src/main/java/com/capitalone/dashboard/collector/TeamDataClient.java index 8a198a7993..48f44176a5 100644 --- a/versionone-feature-collector/src/main/java/com/capitalone/dashboard/client/TeamDataClient.java +++ b/versionone-feature-collector/src/main/java/com/capitalone/dashboard/collector/TeamDataClient.java @@ -16,7 +16,7 @@ * ************************DA-BOARD-LICENSE-END *********************************/ -package com.capitalone.dashboard.client; +package com.capitalone.dashboard.collector; import com.capitalone.dashboard.datafactory.versionone.VersionOneDataFactoryImpl; import com.capitalone.dashboard.misc.HygieiaException; @@ -24,11 +24,8 @@ import com.capitalone.dashboard.model.ScopeOwnerCollectorItem; import com.capitalone.dashboard.repository.FeatureCollectorRepository; import com.capitalone.dashboard.repository.ScopeOwnerRepository; -import com.capitalone.dashboard.util.ClientUtil; -import com.capitalone.dashboard.util.FeatureCollectorConstants; import com.capitalone.dashboard.util.DateUtil; -import com.capitalone.dashboard.util.FeatureSettings; -import com.capitalone.dashboard.util.FeatureWidgetQueries; +import com.capitalone.dashboard.util.FeatureCollectorConstants; import org.bson.types.ObjectId; import org.json.simple.JSONArray; import org.json.simple.JSONObject; @@ -49,11 +46,9 @@ */ public class TeamDataClient extends BaseClient { private static final Logger LOGGER = LoggerFactory.getLogger(TeamDataClient.class); - private final FeatureSettings featureSettings; - private final FeatureWidgetQueries featureWidgetQueries; + private final ScopeOwnerRepository teamRepo; private final FeatureCollectorRepository featureCollectorRepository; - private final VersionOneDataFactoryImpl vOneApi; private ObjectId oldTeamId; private boolean oldTeamEnabledState; @@ -65,16 +60,11 @@ public class TeamDataClient extends BaseClient { public TeamDataClient(FeatureCollectorRepository featureCollectorRepository, FeatureSettings featureSettings, ScopeOwnerRepository teamRepository, VersionOneDataFactoryImpl vOneApi) { - // super(featureSettings, teamRepository, featureCollectorRepository, - // vOneApi); - LOGGER.debug("Constructing data collection for the feature widget, story-level data..."); - - this.featureSettings = featureSettings; + super(vOneApi, featureSettings); + LOGGER.debug("Constructing data collection for the feature widget, story-level data..."); this.featureCollectorRepository = featureCollectorRepository; this.teamRepo = teamRepository; - this.featureWidgetQueries = new FeatureWidgetQueries(this.featureSettings); teamRepo.delete("Closed"); - this.vOneApi = vOneApi; } /** @@ -85,6 +75,7 @@ public TeamDataClient(FeatureCollectorRepository featureCollectorRepository, * A JSON response in JSONArray format from the source system * */ + @Override protected void updateMongoInfo(JSONArray tmpMongoDetailArray) { for (Object obj : tmpMongoDetailArray) { JSONObject dataMainObj = (JSONObject) obj; @@ -109,7 +100,7 @@ protected void updateMongoInfo(JSONArray tmpMongoDetailArray) { team.setName(getJSONString(dataMainObj, "Name")); // changeDate; team.setChangeDate( - ClientUtil.toCanonicalDate(getJSONString(dataMainObj, "ChangeDate"))); + getJSONString(dataMainObj, "ChangeDate")); // assetState team.setAssetState(getJSONString(dataMainObj, "AssetState")); // isDeleted; @@ -144,14 +135,14 @@ private void removeInactiveScopeOwnerByTeamId(String teamId) { */ public void updateTeamInformation() throws HygieiaException { // super.objClass = ScopeOwnerCollectorItem.class; - String returnDate = this.featureSettings.getDeltaCollectorItemStartDate(); + String returnDate = getFeatureSettings().getDeltaCollectorItemStartDate(); if (!StringUtils.isEmpty(getMaxChangeDate())) { returnDate = getMaxChangeDate(); } returnDate = DateUtil.getChangeDateMinutePrior(returnDate, - this.featureSettings.getScheduledPriorMin()); - String queryName = this.featureSettings.getTeamQuery(); - String query = this.featureWidgetQueries.getQuery(returnDate, queryName); + getFeatureSettings().getScheduledPriorMin()); + String queryName = getFeatureSettings().getTeamQuery(); + String query = getQuery(returnDate, queryName); updateObjectInformation(query); } @@ -179,52 +170,22 @@ protected Boolean removeExistingEntity(String localId) { } - public void updateObjectInformation(String query) throws HygieiaException { - long start = System.nanoTime(); - int pageIndex = 0; - int pageSize = this.featureSettings.getPageSize(); - vOneApi.setPageSize(pageSize); - vOneApi.buildBasicQuery(query); - vOneApi.buildPagingQuery(0); - JSONArray outPutMainArray = vOneApi.getPagingQueryResponse(); - if (!CollectionUtils.isEmpty(outPutMainArray)) { - JSONArray tmpDetailArray = (JSONArray) outPutMainArray.get(0); - while (tmpDetailArray.size() > 0) { - updateMongoInfo(tmpDetailArray); - pageIndex = pageIndex + pageSize; - vOneApi.buildPagingQuery(pageIndex); - outPutMainArray = vOneApi.getPagingQueryResponse(); - if (CollectionUtils.isEmpty(outPutMainArray)) { - LOGGER.info("FAILED: Script Completed with Error"); - throw new HygieiaException( - "FAILED: Nothing to update from VersionOne's response", - HygieiaException.NOTHING_TO_UPDATE); - } - tmpDetailArray = (JSONArray) outPutMainArray.get(0); - } - } else { - throw new HygieiaException( - "FAILED: VersionOne response included unexpected JSON format", - HygieiaException.JSON_FORMAT_ERROR); - } - double elapsedTime = (System.nanoTime() - start) / 1000000000.0; - LOGGER.info("Process took :" + elapsedTime + " seconds to update"); - } /** * Retrieves the maximum change date for a given query. * * @return A list object of the maximum change date */ + @Override public String getMaxChangeDate() { Collector col = featureCollectorRepository.findByName(FeatureCollectorConstants.VERSIONONE); if (col == null) return ""; - if (StringUtils.isEmpty(featureSettings.getDeltaCollectorItemStartDate())) + if (StringUtils.isEmpty(getFeatureSettings().getDeltaCollectorItemStartDate())) return ""; List response = teamRepo.findTopByChangeDateDesc(col.getId(), - featureSettings.getDeltaCollectorItemStartDate()); + getFeatureSettings().getDeltaCollectorItemStartDate()); if (!CollectionUtils.isEmpty(response)) return response.get(0).getChangeDate(); return ""; diff --git a/versionone-feature-collector/src/main/java/com/capitalone/dashboard/datafactory/versionone/VersionOneDataFactory.java b/versionone-feature-collector/src/main/java/com/capitalone/dashboard/datafactory/versionone/VersionOneDataFactory.java index d2ebcd0914..2b6fa92bfd 100644 --- a/versionone-feature-collector/src/main/java/com/capitalone/dashboard/datafactory/versionone/VersionOneDataFactory.java +++ b/versionone-feature-collector/src/main/java/com/capitalone/dashboard/datafactory/versionone/VersionOneDataFactory.java @@ -11,8 +11,6 @@ * */ public interface VersionOneDataFactory { - String buildBasicQuery(String query); - String buildPagingQuery(int inPageIndex); JSONArray getPagingQueryResponse() throws HygieiaException; diff --git a/versionone-feature-collector/src/main/java/com/capitalone/dashboard/datafactory/versionone/VersionOneDataFactoryImpl.java b/versionone-feature-collector/src/main/java/com/capitalone/dashboard/datafactory/versionone/VersionOneDataFactoryImpl.java index 2d98c18bd7..aec1fbf9de 100644 --- a/versionone-feature-collector/src/main/java/com/capitalone/dashboard/datafactory/versionone/VersionOneDataFactoryImpl.java +++ b/versionone-feature-collector/src/main/java/com/capitalone/dashboard/datafactory/versionone/VersionOneDataFactoryImpl.java @@ -1,18 +1,20 @@ -/*************************DA-BOARD-LICENSE-START********************************* +/************************* + * 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 - * + *

+ * 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*********************************/ + * ************************DA-BOARD-LICENSE-END + *********************************/ package com.capitalone.dashboard.datafactory.versionone; @@ -39,267 +41,260 @@ @Component public class VersionOneDataFactoryImpl implements VersionOneDataFactory { - private static final Logger LOGGER = LoggerFactory.getLogger(VersionOneDataFactoryImpl.class); - - protected int pageSize; - protected int pageIndex; - protected JSONArray jsonOutputArray; - protected String basicQuery; - protected String pagingQuery; - protected IServices v1Service; - - /** - * Default blank constructor - */ - public VersionOneDataFactoryImpl() { - this.pageSize = 2000; - this.pageIndex = 0; - } - - /** - * Default constructor, which sets page size to 2000 and page index to 0. - * - * @throws HygieiaException - */ - public VersionOneDataFactoryImpl(Map auth) throws HygieiaException { - this(2000, auth); - } - - /** - * Constructs V1 data factory, but defaults the page size to the page size - * parameter given, and the page index to 0. - * - * @param inPageSize - * A default page size to give the class on construction - * @throws HygieiaException - */ - public VersionOneDataFactoryImpl(int inPageSize, Map auth) - throws HygieiaException { - this.v1Service = new Services(versionOneAuthentication(auth)); - this.pageSize = inPageSize; - pageIndex = 0; - } - - /** - * Used for establishing connection to VersionOne based on authentication - * - * @param auth - * A key-value pairing of authentication values - * @return A V1Connector connection instance - */ - private V1Connector versionOneAuthentication(Map auth) throws HygieiaException { - V1Connector connector = null; - - try { - if (!StringUtils.isEmpty(auth.get("v1ProxyUrl"))) { - ProxyProvider proxyProvider = new ProxyProvider(new URI(auth.get("v1ProxyUrl")), "", - ""); - - connector = V1Connector.withInstanceUrl(auth.get("v1BaseUri")) - .withUserAgentHeader(FeatureCollectorConstants.AGENT_NAME, FeatureCollectorConstants.AGENT_VER) - .withAccessToken(auth.get("v1AccessToken")).withProxy(proxyProvider) - .build(); - } else { - connector = V1Connector.withInstanceUrl(auth.get("v1BaseUri")) - .withUserAgentHeader(FeatureCollectorConstants.AGENT_NAME, FeatureCollectorConstants.AGENT_VER) - .withAccessToken(auth.get("v1AccessToken")).build(); - } - } catch (V1Exception ve) { - throw new HygieiaException("FAILED: VersionOne was not able to authenticate", ve, - HygieiaException.INVALID_CONFIGURATION); - } catch (MalformedURLException me) { - throw new HygieiaException("FAILED: Invalid VersionOne URL.", me, - HygieiaException.INVALID_CONFIGURATION); - } catch (URISyntaxException ue) { - throw new HygieiaException("FAILED: Invalid VersionOne URL.", ue, - HygieiaException.INVALID_CONFIGURATION); - } - return connector; - } - - /** - * Sets the local query value on demand based on a given basic query. - * - * @param query - * A query in YAML syntax as a String - * @return The saved YAML-syntax basic query - */ - public String buildBasicQuery(String query) { - this.setBasicQuery(query); - return this.getBasicQuery(); - } - - /** - * Creates a query on demand based on a given basic query and a specified - * page index value. It is recommended to use this method in a loop to - * ensure all pages are covered. - * - * @param inPageIndex - * A given query's current page index, from 0-oo - * @return A JSON-formatted response - */ - public String buildPagingQuery(int inPageIndex) { - this.setPageIndex(inPageIndex); - String pageFilter = "\npage:\n" + " size: " + pageSize + "\n" + " start: " + pageIndex; - this.setPagingQuery(this.getBasicQuery() + pageFilter); - return this.getPagingQuery(); - } - - /** - * Runs the VersionOneConnection library tools against a given - * YAML-formatted query. This requires a pre-formatted paged query to run, - * and will not perform the paging for you - there are other helper methods - * for this. - * - * @return A formatted JSONArray response - * @throws AuthenticationException - */ - public JSONArray getPagingQueryResponse() throws HygieiaException { - synchronized (this.v1Service) { - Object obj = this.v1Service.executePassThroughQuery(this.getPagingQuery()); - if (obj != null) { - if (!obj.toString().equalsIgnoreCase("{\"error\":\"Unauthorized\"}")) { - this.setJsonOutputArray(obj.toString()); - } else { - throw new HygieiaException( - "FAILED: There was a problem authenticating with VersionOne", - HygieiaException.INVALID_CONFIGURATION); - } - } else { - throw new HygieiaException( - "FAILED: There was a problem parsing or casting JSON types from a message response", - HygieiaException.JSON_FORMAT_ERROR); - } - } - - return this.getJsonOutputArray(); - } - - /** - * Runs the VersionOneConnection library tools against a given - * YAML-formatted query. This requires a pre-formatted basic query - * (single-use). - * - * @return A formatted JSONArray response - */ - public JSONArray getQueryResponse() throws HygieiaException { - synchronized (this.v1Service) { - Object obj = this.v1Service.executePassThroughQuery(this.getBasicQuery()); - if (obj != null) { - if (!obj.toString().equalsIgnoreCase("{\"error\":\"Unauthorized\"}")) { - this.setJsonOutputArray(obj.toString()); - } else { - throw new HygieiaException( - "FAILED: There was a problem authenticating with VersionOne", - HygieiaException.INVALID_CONFIGURATION); - } - } else { - throw new HygieiaException( - "FAILED: There was a problem parsing or casting JSON types from a message response", - HygieiaException.JSON_FORMAT_ERROR); - } - } - - return this.getJsonOutputArray(); - } - - /** - * Mutator method for page index. - * - * @param pageIndex - * Page index of query - */ - public void setPageIndex(int pageIndex) { - this.pageIndex = pageIndex; - } - - /** - * Mutator method for page size. - * - * @param pageSize - * Page index of query - */ - public void setPageSize(int pageSize) { - this.pageSize = pageSize; - } - - /** - * Accessor method for page index. - * - * @return Page index of query - */ - public int getPageIndex() { - return this.pageIndex; - } - - /** - * Accessor method for JSON response output array. - * - * @return JSON response array from VersionOne - */ - private JSONArray getJsonOutputArray() { - return jsonOutputArray; - } - - /** - * Mutator method for JSON response output array. - */ - private void setJsonOutputArray(String stringResult) { - JSONParser parser = new JSONParser(); - - try { - this.jsonOutputArray = (JSONArray) parser.parse(stringResult); - } catch (ParseException | ClassCastException e) { - LOGGER.error( - "There was a problem parsing the JSONArray response value from the source system:\n" - + e.getMessage() + " | " + e.getCause()); - this.jsonOutputArray = new JSONArray(); - } - - } - - /** - * Accessor method for basic query formatted object. - * - * @return Basic VersionOne YAML query - */ - public String getBasicQuery() { - return basicQuery; - } - - /** - * Mutator method for basic query formatted object. - * - * @param basicQuery - * VersionOne YAML query - */ - private void setBasicQuery(String basicQuery) { - this.basicQuery = basicQuery; - } - - /** - * Accessor method for retrieving paged query. - * - * @return The paged YAML query - */ - public String getPagingQuery() { - return pagingQuery; - } - - /** - * Mutator method for setting paged query - * - * @param pagingQuery - * The paged YAML query - */ - private void setPagingQuery(String pagingQuery) { - this.pagingQuery = pagingQuery; - } - - /** - * Used for testing: Accessor Method to get currently set page size - */ - public int getPageSize() { - return this.pageSize; - } + private static final Logger LOGGER = LoggerFactory.getLogger(VersionOneDataFactoryImpl.class); + + protected int pageSize; + protected int pageIndex; + protected JSONArray jsonOutputArray; + protected String basicQuery; + protected String pagingQuery; + protected IServices v1Service = null; + + /** + * Default blank constructor + */ + public VersionOneDataFactoryImpl() { + this.pageSize = 2000; + this.pageIndex = 0; + } + + /** + * Default constructor, which sets page size to 2000 and page index to 0. + * + * @throws HygieiaException + */ + public VersionOneDataFactoryImpl(Map auth) throws HygieiaException { + this(2000, auth); + } + + /** + * Constructs V1 data factory, but defaults the page size to the page size + * parameter given, and the page index to 0. + * + * @param inPageSize A default page size to give the class on construction + * @throws HygieiaException + */ + public VersionOneDataFactoryImpl(int inPageSize, Map auth) + throws HygieiaException { + this.v1Service = new Services(versionOneAuthentication(auth)); + this.pageSize = inPageSize; + pageIndex = 0; + } + + /** + * Used for establishing connection to VersionOne based on authentication + * + * @param auth A key-value pairing of authentication values + * @return A V1Connector connection instance + */ + private V1Connector versionOneAuthentication(Map auth) throws HygieiaException { + V1Connector connector; + + try { + if (!StringUtils.isEmpty(auth.get("v1ProxyUrl"))) { + ProxyProvider proxyProvider = new ProxyProvider(new URI(auth.get("v1ProxyUrl")), "", + ""); + + connector = V1Connector.withInstanceUrl(auth.get("v1BaseUri")) + .withUserAgentHeader(FeatureCollectorConstants.AGENT_NAME, FeatureCollectorConstants.AGENT_VER) + .withAccessToken(auth.get("v1AccessToken")) + .withProxy(proxyProvider) + .build(); + } else { + connector = V1Connector.withInstanceUrl(auth.get("v1BaseUri")) + .withUserAgentHeader(FeatureCollectorConstants.AGENT_NAME, FeatureCollectorConstants.AGENT_VER) + .withAccessToken(auth.get("v1AccessToken")).build(); + } + } catch (V1Exception ve) { + throw new HygieiaException("FAILED: VersionOne was not able to authenticate", ve, + HygieiaException.INVALID_CONFIGURATION); + } catch (MalformedURLException | URISyntaxException me) { + throw new HygieiaException("FAILED: Invalid VersionOne URL.", me, + HygieiaException.INVALID_CONFIGURATION); + } + return connector; + } + + + /** + * Creates a query on demand based on a given basic query and a specified + * page index value. It is recommended to use this method in a loop to + * ensure all pages are covered. + * + * @param inPageIndex A given query's current page index, from 0-oo + * @return A JSON-formatted response + */ + public String buildPagingQuery(int inPageIndex) { + this.setPageIndex(inPageIndex); + String pageFilter = "\npage:\n" + " size: " + pageSize + "\n" + " start: " + pageIndex; + this.setPagingQuery(this.getBasicQuery() + pageFilter); + return this.getPagingQuery(); + } + + /** + * Runs the VersionOneConnection library tools against a given + * YAML-formatted query. This requires a pre-formatted paged query to run, + * and will not perform the paging for you - there are other helper methods + * for this. + * + * @return A formatted JSONArray response + * @throws HygieiaException + */ + public JSONArray getPagingQueryResponse() throws HygieiaException { + synchronized (this.v1Service) { + Object obj = this.v1Service.executePassThroughQuery(this.getPagingQuery()); + + if (obj == null) { + throw new HygieiaException( + "FAILED: There was a problem parsing or casting JSON types from a message response", + HygieiaException.JSON_FORMAT_ERROR); + } + + if (obj.toString().equalsIgnoreCase("{\"error\":\"Unauthorized\"}")) { + throw new HygieiaException( + "FAILED: There was a problem authenticating with VersionOne", + HygieiaException.INVALID_CONFIGURATION); + } + + return makeJsonOutputArray(obj.toString()); + } + } + + /** + * Runs the VersionOneConnection library tools against a given + * YAML-formatted query. This requires a pre-formatted basic query + * (single-use). + * + * @return A formatted JSONArray response + */ + public JSONArray getQueryResponse() throws HygieiaException { + synchronized (this.v1Service) { + Object obj = this.v1Service.executePassThroughQuery(this.getBasicQuery()); + + if (obj == null) { + throw new HygieiaException( + "FAILED: There was a problem parsing or casting JSON types from a message response", + HygieiaException.JSON_FORMAT_ERROR); + } + + if (obj.toString().equalsIgnoreCase("{\"error\":\"Unauthorized\"}")) { + throw new HygieiaException( + "FAILED: There was a problem authenticating with VersionOne", + HygieiaException.INVALID_CONFIGURATION); + } + + return makeJsonOutputArray(obj.toString()); + } + } + + /** + * Mutator method for page index. + * + * @param pageIndex Page index of query + */ + public void setPageIndex(int pageIndex) { + this.pageIndex = pageIndex; + } + + /** + * Mutator method for page size. + * + * @param pageSize Page index of query + */ + public void setPageSize(int pageSize) { + this.pageSize = pageSize; + } + + /** + * Accessor method for page index. + * + * @return Page index of query + */ + public int getPageIndex() { + return this.pageIndex; + } + + /** + * Accessor method for JSON response output array. + * + * @return JSON response array from VersionOne + */ + private JSONArray getJsonOutputArray() { + return jsonOutputArray; + } + + /** + * Mutator method for JSON response output array. + */ + private void setJsonOutputArray(String stringResult) { + JSONParser parser = new JSONParser(); + + try { + this.jsonOutputArray = (JSONArray) parser.parse(stringResult); + } catch (ParseException | ClassCastException e) { + LOGGER.error( + "There was a problem parsing the JSONArray response value from the source system:\n" + + e.getMessage() + " | " + e.getCause()); + this.jsonOutputArray = new JSONArray(); + } + + } + + /** + * Mutator method for JSON response output array. + */ + private JSONArray makeJsonOutputArray(String stringResult) { + JSONParser parser = new JSONParser(); + try { + return (JSONArray) parser.parse(stringResult); + } catch (ParseException | ClassCastException e) { + LOGGER.error( + "There was a problem parsing the JSONArray response value from the source system:\n" + + e.getMessage() + " | " + e.getCause()); + return new JSONArray(); + } + } + + /** + * Accessor method for basic query formatted object. + * + * @return Basic VersionOne YAML query + */ + public String getBasicQuery() { + return basicQuery; + } + + /** + * Mutator method for basic query formatted object. + * + * @param basicQuery VersionOne YAML query + */ + public void setBasicQuery(String basicQuery) { + this.basicQuery = basicQuery; + } + + /** + * Accessor method for retrieving paged query. + * + * @return The paged YAML query + */ + public String getPagingQuery() { + return pagingQuery; + } + + /** + * Mutator method for setting paged query + * + * @param pagingQuery The paged YAML query + */ + public void setPagingQuery(String pagingQuery) { + this.pagingQuery = pagingQuery; + } + + /** + * Used for testing: Accessor Method to get currently set page size + */ + public int getPageSize() { + return this.pageSize; + } } diff --git a/versionone-feature-collector/src/main/java/com/capitalone/dashboard/model/FeatureCollector.java b/versionone-feature-collector/src/main/java/com/capitalone/dashboard/model/FeatureCollector.java index bf10512567..cfe427ec77 100644 --- a/versionone-feature-collector/src/main/java/com/capitalone/dashboard/model/FeatureCollector.java +++ b/versionone-feature-collector/src/main/java/com/capitalone/dashboard/model/FeatureCollector.java @@ -1,18 +1,3 @@ -/*************************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.model; @@ -21,8 +6,6 @@ /** * Collector implementation for Feature that stores system configuration * settings required for source system data connection (e.g., API tokens, etc.) - * - * @author KFK884 */ public class FeatureCollector extends Collector { /** diff --git a/versionone-feature-collector/src/main/java/com/capitalone/dashboard/repository/FeatureCollectorRepository.java b/versionone-feature-collector/src/main/java/com/capitalone/dashboard/repository/FeatureCollectorRepository.java index 4aa1283638..6abf467be3 100644 --- a/versionone-feature-collector/src/main/java/com/capitalone/dashboard/repository/FeatureCollectorRepository.java +++ b/versionone-feature-collector/src/main/java/com/capitalone/dashboard/repository/FeatureCollectorRepository.java @@ -1,18 +1,3 @@ -/*************************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.repository; diff --git a/versionone-feature-collector/src/main/java/com/capitalone/dashboard/util/ClientUtil.java b/versionone-feature-collector/src/main/java/com/capitalone/dashboard/util/ClientUtil.java deleted file mode 100644 index 1aaf1a7ca5..0000000000 --- a/versionone-feature-collector/src/main/java/com/capitalone/dashboard/util/ClientUtil.java +++ /dev/null @@ -1,97 +0,0 @@ -/************************* - * 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.util; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.util.StringUtils; - -import java.nio.ByteBuffer; -import java.nio.charset.CharacterCodingException; -import java.nio.charset.CharsetDecoder; -import java.nio.charset.StandardCharsets; -import java.util.List; -import java.util.stream.Collectors; - -/** - * This class houses any globally-used utility methods re-used by aspects of - * clients in this collector - * - * @author KFK884 - */ -public class ClientUtil { - @SuppressWarnings("unused") - private static final Logger LOGGER = LoggerFactory.getLogger(ClientUtil.class); - - /** - * Utility method used to sanitize / canonicalize a String-based response - * artifact from a source system. This will return a valid UTF-8 strings, or - * a "" (blank) response for any of the following cases: - * "NULL";"Null";"null";null;"" - * - * @param nativeRs The string response artifact retrieved from the source system - * to be sanitized - * @return A UTF-8 sanitized response - */ - public static String sanitizeResponse(String nativeRs) { - if (StringUtils.isEmpty(nativeRs)) return ""; - - byte[] utf8Bytes; - CharsetDecoder cs = StandardCharsets.UTF_8.newDecoder(); - - if ("null".equalsIgnoreCase(nativeRs)) return ""; - utf8Bytes = nativeRs.getBytes(StandardCharsets.UTF_8); - try { - cs.decode(ByteBuffer.wrap(utf8Bytes)); - return new String(utf8Bytes, StandardCharsets.UTF_8); - } catch (CharacterCodingException e) { - return "[INVALID NON UTF-8 ENCODING]"; - } - } - - /** - * Canonicalizes date format returned from source system. Some source - * systems have incorrectly formatted dates, or date times stamps that are - * not database friendly. - * - * @param nativeRs Native date format as a string - * @return A stringified canonical date format - */ - public static String toCanonicalDate(String nativeRs) { - return nativeRs; - /** what's the point, this doesnt do anything.. - String canonicalRs = new String(); - - //canonicalRs = nativeRs.replace("T", " "); - canonicalRs = nativeRs; - - return canonicalRs; - **/ - } - - /** - * Canonicalizes a given JSONArray to a basic List object to avoid the use of JSON parsers. - * - * @param list A given JSONArray object response from the source system - * @return The sanitized, canonical List - */ - public static List toCanonicalList(List list) { - return list.stream().map(ClientUtil::sanitizeResponse).collect(Collectors.toList()); - } -} diff --git a/versionone-feature-collector/src/main/java/com/capitalone/dashboard/util/DateUtil.java b/versionone-feature-collector/src/main/java/com/capitalone/dashboard/util/DateUtil.java index acfb265441..b358238b56 100644 --- a/versionone-feature-collector/src/main/java/com/capitalone/dashboard/util/DateUtil.java +++ b/versionone-feature-collector/src/main/java/com/capitalone/dashboard/util/DateUtil.java @@ -4,7 +4,6 @@ import org.slf4j.LoggerFactory; import java.text.DateFormat; -import java.text.Format; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Calendar; @@ -13,78 +12,8 @@ public final class DateUtil { private static final Logger LOGGER = LoggerFactory.getLogger(DateUtil.class); - public static final String DISPLAY_DATE_FORMAT = "dd-MMM-yyyy"; - public static final String ISO_DATE_FORMAT = "yyyy-MM-dd"; - public static final String ISO_TIME_FORMAT = "T00:00:00.000000"; - public static final String ISO_DATE_TIME_FORMATZ = "yyyy-MM-dd'T'HH:mm:ss.SSSSSS"; public static final String ISO_DATE_TIME_FORMAT = "yyyy-MM-dd'T'HH:mm:ss"; - private DateUtil() { - // utility class - } - - public static Date getNextBusinessDate(Date iDate) { - Calendar calendar = Calendar.getInstance(); - calendar.setTime(iDate); - - int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK); - - if (dayOfWeek == Calendar.FRIDAY) { - calendar.add(Calendar.DATE, 3); - } else if (dayOfWeek == Calendar.SATURDAY) { - calendar.add(Calendar.DATE, 2); - } else { - calendar.add(Calendar.DATE, 1); - } - return calendar.getTime(); - } - - public static boolean isToday(Date iDate) { - Date today = DateUtil.getTodayNoTime(); - Date inputDate = DateUtil.getDateNoTime(iDate); - return inputDate.compareTo(today) == 0; - } - - public static String toISODateTimeFormat(Date iDate) { - DateFormat df = new SimpleDateFormat(ISO_DATE_FORMAT); - return df.format(iDate) + ISO_TIME_FORMAT; - } - - public static String toISODateFormat(Date iDate) { - Format formatter = new SimpleDateFormat(ISO_DATE_FORMAT); - return formatter.format(iDate); - } - - public static Date addDays(Date iDate, int amount) { - Date newDate = iDate; - for (int i = 0; i < amount; i++) { - newDate = DateUtil.getNextBusinessDate(newDate); - } - return newDate; - } - - public static Date getDateNoTime(Date iDate) { - // Get Calendar object set to the date and time of the given Date object - Calendar cal = Calendar.getInstance(); - cal.setTime(iDate); - - // Set time fields to zero - cal.set(Calendar.HOUR_OF_DAY, 0); - cal.set(Calendar.MINUTE, 0); - cal.set(Calendar.SECOND, 0); - cal.set(Calendar.MILLISECOND, 0); - - return cal.getTime(); - } - - public static Date getTodayNoTime() { - return DateUtil.getDateNoTime(new Date()); - } - - public static String toDisplayDateFormat(Date iDate) { - DateFormat df = new SimpleDateFormat(DISPLAY_DATE_FORMAT); - return df.format(iDate); - } public static Date fromISODateTimeFormat(String isoString) { String iString = isoString; @@ -92,44 +21,20 @@ public static Date fromISODateTimeFormat(String isoString) { if (charIndex != -1){ iString = iString.substring(0, charIndex); } - Date dt = null; try { - dt = new SimpleDateFormat(ISO_DATE_TIME_FORMAT).parse(iString); + return new SimpleDateFormat(ISO_DATE_TIME_FORMAT).parse(iString); } catch (ParseException e) { LOGGER.error("Parse error of: "+ iString, e); + return null; } - return dt; } - public static Date fromISODateFormat(String iString) { - if (iString == null) - return null; - Date dt = null; - - try { - dt = new SimpleDateFormat(ISO_DATE_FORMAT).parse(iString); - } catch (ParseException e) { - LOGGER.error("Parse error of: "+ iString, e); - } - - return dt; - } public static String toISODateRealTimeFormat(Date iDate) { DateFormat df = new SimpleDateFormat(ISO_DATE_TIME_FORMAT); return df.format(iDate); } - public static int differenceInDays(Date newerDate, Date olderDate) { - return (int) ((newerDate.getTime() - olderDate.getTime()) / (1000 * 60 * 60 * 24)); - } - - public static Date getDatePriorToNDays(Date fromDate, int numberOfDays) { - Calendar calendar = Calendar.getInstance(); - calendar.setTime(fromDate); - calendar.add(Calendar.DAY_OF_MONTH, -1 * numberOfDays); - return calendar.getTime(); - } public static Date getDatePriorToMinutes(Date fromDate, int minutes) { Calendar calendar = Calendar.getInstance(); diff --git a/versionone-feature-collector/src/main/java/com/capitalone/dashboard/util/FeatureWidgetQueries.java b/versionone-feature-collector/src/main/java/com/capitalone/dashboard/util/FeatureWidgetQueries.java deleted file mode 100644 index 9a3276f875..0000000000 --- a/versionone-feature-collector/src/main/java/com/capitalone/dashboard/util/FeatureWidgetQueries.java +++ /dev/null @@ -1,77 +0,0 @@ -package com.capitalone.dashboard.util; - -import org.stringtemplate.v4.ST; -import org.stringtemplate.v4.STGroup; -import org.stringtemplate.v4.STGroupDir; - - -/** - * Provides dynamic variable access to the available source system queries for - * the feature widget. - * - * @author kfk884 - * - */ -@SuppressWarnings("PMD.SingularField") -public class FeatureWidgetQueries { - private final FeatureSettings featureSettings; - private final String queryFolder; - private final STGroup folder; - - /** - * Constructs the source system query configuration class, based on system - * settings. - * - * @param featureSettings - * Feature collector system settings - */ - public FeatureWidgetQueries(FeatureSettings featureSettings) { - this.featureSettings = featureSettings; - this.queryFolder = this.featureSettings.getQueryFolder(); - this.folder = new STGroupDir(queryFolder, '$', '$'); - } - - /** - * Retrieves source system queries based on the query name (without the file - * type) and a specified change date parameter. - * - * @param changeDatePara - * The change date specified from which to pull data with a given - * query template. - * @param queryName - * The source system query name (without the file type). - * @return A given source system query, in String format. - */ - public String getQuery(String changeDatePara, String queryName) { - ST st = folder.getInstanceOf(queryName); - st.add("changeDate", changeDatePara); - String query = st.render(); - - return query; - } - - /** - * Retrieves source system history/trending queries based on the query name - * (without the file type) and other parameters. - * - * @param sprintStartDate - * The sprint start data in ISO format. - * @param sprintEndDate - * The sprint end data in ISO format. - * @param sprintDeltaDate - * The delta date in ISO format. - * @param queryName - * The source system query name (without the file type). - * @return A given historical source system query, in String format. - */ - public String getTrendingQuery(String sprintStartDate, - String sprintEndDate, String sprintDeltaDate, String queryName) { - ST st = folder.getInstanceOf(queryName); - st.add("sprintStartDate", sprintStartDate); - st.add("sprintEndDate", sprintEndDate); - st.add("sprintDeltaDate", sprintDeltaDate); - String query = st.render(); - - return query; - } -} diff --git a/versionone-feature-collector/src/test/java/com/capitalone/dashboard/client/BaseClientTest.java b/versionone-feature-collector/src/test/java/com/capitalone/dashboard/client/BaseClientTest.java new file mode 100644 index 0000000000..aa9edc92f4 --- /dev/null +++ b/versionone-feature-collector/src/test/java/com/capitalone/dashboard/client/BaseClientTest.java @@ -0,0 +1,62 @@ +package com.capitalone.dashboard.client; + +import com.capitalone.dashboard.collector.BaseClient; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; + +public class BaseClientTest { + private static Logger logger = LoggerFactory.getLogger(BaseClientTest.class); + + @BeforeClass + public static void setUpBeforeClass() throws Exception { + logger.info("Beginning tests for com.capitalone.dashboard.collector.BaseClientTest"); + } + + @AfterClass + public static void tearDownAfterClass() throws Exception { + } + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + /** + * Tests capabilities of string sanitizing method to, in fact, sanitize data + */ + @Test + public void testSanitizeResponse() { + String badEncoding; + byte[] b = {(byte) 0xc3, (byte) 0x28}; + badEncoding = new String(b); + + assertEquals("Santized test string did not match expected output", + "Happy Path", BaseClient.sanitizeResponse("Happy Path")); + assertEquals("Santized test string did not match expected output", "", + BaseClient.sanitizeResponse("")); + assertEquals("Santized test string did not match expected output", "", + BaseClient.sanitizeResponse("NULL")); + assertEquals("Santized test string did not match expected output", "", + BaseClient.sanitizeResponse("Null")); + assertEquals("Santized test string did not match expected output", "", + BaseClient.sanitizeResponse("null")); + assertEquals("Santized test string did not match expected output", "", + BaseClient.sanitizeResponse(null)); + // This test is slightly misleading - there is no good way natively to + // handle for removal of character set mapping tests in Java + assertNotEquals("Santized test string did not match expected output", + "[INVALID NON UTF-8 ENCODING]", + BaseClient.sanitizeResponse(badEncoding)); + } +} \ No newline at end of file diff --git a/versionone-feature-collector/src/test/java/com/capitalone/dashboard/datafactory/versionone/test/VersionOneDataFactoryImplTest.java b/versionone-feature-collector/src/test/java/com/capitalone/dashboard/datafactory/versionone/test/VersionOneDataFactoryImplTest.java index 67befbc09b..2c867824fa 100644 --- a/versionone-feature-collector/src/test/java/com/capitalone/dashboard/datafactory/versionone/test/VersionOneDataFactoryImplTest.java +++ b/versionone-feature-collector/src/test/java/com/capitalone/dashboard/datafactory/versionone/test/VersionOneDataFactoryImplTest.java @@ -1,13 +1,7 @@ package com.capitalone.dashboard.datafactory.versionone.test; -import static org.junit.Assert.*; - -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.Calendar; -import java.util.HashMap; -import java.util.Map; - +import com.capitalone.dashboard.datafactory.versionone.VersionOneDataFactoryImpl; +import com.capitalone.dashboard.misc.HygieiaException; import org.apache.commons.lang3.StringUtils; import org.json.simple.JSONArray; import org.json.simple.JSONObject; @@ -20,8 +14,16 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.capitalone.dashboard.datafactory.versionone.VersionOneDataFactoryImpl; -import com.capitalone.dashboard.misc.HygieiaException; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.HashMap; +import java.util.Map; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; /** * Tests all facets of the VerisonOneDataFactoryImpl class, which is responsible @@ -54,7 +56,7 @@ public VersionOneDataFactoryImplTest() { public static void setUpBeforeClass() throws Exception { logger.info( "Beginning tests for com.capitalone.dashboard.datafactory.versionone.VersionOneDataFactoryImpl"); - auth = new HashMap(); + auth = new HashMap<>(); // TODO: Include your own company proxy auth.put("v1ProxyUrl", ""); // TODO: Include your own base uri for VersionOne @@ -116,6 +118,7 @@ public void tearDown() throws Exception { @Test public void testBuildPagingQuery() { v1DataFactory.setPageSize(1); + v1DataFactory.setBasicQuery(query); v1DataFactory.buildPagingQuery(30); assertNotNull("The basic query was created", v1DataFactory.getPagingQuery()); assertEquals("The page size was accurate", 1, v1DataFactory.getPageSize()); @@ -131,7 +134,7 @@ public void testBuildPagingQuery() { @Test public void testGetPagingQueryResponse() { v1DataFactory.setPageSize(1); - v1DataFactory.buildBasicQuery(query); + v1DataFactory.setBasicQuery(query); v1DataFactory.buildPagingQuery(0); try { JSONArray rs = v1DataFactory.getPagingQueryResponse(); @@ -139,10 +142,9 @@ public void testGetPagingQueryResponse() { /* * Testing actual JSON for values */ - JSONArray dataMainArry = new JSONArray(); - JSONObject dataMainObj = new JSONObject(); - dataMainArry = (JSONArray) rs.get(0); - dataMainObj = (JSONObject) dataMainArry.get(0); + + JSONArray dataMainArry = (JSONArray) rs.get(0); + JSONObject dataMainObj = (JSONObject) dataMainArry.get(0); // number assertTrue("No valid Number was found", @@ -164,8 +166,7 @@ public void testGetPagingQueryResponse() { /* * Testing actual JSON for values */ - String strRs = new String(); - strRs = rs.toString(); + String strRs = rs.toString(); assertEquals( "There was nothing returned from VersionOne that is consistent with a valid response.", @@ -175,22 +176,14 @@ public void testGetPagingQueryResponse() { } } - /** - * Test method for - * {@link com.capitalone.dashboard.datafactory.versionone.VersionOneDataFactoryImpl#VersionOneDataFactoryImpl()} - * . - */ + @Test public void testVersionOneDataFactoryImpl() { assertEquals("The compared contructed page size values did not match", 2000, v1DataFactory.getPageSize()); } - /** - * Test method for - * {@link com.capitalone.dashboard.datafactory.versionone.VersionOneDataFactoryImpl#VersionOneDataFactoryImpl(int)} - * . - */ + @Test public void testVersionOneDataFactoryImplInt() { v1DataFactory.setPageSize(1000); @@ -198,40 +191,30 @@ public void testVersionOneDataFactoryImplInt() { v1DataFactory.getPageSize()); } - /** - * Test method for - * {@link com.capitalone.dashboard.datafactory.versionone.VersionOneDataFactoryImpl#buildBasicQuery(java.lang.String)} - * . - */ + @Test public void testBuildBasicQuery() { v1DataFactory.setPageSize(1); - v1DataFactory.buildBasicQuery(query); + v1DataFactory.setBasicQuery(query); assertNotNull("The basic query was created", v1DataFactory.getBasicQuery()); assertEquals("The page size was accurate", 1, v1DataFactory.getPageSize()); assertEquals("The page index was accurate", 0, v1DataFactory.getPageIndex()); } - /** - * Test method for - * {@link com.capitalone.dashboard.datafactory.versionone.VersionOneDataFactoryImpl#getQueryResponse(java.lang.String)} - * . - */ + @Ignore @Test public void testGetQueryResponse() { v1DataFactory.setPageSize(1); - v1DataFactory.buildBasicQuery(query); + v1DataFactory.setBasicQuery(query); try { JSONArray rs = v1DataFactory.getQueryResponse(); /* * Testing actual JSON for values */ - JSONArray dataMainArry = new JSONArray(); - JSONObject dataMainObj = new JSONObject(); - dataMainArry = (JSONArray) rs.get(0); - dataMainObj = (JSONObject) dataMainArry.get(0); + JSONArray dataMainArry = (JSONArray) rs.get(0); + JSONObject dataMainObj = (JSONObject) dataMainArry.get(0); // number assertTrue("No valid Number was found", @@ -253,8 +236,7 @@ public void testGetQueryResponse() { /* * Testing actual JSON for values */ - String strRs = new String(); - strRs = rs.toString(); + String strRs = rs.toString(); assertEquals( "There was nothing returned from VersionOne that is consistent with a valid response.", diff --git a/versionone-feature-collector/src/test/java/com/capitalone/dashboard/datafactory/versionone/test/package-info.java b/versionone-feature-collector/src/test/java/com/capitalone/dashboard/datafactory/versionone/test/package-info.java deleted file mode 100644 index 8e29228615..0000000000 --- a/versionone-feature-collector/src/test/java/com/capitalone/dashboard/datafactory/versionone/test/package-info.java +++ /dev/null @@ -1,7 +0,0 @@ -/** - * Houses test methods for VersionOne data connection and response building capabilities. - * - * @author KFK884 - * - */ -package com.capitalone.dashboard.datafactory.versionone.test; \ No newline at end of file diff --git a/versionone-feature-collector/src/test/java/com/capitalone/dashboard/util/ClientUtilTest.java b/versionone-feature-collector/src/test/java/com/capitalone/dashboard/util/ClientUtilTest.java deleted file mode 100644 index 7769f889e4..0000000000 --- a/versionone-feature-collector/src/test/java/com/capitalone/dashboard/util/ClientUtilTest.java +++ /dev/null @@ -1,112 +0,0 @@ -/*************************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.util; - -import static org.junit.Assert.*; - -import org.junit.After; -import org.junit.AfterClass; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.capitalone.dashboard.util.ClientUtil; - -/** - * Tests key facets of the ClientUtilTest class, which is responsible for - * orchestrating updates to the local repositories based on data from the source - * system. - * - * @author KFK884 - * - */ -public class ClientUtilTest { - private static Logger logger = LoggerFactory.getLogger("ClientUtilTest"); - protected static ClientUtil classUnderTest; - - /** - * Default constructor - */ - public ClientUtilTest() { - } - - @BeforeClass - public static void setUpBeforeClass() throws Exception { - logger.info("Beginning tests for com.capitalone.dashboard.collector.ClientUtilTest"); - classUnderTest = new ClientUtil(); - } - - @AfterClass - public static void tearDownAfterClass() throws Exception { - } - - @Before - public void setUp() throws Exception { - } - - @After - public void tearDown() throws Exception { - } - - /** - * Tests capabilities of string sanitizing method to, in fact, sanitize data - */ - @Test - public void testSanitizeResponse() { - String badEncoding; - byte[] b = { (byte) 0xc3, (byte) 0x28 }; - badEncoding = new String(b); - - assertEquals("Santized test string did not match expected output", - "Happy Path", classUnderTest.sanitizeResponse("Happy Path")); - assertEquals("Santized test string did not match expected output", "", - classUnderTest.sanitizeResponse("")); - assertEquals("Santized test string did not match expected output", "", - classUnderTest.sanitizeResponse("NULL")); - assertEquals("Santized test string did not match expected output", "", - classUnderTest.sanitizeResponse("Null")); - assertEquals("Santized test string did not match expected output", "", - classUnderTest.sanitizeResponse("null")); - assertEquals("Santized test string did not match expected output", "", - classUnderTest.sanitizeResponse(null)); - // This test is slightly misleading - there is no good way natively to - // handle for removal of character set mapping tests in Java - assertNotEquals("Santized test string did not match expected output", - "[INVALID NON UTF-8 ENCODING]", - classUnderTest.sanitizeResponse(badEncoding)); - } - - /** - * Tests capabilities of converting VersionOne date format to standard - * localized format - */ - @Test - public void testToCanonicalDate() { - String testLongDateFormat = new String("2015-01-03T00:00:00.0000000"); - String testBlank = ""; - - assertEquals( - "Actual date format did not match expected date format output", - "2015-01-03T00:00:00.0000000", - classUnderTest.toCanonicalDate(testLongDateFormat)); - assertEquals( - "Actual date format did not match expected date format output", - "", classUnderTest.toCanonicalDate(testBlank)); - } -}