summaryrefslogtreecommitdiffstats
path: root/sparkybe-onap-service/src
diff options
context:
space:
mode:
Diffstat (limited to 'sparkybe-onap-service/src')
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/aggregatevnf/search/AggregateSummaryProcessor.java210
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/aggregatevnf/search/AggregateVnfSearchProvider.java129
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/aggregatevnf/search/VnfSearchQueryBuilder.java176
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/aggregation/sync/AggregationSyncControllerFactory.java241
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/aggregation/sync/AggregationSynchronizer.java782
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/aggregation/sync/HistoricalEntitySummarizer.java384
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/aggregation/sync/HistoricalEntitySyncController.java94
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/analytics/AbstractStatistics.java178
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/analytics/AveragingRingBuffer.java121
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/analytics/ComponentStatistics.java80
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/analytics/HistogramSampler.java286
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/analytics/HistoricalCounter.java177
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/autosuggestion/sync/AutoSuggestionSyncController.java105
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/autosuggestion/sync/AutosuggestionSynchronizer.java776
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/autosuggestion/sync/VnfAliasSuggestionSynchronizer.java197
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/autosuggestion/sync/VnfAliasSyncController.java99
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/common/search/CommonSearchSuggestion.java90
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/config/SparkyResourceLoader.java125
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/config/oxm/CrossEntityReference.java78
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/config/oxm/CrossEntityReferenceDescriptor.java67
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/config/oxm/CrossEntityReferenceLookup.java136
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/config/oxm/GeoEntityDescriptor.java61
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/config/oxm/GeoEntityLookup.java137
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/config/oxm/GeoOxmEntityDescriptor.java71
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/config/oxm/OxmEntityDescriptor.java68
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/config/oxm/OxmEntityLookup.java132
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/config/oxm/OxmModelLoader.java195
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/config/oxm/OxmModelProcessor.java33
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/config/oxm/SearchableEntityLookup.java119
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/config/oxm/SearchableOxmEntityDescriptor.java75
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/config/oxm/SuggestionEntityDescriptor.java54
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/config/oxm/SuggestionEntityLookup.java181
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/crossentityreference/sync/CrossEntityReferenceSynchronizer.java937
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/dal/ActiveInventoryAdapter.java404
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/dal/ElasticSearchAdapter.java157
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/dal/GizmoAdapter.java336
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/dal/NetworkTransaction.java159
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/dal/aai/ActiveInventoryEntityStatistics.java285
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/dal/aai/ActiveInventoryProcessingExceptionStatistics.java139
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/dal/elasticsearch/ElasticSearchEntityStatistics.java265
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/dal/exception/ElasticSearchOperationException.java53
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/dal/proxy/processor/AaiUiProxyProcessor.java207
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/dal/rest/HttpMethod.java33
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/dal/rest/RestClientConstructionException.java38
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/dal/rest/RestClientFactory.java97
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/dal/rest/RestOperationalStatistics.java255
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/dal/rest/config/RestEndpointConfig.java179
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/editattributes/AttributeEditProcessor.java182
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/editattributes/AttributeUpdater.java362
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/editattributes/UserAuthorizationReader.java79
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/editattributes/UserValidator.java67
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/editattributes/entity/EditRequest.java69
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/editattributes/exception/AttributeUpdateException.java62
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/inventory/EntityHistoryQueryBuilder.java143
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/inventory/GeoVisualizationProcessor.java180
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/inventory/entity/GeoIndexDocument.java289
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/inventory/entity/TopographicalEntity.java219
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/logging/AaiUiMsgs.java472
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/logging/util/LoggingUtils.java43
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/logging/util/ServletUtils.java204
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/EntityCountHistoryProcessor.java407
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/EntityTypeSummary.java53
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/EntityTypeSummaryBucket.java46
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/SearchEntityProperties.java49
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/SearchResponse.java102
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/SearchServiceAdapter.java139
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/UnifiedSearchProcessor.java188
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/api/SearchProvider.java36
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/config/SuggestionConfig.java76
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/entity/QuerySearchEntity.java73
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/entity/SearchSuggestion.java39
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/FilterElasticSearchAdapter.java119
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/FilterProcessor.java144
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/FilterQueryBuilder.java218
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/FilteredSearchHelper.java158
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/UiFiltersEntityConverter.java180
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/config/FiltersConfig.java158
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/config/FiltersDetailsConfig.java58
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/config/FiltersForViewsConfig.java57
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/config/UiFilterConfig.java188
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/config/UiFilterDataSourceConfig.java99
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/config/UiFilterListItemConfig.java70
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/config/UiFilterOptionsValuesConfig.java68
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/config/UiViewListItemConfig.java68
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/entity/AggregationEntity.java80
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/entity/BoolQueryBuilder.java123
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/entity/FilteredAggregationQueryBuilder.java65
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/entity/MatchFilterCriteriaEntity.java77
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/entity/SearchFilter.java88
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/entity/UiFilterEntity.java180
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/entity/UiFilterValueEntity.java80
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/entity/UiFiltersEntity.java53
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/registry/SearchProviderRegistry.java76
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/security/BaseCookieDecryptor.java51
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/security/CookieDecryptor.java31
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/security/EcompSso.java155
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/security/SecurityContextFactory.java78
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/security/SecurityContextFactoryImpl.java205
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/security/filter/CspCookieFilter.java267
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/security/filter/LoginFilter.java236
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/security/portal/PortalRestAPIServiceImpl.java213
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/security/portal/UserManager.java170
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/security/portal/config/PortalAuthenticationConfig.java124
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/security/portal/config/RolesConfig.java90
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/subscription/SubscriptionServiceProcessor.java74
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/subscription/config/SubscriptionConfig.java139
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/subscription/payload/entity/Message.java60
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/subscription/payload/entity/ObjectInspectorPayload.java128
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/subscription/payload/entity/Params.java60
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/subscription/payload/entity/Payload.java60
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/subscription/services/SubscriptionService.java65
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/AbstractEntitySynchronizer.java524
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/ElasticSearchIndexCleaner.java604
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/ElasticSearchSchemaFactory.java97
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/IndexCleaner.java57
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/IndexIntegrityValidator.java178
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/IndexSynchronizer.java67
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/IndexValidator.java58
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/SyncController.java96
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/SyncControllerImpl.java682
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/SyncControllerRegistrar.java29
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/SyncControllerRegistry.java50
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/SyncControllerService.java222
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/SynchronizerConstants.java65
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/TaskProcessingStats.java135
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/TransactionRateMonitor.java75
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/config/ElasticSearchEndpointConfig.java72
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/config/ElasticSearchSchemaConfig.java77
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/config/NetworkStatisticsConfig.java239
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/config/SyncControllerConfig.java305
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/entity/AggregationEntity.java99
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/entity/AggregationSuggestionEntity.java111
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/entity/IndexDocument.java41
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/entity/IndexableCrossEntityReference.java97
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/entity/IndexableEntity.java100
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/entity/MergableEntity.java59
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/entity/ObjectIdCollection.java78
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/entity/SearchableEntity.java142
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/entity/SelfLinkDescriptor.java90
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/entity/SuggestionSearchEntity.java327
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/entity/TransactionStorageType.java56
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/enumeration/OperationState.java32
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/enumeration/SynchronizerState.java32
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/task/PerformActiveInventoryRetrieval.java97
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/task/PerformElasticSearchPut.java90
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/task/PerformElasticSearchRetrieval.java72
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/task/PerformElasticSearchUpdate.java82
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/task/PerformGizmoRetrieval.java95
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/task/StoreDocumentTask.java90
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/task/SyncControllerTask.java55
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/topology/sync/GeoSyncController.java101
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/topology/sync/GeoSynchronizer.java487
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/util/ConfigHelper.java193
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/util/EncryptConvertor.java149
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/util/Encryptor.java155
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/util/ErrorUtil.java61
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/util/JsonXmlConverter.java79
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/util/NodeUtils.java896
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/util/RawByteHelper.java176
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/util/RestletUtils.java119
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/util/SuggestionsPermutation.java100
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/util/TreeWalker.java136
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/EntityTypeAggregation.java61
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/SchemaVisualizationProcessor.java99
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/config/SparkyConstants.java102
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/config/TierSupportUiConstants.java102
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/config/VisualizationConfigs.java174
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/ActiveInventoryNode.java831
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/D3VisualizationOutput.java93
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/EntityEntry.java81
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/GizmoEntity.java98
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/GizmoRelationshipEntity.java103
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/GizmoRelationshipHint.java77
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/GraphMeta.java147
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/GraphRequest.java58
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/InlineMessage.java70
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/JsonNode.java207
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/JsonNodeLink.java77
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/NodeDebug.java59
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/NodeMeta.java207
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/NodeProcessingTransaction.java109
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/QueryParams.java57
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/QueryRequest.java47
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/RelatedToProperty.java64
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/Relationship.java96
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/RelationshipData.java63
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/RelationshipDirectionality.java42
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/RelationshipList.java57
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/SearchableEntityList.java116
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/SelfLinkDeterminationTransaction.java80
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/SparkyGraphLink.java75
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/SparkyGraphNode.java248
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/enumeration/NodeProcessingAction.java36
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/enumeration/NodeProcessingState.java31
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/search/ViewInspectSearchProvider.java426
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/services/BaseGizmoVisualizationContext.java990
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/services/BaseVisualizationContext.java1631
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/services/BaseVisualizationService.java382
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/services/VisualizationContext.java55
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/services/VisualizationService.java52
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/services/VisualizationTransformer.java305
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/task/PerformGizmoNodeSelfLinkProcessingTask.java128
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/task/PerformNodeSelfLinkProcessingTask.java129
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/task/PerformSelfLinkDeterminationTask.java95
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewinspect/sync/ViewInspectEntitySynchronizer.java779
-rw-r--r--sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewinspect/sync/ViewInspectSyncController.java122
-rw-r--r--sparkybe-onap-service/src/main/resources/logging/AAIUIMsgs.properties901
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/analytics/AveragingRingBufferTest.java134
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/analytics/HistogramSamplerTest.java91
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/analytics/HistoricalCounterTest.java70
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/analytics/TransactionRateControllerTest.java217
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/autosuggestion/sync/AutosuggestionSynchronizerTest.java387
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/common/search/CommonSearchSuggestionTest.java55
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/config/oxm/CrossEntityReferenceDescriptorTest.java34
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/config/oxm/CrossEntityReferenceTest.java36
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/config/oxm/GeoEntityDescriptorTest.java37
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/config/oxm/GeoOxmEntityDescriptorTest.java40
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/config/oxm/OxmEntityContainerLookup.java99
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/config/oxm/OxmEntityDescriptorTest.java41
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/crossentityreference/sync/CrossEntityReferenceSynchronizerTest.java1035
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/ActiveInventoryAdapterTest.java63
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/ElasticSearchAdapterTest.java50
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/NetworkTransactionTest.java59
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/elasticsearch/entity/AutoSuggestDocumentEntity.java44
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/elasticsearch/entity/AutoSuggestDocumentEntityFields.java81
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/elasticsearch/entity/AutoSuggestElasticHitEntity.java87
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/elasticsearch/entity/AutoSuggestElasticHitsEntity.java50
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/elasticsearch/entity/AutoSuggestElasticSearchResponse.java85
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/elasticsearch/entity/BucketEntity.java61
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/elasticsearch/entity/ElasticHit.java29
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/elasticsearch/entity/ElasticHitsEntity.java74
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/elasticsearch/entity/ElasticSearchAggegrationResponse.java109
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/elasticsearch/entity/ElasticSearchAggregation.java74
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/elasticsearch/entity/ElasticSearchCountResponse.java60
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/elasticsearch/entity/PayloadEntity.java32
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/proxy/processor/AaiUiProxyProcessorTest.java145
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/rest/config/RestEndpointConfigTest.java76
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/sas/config/SearchServiceConfigTest.java21
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/sas/entity/DocumentEntity.java68
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/sas/entity/EntityCountResponse.java55
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/sas/entity/GroupByAggregationEntity.java60
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/sas/entity/GroupByAggregationResponseEntity.java48
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/sas/entity/HitEntity.java48
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/sas/entity/SearchAbstractionEntityBuilder.java294
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/sas/entity/SearchAbstractionResponse.java39
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/sas/entity/SearchResult.java49
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/editattributes/AttributeUpdaterTest.java164
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/editattributes/EditAttributesTest.java171
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/editattributes/TestUserAuthorizationReader.java113
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/editattributes/TestUserValidator.java137
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/editattributes/entity/EditRequestTest.java43
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/inventory/EntityHistoryQueryBuilderTest.java34
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/inventory/GeoIndexDocumentTest.java121
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/inventory/entity/TopographicalEntityTest.java50
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/logging/util/LoggingUtilsTest.java25
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/EntityCountHistoryProcessorTest.java154
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/EntityTypeSummaryBucketTest.java31
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/EntityTypeSummaryTest.java37
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/SearchEntityPropertiesTest.java34
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/SearchServiceAdapterTest.java47
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/UnifiedSearchProcessorTest.java445
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/config/SuggestionConfigTest.java42
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/entity/MockSearchResponse.java71
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/filters/FilterProcessorTest.java374
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/filters/FilteredSearchHelperTest.java69
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/filters/config/FiltersConfigTest.java47
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/filters/config/FiltersDetailsConfigTest.java40
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/filters/config/FiltersForViewsConfigTest.java40
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/filters/config/UiFilterConfigTest.java57
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/filters/config/UiFilterDataSourceConfigTest.java44
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/filters/config/UiFilterListItemConfigTest.java34
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/filters/config/UiFilterOptionsValuesConfigTest.java31
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/filters/config/UiViewListItemConfigTest.java38
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/filters/entity/DiscoverFiltersRequest.java40
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/filters/entity/ViewConfiguration.java68
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/filters/entity/ViewFilter.java57
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/security/SecurityContextFactoryImplTest.java143
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/security/portal/TestPortalRestAPIServiceImpl.java283
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/security/portal/TestUserManager.java265
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/subscription/config/SubscriptionConfigTest.java54
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/subscription/payload/entity/MessageTest.java32
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/subscription/payload/entity/ObjectInspectorPayloadTest.java43
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/subscription/payload/entity/ParamsTest.java30
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/subscription/payload/entity/PayloadTest.java32
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/sync/AbstractEntitySynchronizerTest.java463
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/sync/AggregationSynchronizerTest.java345
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/sync/ElasticSearchIndexCleanerTest.java122
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/sync/SyncControllerImplTest.java81
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/sync/config/ElasticSearchEndpointConfigTest.java39
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/sync/config/ElasticSearchSchemaConfigTest.java47
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/sync/config/NetworkStatisticsConfigTest.java74
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/sync/config/SyncControllerConfigTest.java64
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/synchronizer/AsyncRateControlTester.java242
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/synchronizer/GizmoEntitySummarizer.java251
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/synchronizer/IndexDocumentTest.java104
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/synchronizer/IndexableCrossEntityReferenceTest.java72
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/synchronizer/SyncControllerBuilder.java512
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/synchronizer/SyncControllerServiceTest.java34
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/synchronizer/TestSyncController.java177
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/synchronizer/entity/AggregationSuggestionEntityTest.java75
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/synchronizer/entity/SuggestionSearchEntityTest.java187
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/synchronizer/task/PerformActiveInventoryRetrievalTest.java93
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/util/CaptureLoggerAppender.java247
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/util/ExceptionHelper.java62
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/util/HttpServletHelper.java162
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/util/LogValidator.java85
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/util/OxmModelAndProcessorHelper.java143
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/util/SparkyTestConstants.java19
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/util/StringCollectionContainsMatcher.java39
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/util/SuggestionsPermutationTest.java130
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/util/TestResourceLoader.java31
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/util/TreeWalkerTest.java563
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/BaseVisualizationContextTest.java5
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/BaseVisualizationServiceTest.java75
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/SchemaVisualizationProcessorTest.java78
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/SearchAdapterTest.java87
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/SearchResponseTest.java92
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/SearchServletTest.java992
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/SearchableGroupsTest.java73
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/ViewAndInspectSearchRequestTest.java81
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/VisualizationTransformerTest.java77
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/config/VisualizationConfigTest.java62
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/ActiveInventoryNodeTest.java128
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/D3VisualizationOutputTest.java46
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/EntityEntryTest.java94
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/GraphMetaTest.java61
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/GraphRequestTest.java61
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/InlineMessageTest.java55
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/JsonNodeLinkTest.java57
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/NodeDebugTest.java57
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/NodeMetaTest.java88
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/NodeProcessingTransactionTest.java62
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/QueryParamsTest.java56
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/QueryRequestTest.java54
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/RelatedToPropertyTest.java54
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/RelationshipDataTest.java54
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/RelationshipListTest.java32
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/RelationshipTest.java43
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/SearchResponseTest.java52
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/SearchableEntityListTest.java44
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/SelfLinkDeterminationTransactionTest.java68
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/SparkyGraphLinkTest.java56
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/SparkyGraphNodeTest.java81
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/services/BaseVisualizationContextTest.java273
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/sync/ViewInspectGizmoEntitySynchronizer.java792
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/sync/ViewInspectGizmoSyncController.java107
-rw-r--r--sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/util/SchemaVisualizationTestDataBuilder.java134
-rw-r--r--sparkybe-onap-service/src/test/resources/bundleconfig/etc/appprops/source-of-truth.properties47
-rw-r--r--sparkybe-onap-service/src/test/resources/es_test_scripts/commands.txt3
-rw-r--r--sparkybe-onap-service/src/test/resources/es_test_scripts/geoEntities.json6
-rw-r--r--sparkybe-onap-service/src/test/resources/es_test_scripts/prepareGeoEntityBulkImport.pl41
-rw-r--r--sparkybe-onap-service/src/test/resources/es_test_scripts/sampleGeoEntities.csv4
-rw-r--r--sparkybe-onap-service/src/test/resources/es_test_scripts/topoHistoryBulkLoad.json24
-rw-r--r--sparkybe-onap-service/src/test/resources/es_test_scripts/topoHistoryConfigSettings.json20
-rw-r--r--sparkybe-onap-service/src/test/resources/es_test_scripts/topographicalConfigSettings.json24
-rw-r--r--sparkybe-onap-service/src/test/resources/es_test_scripts/topographysearch_schema.json9
-rw-r--r--sparkybe-onap-service/src/test/resources/filters/AggregationSuggestionEntity_getIndexDocumentJson_expected.json1
-rw-r--r--sparkybe-onap-service/src/test/resources/filters/aaiui_filters.json88
-rw-r--r--sparkybe-onap-service/src/test/resources/filters/aaiui_filters_testConfig.json79
-rw-r--r--sparkybe-onap-service/src/test/resources/filters/aaiui_views.json38
-rw-r--r--sparkybe-onap-service/src/test/resources/filters/aaiui_views_testConfig.json21
-rw-r--r--sparkybe-onap-service/src/test/resources/filters/filterAggregationEndpoint_emptyRequestBody_expectedResponse.json1
-rw-r--r--sparkybe-onap-service/src/test/resources/filters/filterAggregationEndpoint_emptyRequestFilterArray_expectedResponse.json1
-rw-r--r--sparkybe-onap-service/src/test/resources/filters/filterAggregationEndpoint_emptyRequestFilterArray_requestBody.json3
-rw-r--r--sparkybe-onap-service/src/test/resources/filters/filterAggregationEndpoint_successPath_expectedResponse.json1
-rw-r--r--sparkybe-onap-service/src/test/resources/filters/filterAggregationEndpoint_successPath_operationResult.json1
-rw-r--r--sparkybe-onap-service/src/test/resources/filters/filterAggregationEndpoint_successPath_requestBody.json11
-rw-r--r--sparkybe-onap-service/src/test/resources/portal/portal-authentication.properties2
-rw-r--r--sparkybe-onap-service/src/test/resources/portal/roles.config6
-rw-r--r--sparkybe-onap-service/src/test/resources/sync/ElasticSearch/AfterSync_ElasticSearch_ScrollApi_Successful.json171
-rw-r--r--sparkybe-onap-service/src/test/resources/sync/ElasticSearch/BeforeSync_ElasticSearch_ScrollApi_Successful.json156
-rw-r--r--sparkybe-onap-service/src/test/resources/sync/ElasticSearch/docEntityFromElasticSearch1.json17
-rw-r--r--sparkybe-onap-service/src/test/resources/sync/ElasticSearch/docEntityFromElasticSearch2.json17
-rw-r--r--sparkybe-onap-service/src/test/resources/sync/ElasticSearch/docEntityFromElasticSearch3.json17
-rw-r--r--sparkybe-onap-service/src/test/resources/sync/ElasticSearch/docEntityFromElasticSearch4.json17
-rw-r--r--sparkybe-onap-service/src/test/resources/sync/ElasticSearch/docEntityFromElasticSearch5.json17
-rw-r--r--sparkybe-onap-service/src/test/resources/sync/aai/aai-resources/customer/customer-4.json60
-rw-r--r--sparkybe-onap-service/src/test/resources/sync/aai/aai-resources/service-instance/service-instance-50.json26
-rw-r--r--sparkybe-onap-service/src/test/resources/sync/aai/aai-resources/service-instance/service-instance-51.json28
-rw-r--r--sparkybe-onap-service/src/test/resources/sync/aai/aai-resources/service-instance/service-instance-52.json12
-rw-r--r--sparkybe-onap-service/src/test/resources/sync/aai/aai-resources/service-instance/service-instance-53.json12
-rw-r--r--sparkybe-onap-service/src/test/resources/sync/aai/aai-resources/service-instance/service-instance-54.json6
-rw-r--r--sparkybe-onap-service/src/test/resources/sync/aai/aai-resources/service-instance/service-instance-55.json8
-rw-r--r--sparkybe-onap-service/src/test/resources/sync/aai/aai-resources/service-instance/service-instance-56.json4
-rw-r--r--sparkybe-onap-service/src/test/resources/sync/aai/aai-resources/service-instance/service-instance-57.json11
-rw-r--r--sparkybe-onap-service/src/test/resources/sync/aai/aai-resources/service-instance/service-instance-58.json32
-rw-r--r--sparkybe-onap-service/src/test/resources/sync/aai/aai-resources/service-instance/service-instance-59.json4
-rw-r--r--sparkybe-onap-service/src/test/resources/sync/aai/aai-resources/service-subscription/service-subscription-2.json50
-rw-r--r--sparkybe-onap-service/src/test/resources/sync/aai/aai-resources/tenant/tenant-1.json23
-rw-r--r--sparkybe-onap-service/src/test/resources/sync/aai/aai-traversal/generic-query/service-instance-50.json8
-rw-r--r--sparkybe-onap-service/src/test/resources/sync/aai/aai-traversal/generic-query/service-instance-51.json8
-rw-r--r--sparkybe-onap-service/src/test/resources/sync/aai/aai-traversal/generic-query/service-instance-52.json8
-rw-r--r--sparkybe-onap-service/src/test/resources/sync/aai/aai-traversal/generic-query/service-instance-53.json8
-rw-r--r--sparkybe-onap-service/src/test/resources/sync/aai/aai-traversal/generic-query/service-instance-54.json8
-rw-r--r--sparkybe-onap-service/src/test/resources/sync/aai/aai-traversal/generic-query/service-instance-55.json8
-rw-r--r--sparkybe-onap-service/src/test/resources/sync/aai/aai-traversal/generic-query/service-instance-56.json8
-rw-r--r--sparkybe-onap-service/src/test/resources/sync/aai/aai-traversal/generic-query/service-instance-57.json8
-rw-r--r--sparkybe-onap-service/src/test/resources/sync/aai/aai-traversal/generic-query/service-instance-58.json8
-rw-r--r--sparkybe-onap-service/src/test/resources/sync/aai/aai-traversal/generic-query/service-instance-59.json8
-rw-r--r--sparkybe-onap-service/src/test/resources/sync/aai/aai-traversal/generic-query/service-instance/service-instance-54.json8
-rw-r--r--sparkybe-onap-service/src/test/resources/sync/aai/aai-traversal/generic-query/service-instance/service-instance-55.json8
-rw-r--r--sparkybe-onap-service/src/test/resources/sync/aai/aai-traversal/generic-query/service-subscription/service-subscription-2.json8
-rw-r--r--sparkybe-onap-service/src/test/resources/sync/aai/activeInventory_complex_nodesQuery_response.json24
-rw-r--r--sparkybe-onap-service/src/test/resources/sync/aai/activeInventory_generic-vnf_nodesQuery_response.json16
-rw-r--r--sparkybe-onap-service/src/test/resources/sync/aai/activeInventory_service-subscription_nodesQuery_response.json16
-rw-r--r--sparkybe-onap-service/src/test/resources/sync/aai/complex1_fullDepth_aaiEntityRetrieval.json30
-rw-r--r--sparkybe-onap-service/src/test/resources/sync/aai/complex2_fullDepth_aaiEntityRetrieval.json30
-rw-r--r--sparkybe-onap-service/src/test/resources/sync/aai/complex3_fullDepth_aaiEntityRetrieval.json30
-rw-r--r--sparkybe-onap-service/src/test/resources/sync/aai/complex4_fullDepth_aaiEntityRetrieval.json30
-rw-r--r--sparkybe-onap-service/src/test/resources/sync/aai/complex5_fullDepth_aaiEntityRetrieval.json30
-rw-r--r--sparkybe-onap-service/src/test/resources/sync/aai/generic-vnf-generic-vnf-1_full_depth.json136
-rw-r--r--sparkybe-onap-service/src/test/resources/sync/aai/generic-vnf-generic-vnf-2_full_depth.json118
-rw-r--r--sparkybe-onap-service/src/test/resources/sync/aai/generic-vnf-generic-vnf-3_full_depth.json30
-rw-r--r--sparkybe-onap-service/src/test/resources/sync/aai/service-subscription-service-subscription-1.json12
-rw-r--r--sparkybe-onap-service/src/test/resources/sync/aai/service-subscription-service-subscription-2.json350
-rw-r--r--sparkybe-onap-service/src/test/resources/sync/aai/service-subscription-service-subscription-3.json12
-rw-r--r--sparkybe-onap-service/src/test/resources/sync/auth/emptyCert.p120
-rw-r--r--sparkybe-onap-service/src/test/resources/sync/etc/autoSuggestMappings.json1
-rw-r--r--sparkybe-onap-service/src/test/resources/sync/etc/autoSuggestSettings.json1
-rw-r--r--sparkybe-onap-service/src/test/resources/user-auth-reader/authorized-users-empty.config0
-rw-r--r--sparkybe-onap-service/src/test/resources/user-auth-reader/authorized-users.config3
-rw-r--r--sparkybe-onap-service/src/test/resources/user-validator/authorized-users.config3
422 files changed, 53750 insertions, 0 deletions
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/aggregatevnf/search/AggregateSummaryProcessor.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/aggregatevnf/search/AggregateSummaryProcessor.java
new file mode 100644
index 0000000..be29889
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/aggregatevnf/search/AggregateSummaryProcessor.java
@@ -0,0 +1,210 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.aggregatevnf.search;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.json.JsonObject;
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.camel.Exchange;
+import org.json.JSONArray;
+import org.json.JSONObject;
+import org.onap.aai.cl.api.Logger;
+import org.onap.aai.cl.eelf.LoggerFactory;
+import org.onap.aai.restclient.client.OperationResult;
+import org.onap.aai.sparky.dal.ElasticSearchAdapter;
+import org.onap.aai.sparky.logging.AaiUiMsgs;
+import org.onap.aai.sparky.logging.util.ServletUtils;
+import org.onap.aai.sparky.search.filters.FilterQueryBuilder;
+import org.onap.aai.sparky.search.filters.config.FiltersConfig;
+import org.onap.aai.sparky.search.filters.entity.SearchFilter;
+import org.onap.aai.sparky.viewandinspect.config.SparkyConstants;
+
+public class AggregateSummaryProcessor {
+
+ private static final Logger LOG = LoggerFactory.getInstance().getLogger(AggregateSummaryProcessor.class);
+
+ private static final String KEY_FILTERS = "filters";
+
+ private ElasticSearchAdapter elasticSearchAdapter = null;
+
+ private String vnfAggregationIndexName;
+ private FiltersConfig filtersConfig;
+
+ public AggregateSummaryProcessor(ElasticSearchAdapter elasticSearchAdapter, FiltersConfig filtersConfig) {
+ this.elasticSearchAdapter = elasticSearchAdapter;
+ this.filtersConfig = filtersConfig;
+ }
+
+ public void setVnfAggregationIndexName(String vnfAggregationIndexName) {
+ this.vnfAggregationIndexName = vnfAggregationIndexName;
+ }
+
+ public void getFilteredAggregation(Exchange exchange) {
+
+ HttpServletRequest request = exchange.getIn().getBody(HttpServletRequest.class);
+ ServletUtils.setUpMdcContext(exchange, request);
+
+
+ try {
+ String payload = exchange.getIn().getBody(String.class);
+
+ if (payload == null || payload.isEmpty()) {
+
+ LOG.error(AaiUiMsgs.SEARCH_SERVLET_ERROR, "Request Payload is empty");
+
+ /*
+ * Don't throw back an error, just return an empty set
+ */
+
+ } else {
+
+ JSONObject parameters = new JSONObject(payload);
+
+ JSONArray requestFilters = null;
+ if (parameters.has(KEY_FILTERS)) {
+ requestFilters = parameters.getJSONArray(KEY_FILTERS);
+ } else {
+
+ JSONObject zeroResponsePayload = new JSONObject();
+ zeroResponsePayload.put("count", 0);
+ //response.setStatus(Status.SUCCESS_OK);
+ //response.setEntity(zeroResponsePayload.toString(), MediaType.APPLICATION_JSON);
+ exchange.getOut().setBody(zeroResponsePayload.toString());
+
+ LOG.error(AaiUiMsgs.ERROR_FILTERS_NOT_FOUND);
+ return;
+ }
+
+ if (requestFilters != null && requestFilters.length() > 0) {
+ List<JSONObject> filtersToQuery = new ArrayList<JSONObject>();
+ for(int i = 0; i < requestFilters.length(); i++) {
+ JSONObject filterEntry = requestFilters.getJSONObject(i);
+ filtersToQuery.add(filterEntry);
+ }
+
+ String jsonResponsePayload = getVnfFilterAggregations(filtersToQuery);
+ exchange.getOut().setHeader(Exchange.HTTP_RESPONSE_CODE, 200);
+ exchange.getOut().setHeader(Exchange.CONTENT_TYPE, "application/json");
+ exchange.getOut().setBody(jsonResponsePayload);
+
+ } else {
+ String emptyResponse = getEmptyAggResponse();
+ exchange.getOut().setHeader(Exchange.HTTP_RESPONSE_CODE, 200);
+ exchange.getOut().setHeader(Exchange.CONTENT_TYPE, "application/json");
+ exchange.getOut().setBody(emptyResponse);
+ LOG.error(AaiUiMsgs.ERROR_FILTERS_NOT_FOUND);
+ }
+ }
+ } catch (Exception exc) {
+ LOG.error(AaiUiMsgs.ERROR_GENERIC, "FilterProcessor failed to get filter list due to error = " + exc.getMessage());
+ }
+ }
+
+ private String getEmptyAggResponse() {
+ JSONObject aggPayload = new JSONObject();
+ aggPayload.put("totalChartHits", 0);
+ aggPayload.put("buckets", new JSONArray());
+ JSONObject payload = new JSONObject();
+ payload.append("groupby_aggregation", aggPayload);
+
+ return payload.toString();
+ }
+
+ private static final String FILTER_ID_KEY = "filterId";
+ private static final String FILTER_VALUE_KEY = "filterValue";
+ private static final int DEFAULT_SHOULD_MATCH_SCORE = 1;
+ private static final String VNF_FILTER_AGGREGATION = "vnfFilterAggregation";
+
+
+ private String getVnfFilterAggregations(List<JSONObject> filtersToQuery) throws IOException {
+
+ List<SearchFilter> searchFilters = new ArrayList<SearchFilter>();
+ for(JSONObject filterEntry : filtersToQuery) {
+
+ String filterId = filterEntry.getString(FILTER_ID_KEY);
+ if(filterId != null) {
+ SearchFilter filter = new SearchFilter();
+ filter.setFilterId(filterId);
+
+ if(filterEntry.has(FILTER_VALUE_KEY)) {
+ String filterValue = filterEntry.getString(FILTER_VALUE_KEY);
+ filter.addValue(filterValue);
+ }
+
+ searchFilters.add(filter);
+ }
+ }
+
+ // Create query for summary by entity type
+ JsonObject vnfSearch = FilterQueryBuilder.createCombinedBoolAndAggQuery(filtersConfig, searchFilters, DEFAULT_SHOULD_MATCH_SCORE);
+
+ // Parse response for summary by entity type query
+ OperationResult opResult = elasticSearchAdapter.doPost(
+ elasticSearchAdapter.buildElasticSearchUrlForApi(vnfAggregationIndexName,
+ SparkyConstants.ES_SEARCH_API),
+ vnfSearch.toString(), javax.ws.rs.core.MediaType.APPLICATION_JSON_TYPE);
+
+ if ( opResult.wasSuccessful()) {
+ return buildAggregateVnfResponseJson(opResult.getResult());
+ } else {
+ return buildEmptyAggregateVnfResponseJson();
+ }
+ }
+
+ private String buildEmptyAggregateVnfResponseJson() {
+ JSONObject finalOutputToFe = new JSONObject();
+ finalOutputToFe.put("total", 0);
+ return finalOutputToFe.toString();
+ }
+
+ private String buildAggregateVnfResponseJson(String responseJsonStr) {
+
+ JSONObject finalOutputToFe = new JSONObject();
+ JSONObject responseJson = new JSONObject(responseJsonStr);
+
+
+ JSONObject hits = responseJson.getJSONObject("hits");
+ int totalHits = hits.getInt("total");
+ finalOutputToFe.put("total", totalHits);
+
+ JSONObject aggregations = responseJson.getJSONObject("aggregations");
+ String[] aggKeys = JSONObject.getNames(aggregations);
+ JSONObject aggregationsList = new JSONObject();
+
+ for(String aggName : aggKeys) {
+ JSONObject aggregation = aggregations.getJSONObject(aggName);
+ JSONArray buckets = aggregation.getJSONArray("buckets");
+ aggregationsList.put(aggName, buckets);
+ }
+
+ finalOutputToFe.put("aggregations", aggregationsList);
+
+ return finalOutputToFe.toString();
+ }
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/aggregatevnf/search/AggregateVnfSearchProvider.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/aggregatevnf/search/AggregateVnfSearchProvider.java
new file mode 100644
index 0000000..6e7b456
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/aggregatevnf/search/AggregateVnfSearchProvider.java
@@ -0,0 +1,129 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.aggregatevnf.search;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.json.JsonObject;
+import javax.ws.rs.core.MediaType;
+
+import org.json.JSONArray;
+import org.json.JSONObject;
+import org.onap.aai.cl.api.Logger;
+import org.onap.aai.cl.eelf.LoggerFactory;
+import org.onap.aai.restclient.client.OperationResult;
+import org.onap.aai.sparky.common.search.CommonSearchSuggestion;
+import org.onap.aai.sparky.dal.ElasticSearchAdapter;
+import org.onap.aai.sparky.logging.AaiUiMsgs;
+import org.onap.aai.sparky.search.api.SearchProvider;
+import org.onap.aai.sparky.search.entity.QuerySearchEntity;
+import org.onap.aai.sparky.search.entity.SearchSuggestion;
+import org.onap.aai.sparky.search.filters.entity.UiFilterValueEntity;
+import org.onap.aai.sparky.util.NodeUtils;
+import org.onap.aai.sparky.viewandinspect.config.SparkyConstants;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+public class AggregateVnfSearchProvider implements SearchProvider {
+
+ private static final Logger LOG = LoggerFactory.getInstance().getLogger(AggregateVnfSearchProvider.class);
+
+ private ObjectMapper mapper;
+ private ElasticSearchAdapter elasticSearchAdapter = null;
+ private String autoSuggestIndexName;
+ private String vnfSearchSuggestionRoute;
+
+ public AggregateVnfSearchProvider(ElasticSearchAdapter elasticSearchAdapter,
+ String autoSuggestIndexName, String vnfSearchSuggestionRoute) {
+ mapper = new ObjectMapper();
+ this.elasticSearchAdapter = elasticSearchAdapter;
+ this.autoSuggestIndexName = autoSuggestIndexName;
+ this.vnfSearchSuggestionRoute = vnfSearchSuggestionRoute;
+ }
+
+ public void setAutoSuggestIndexName(String autoSuggestIndexName) {
+ this.autoSuggestIndexName = autoSuggestIndexName;
+ }
+
+ @Override
+ public List<SearchSuggestion> search(QuerySearchEntity queryRequest) {
+
+ List<SearchSuggestion> returnList = new ArrayList<SearchSuggestion>();
+
+ try {
+
+ /* Create suggestions query */
+ JsonObject vnfSearch = VnfSearchQueryBuilder.createSuggestionsQuery(String.valueOf(queryRequest.getMaxResults()), queryRequest.getQueryStr());
+
+ /* Parse suggestions response */
+ OperationResult opResult = elasticSearchAdapter.doPost(
+ elasticSearchAdapter.buildElasticSearchUrlForApi(autoSuggestIndexName,
+ SparkyConstants.ES_SUGGEST_API),
+ vnfSearch.toString(), MediaType.APPLICATION_JSON_TYPE);
+
+ String result = opResult.getResult();
+
+ if (!opResult.wasSuccessful()) {
+ LOG.error(AaiUiMsgs.ERROR_PARSING_JSON_PAYLOAD_VERBOSE, result);
+ return returnList;
+ }
+
+ JSONObject responseJson = new JSONObject(result);
+ String suggestionsKey = "vnfs";
+ JSONArray suggestionsArray = new JSONArray();
+ JSONArray suggestions = responseJson.getJSONArray(suggestionsKey);
+ if (suggestions.length() > 0) {
+ suggestionsArray = suggestions.getJSONObject(0).getJSONArray("options");
+ for (int i = 0; i < suggestionsArray.length(); i++) {
+ JSONObject querySuggestion = suggestionsArray.getJSONObject(i);
+ if (querySuggestion != null) {
+ CommonSearchSuggestion responseSuggestion = new CommonSearchSuggestion();
+ responseSuggestion.setText(querySuggestion.getString("text"));
+ responseSuggestion.setRoute(vnfSearchSuggestionRoute);
+ responseSuggestion.setHashId(NodeUtils.generateUniqueShaDigest(querySuggestion.getString("text")));
+
+ // Extract filter list from JSON and add to response suggestion
+ JSONObject payload = querySuggestion.getJSONObject("payload");
+ if (payload.length() > 0) {
+ JSONArray filterList = payload.getJSONArray("filterList");
+ for (int filter = 0; filter < filterList.length(); filter++) {
+ String filterValueString = filterList.getJSONObject(filter).toString();
+ UiFilterValueEntity filterValue = mapper.readValue(filterValueString, UiFilterValueEntity.class);
+ responseSuggestion.getFilterValues().add(filterValue);
+ }
+ }
+ returnList.add(responseSuggestion);
+ }
+ }
+ }
+ } catch (Exception exc) {
+ LOG.error(AaiUiMsgs.ERROR_GENERIC, "Search failed due to error = " + exc.getMessage());
+ }
+
+ return returnList;
+ }
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/aggregatevnf/search/VnfSearchQueryBuilder.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/aggregatevnf/search/VnfSearchQueryBuilder.java
new file mode 100644
index 0000000..2645433
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/aggregatevnf/search/VnfSearchQueryBuilder.java
@@ -0,0 +1,176 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.aggregatevnf.search;
+
+import java.util.Map;
+
+import javax.json.Json;
+import javax.json.JsonArray;
+import javax.json.JsonArrayBuilder;
+import javax.json.JsonObject;
+import javax.json.JsonObjectBuilder;
+
+
+/**
+ * Build a JSON payload to send to elastic search to get vnf search data.
+ */
+
+public class VnfSearchQueryBuilder {
+
+
+ /**
+ * Creates the suggestions query.
+ *
+ * @param maxResults maximum number of suggestions to fetch
+ * @param queryStr query string
+ * @return the json object
+ */
+
+ /*
+ * { "vnfs" : { "text" : "VNFs", "completion" : { "field" : "entity_suggest", "size": 1 } } }
+ */
+ public static JsonObject createSuggestionsQuery(String maxResults, String queryStr) {
+ JsonObjectBuilder jsonBuilder = Json.createObjectBuilder();
+
+ JsonObjectBuilder completionBlob = Json.createObjectBuilder();
+ completionBlob.add("field", "entity_suggest");
+ completionBlob.add("size", maxResults);
+
+ JsonObjectBuilder jsonAllBuilder = Json.createObjectBuilder();
+ jsonAllBuilder.add("text", queryStr);
+ jsonAllBuilder.add("completion", completionBlob);
+
+ jsonBuilder.add("vnfs", jsonAllBuilder.build());
+ return jsonBuilder.build();
+ }
+
+ public static JsonObject getTermBlob(String key, String value) {
+ JsonObjectBuilder termBlobBuilder = Json.createObjectBuilder();
+ JsonObjectBuilder jsonBuilder = Json.createObjectBuilder().add(key, value);
+ return termBlobBuilder.add("term", jsonBuilder.build()).build();
+ }
+
+ public static void getSummaryAggsBlob(JsonObjectBuilder aggsBlobBuilder, String aggsKey,
+ int resultSize) {
+ JsonObjectBuilder fieldBuilder =
+ Json.createObjectBuilder().add("field", aggsKey).add("size", resultSize);
+ JsonObject aggsFieldBlob = fieldBuilder.build();
+ JsonObjectBuilder defaultBlobBuilder = Json.createObjectBuilder().add("terms", aggsFieldBlob);
+ JsonObject defaultBlob = defaultBlobBuilder.build();
+ aggsBlobBuilder.add("default", defaultBlob);
+ }
+
+ public static void buildSingleTermCountQuery(JsonObjectBuilder jsonBuilder, String key,
+ String value) {
+ jsonBuilder.add("query", getTermBlob(key, value));
+ }
+
+ public static void buildSingleTermSummaryQuery(JsonObjectBuilder jsonBuilder, String key,
+ String value, String groupByKey) {
+ JsonObjectBuilder queryBlobBuilder = Json.createObjectBuilder();
+ JsonObjectBuilder aggsBlobBuilder = Json.createObjectBuilder();
+
+ queryBlobBuilder.add("constant_score",
+ Json.createObjectBuilder().add("filter", getTermBlob(key, value)));
+
+ getSummaryAggsBlob(aggsBlobBuilder, groupByKey, 0);
+
+ jsonBuilder.add("query", queryBlobBuilder.build());
+ jsonBuilder.add("aggs", aggsBlobBuilder.build());
+ }
+
+ public static void buildMultiTermSummaryQuery(JsonObjectBuilder jsonBuilder,
+ Map<String, String> attributes, String groupByKey) {
+ JsonObjectBuilder queryBlobBuilder = Json.createObjectBuilder();
+ JsonObjectBuilder aggsBlobBuilder = Json.createObjectBuilder();
+ JsonArrayBuilder mustBlobBuilder = Json.createArrayBuilder();
+ for (String key : attributes.keySet()) {
+ mustBlobBuilder.add(getTermBlob(key, attributes.get(key)));
+ }
+ JsonArray mustBlob = mustBlobBuilder.build();
+
+ queryBlobBuilder.add("constant_score", Json.createObjectBuilder().add("filter",
+ Json.createObjectBuilder().add("bool", Json.createObjectBuilder().add("must", mustBlob))));
+
+ getSummaryAggsBlob(aggsBlobBuilder, groupByKey, 0);
+
+ jsonBuilder.add("query", queryBlobBuilder.build());
+ jsonBuilder.add("aggs", aggsBlobBuilder.build());
+ }
+
+ public static void buildZeroTermSummaryQuery(JsonObjectBuilder jsonBuilder, String groupByKey) {
+ JsonObjectBuilder aggsBlobBuilder = Json.createObjectBuilder();
+
+ getSummaryAggsBlob(aggsBlobBuilder, groupByKey, 0);
+
+ jsonBuilder.add("aggs", aggsBlobBuilder.build());
+ }
+
+ public static void buildMultiTermCountQuery(JsonObjectBuilder jsonBuilder,
+ Map<String, String> attributes) {
+ JsonArrayBuilder mustBlobBuilder = Json.createArrayBuilder();
+ for (String key : attributes.keySet()) {
+ mustBlobBuilder.add(getTermBlob(key, attributes.get(key)));
+ }
+ jsonBuilder.add("query", Json.createObjectBuilder().add("bool",
+ Json.createObjectBuilder().add("must", mustBlobBuilder)));
+ }
+
+
+
+ public static JsonObject createSummaryByEntityTypeQuery(Map<String, String> attributes,
+ String groupByKey) {
+ JsonObjectBuilder jsonBuilder = Json.createObjectBuilder();
+ jsonBuilder.add("size", "0"); // avoid source data
+ if (attributes.size() == 0) {
+ buildZeroTermSummaryQuery(jsonBuilder, groupByKey);
+ } else if (attributes.size() == 1) {
+ Map.Entry<String, String> entry = attributes.entrySet().iterator().next();
+ buildSingleTermSummaryQuery(jsonBuilder, entry.getKey(), entry.getValue(), groupByKey);
+ } else {
+ buildMultiTermSummaryQuery(jsonBuilder, attributes, groupByKey);
+ }
+ return jsonBuilder.build();
+ }
+
+ public static JsonObject createEntityCountsQuery(Map<String, String> attributes) {
+ JsonObjectBuilder jsonBuilder = Json.createObjectBuilder();
+ if (attributes.size() == 1) {
+ Map.Entry<String, String> entry = attributes.entrySet().iterator().next();
+ buildSingleTermCountQuery(jsonBuilder, entry.getKey(), entry.getValue());
+ } else {
+ buildMultiTermCountQuery(jsonBuilder, attributes);
+ }
+ return jsonBuilder.build();
+ }
+
+ public static JsonArray getSortCriteria(String sortFieldName, String sortOrder) {
+ JsonArrayBuilder jsonBuilder = Json.createArrayBuilder();
+ jsonBuilder.add(Json.createObjectBuilder().add(sortFieldName,
+ Json.createObjectBuilder().add("order", sortOrder)));
+
+ return jsonBuilder.build();
+ }
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/aggregation/sync/AggregationSyncControllerFactory.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/aggregation/sync/AggregationSyncControllerFactory.java
new file mode 100644
index 0000000..8681853
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/aggregation/sync/AggregationSyncControllerFactory.java
@@ -0,0 +1,241 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.aggregation.sync;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import org.onap.aai.cl.api.Logger;
+import org.onap.aai.cl.eelf.LoggerFactory;
+import org.onap.aai.sparky.config.oxm.OxmEntityLookup;
+import org.onap.aai.sparky.config.oxm.SuggestionEntityDescriptor;
+import org.onap.aai.sparky.config.oxm.SuggestionEntityLookup;
+import org.onap.aai.sparky.dal.ActiveInventoryAdapter;
+import org.onap.aai.sparky.dal.ElasticSearchAdapter;
+import org.onap.aai.sparky.logging.AaiUiMsgs;
+import org.onap.aai.sparky.sync.ElasticSearchIndexCleaner;
+import org.onap.aai.sparky.sync.ElasticSearchSchemaFactory;
+import org.onap.aai.sparky.sync.IndexCleaner;
+import org.onap.aai.sparky.sync.IndexIntegrityValidator;
+import org.onap.aai.sparky.sync.SyncController;
+import org.onap.aai.sparky.sync.SyncControllerImpl;
+import org.onap.aai.sparky.sync.SyncControllerRegistrar;
+import org.onap.aai.sparky.sync.SyncControllerRegistry;
+import org.onap.aai.sparky.sync.config.ElasticSearchEndpointConfig;
+import org.onap.aai.sparky.sync.config.ElasticSearchSchemaConfig;
+import org.onap.aai.sparky.sync.config.NetworkStatisticsConfig;
+import org.onap.aai.sparky.sync.config.SyncControllerConfig;
+
+public class AggregationSyncControllerFactory implements SyncControllerRegistrar {
+
+ private static final Logger LOG =
+ LoggerFactory.getInstance().getLogger(AggregationSyncControllerFactory.class);
+
+ private ActiveInventoryAdapter aaiAdapter;
+ private ElasticSearchAdapter esAdapter;
+ private SuggestionEntityLookup suggestionEntityLookup;
+
+ private Map<String, String> aggregationEntityToIndexMap;
+ private Map<String, ElasticSearchSchemaConfig> indexNameToSchemaConfigMap;
+
+ private ElasticSearchEndpointConfig elasticSearchEndpointConfig;
+ private SyncControllerConfig syncControllerConfig;
+ private SyncControllerRegistry syncControllerRegistry;
+ private NetworkStatisticsConfig aaiStatConfig;
+ private NetworkStatisticsConfig esStatConfig;
+ private OxmEntityLookup oxmEntityLookup;
+ private ElasticSearchSchemaFactory elasticSearchSchemaFactory;
+
+ private List<SyncController> syncControllers;
+
+ public AggregationSyncControllerFactory(ElasticSearchEndpointConfig esEndpointConfig,
+ SyncControllerConfig syncControllerConfig, SyncControllerRegistry syncControllerRegistry,
+ SuggestionEntityLookup suggestionEntityLookup,
+ OxmEntityLookup oxmEntityLookup,
+ ElasticSearchSchemaFactory elasticSearchSchemaFactory) {
+ this.elasticSearchSchemaFactory = elasticSearchSchemaFactory;
+ this.syncControllers = new ArrayList<SyncController>();
+ this.elasticSearchEndpointConfig = esEndpointConfig;
+ this.syncControllerConfig = syncControllerConfig;
+ this.syncControllerRegistry = syncControllerRegistry;
+ this.suggestionEntityLookup = suggestionEntityLookup;
+ this.oxmEntityLookup = oxmEntityLookup;
+ }
+
+ public NetworkStatisticsConfig getAaiStatConfig() {
+ return aaiStatConfig;
+ }
+
+ public void setAaiStatConfig(NetworkStatisticsConfig aaiStatConfig) {
+ this.aaiStatConfig = aaiStatConfig;
+ }
+
+ public NetworkStatisticsConfig getEsStatConfig() {
+ return esStatConfig;
+ }
+
+ public void setEsStatConfig(NetworkStatisticsConfig esStatConfig) {
+ this.esStatConfig = esStatConfig;
+ }
+
+ public Map<String, ElasticSearchSchemaConfig> getIndexNameToSchemaConfigMap() {
+ return indexNameToSchemaConfigMap;
+ }
+
+ public void setIndexNameToSchemaConfigMap(
+ Map<String, ElasticSearchSchemaConfig> indexNameToSchemaConfigMap) {
+ this.indexNameToSchemaConfigMap = indexNameToSchemaConfigMap;
+ }
+
+ public ElasticSearchEndpointConfig getElasticSearchEndpointConfig() {
+ return elasticSearchEndpointConfig;
+ }
+
+ public void setElasticSearchEndpointConfig(
+ ElasticSearchEndpointConfig elasticSearchEndpointConfig) {
+ this.elasticSearchEndpointConfig = elasticSearchEndpointConfig;
+ }
+
+ public SyncControllerConfig getSyncControllerConfig() {
+ return syncControllerConfig;
+ }
+
+ public void setSyncControllerConfig(SyncControllerConfig syncControllerConfig) {
+ this.syncControllerConfig = syncControllerConfig;
+ }
+
+ public ActiveInventoryAdapter getAaiAdapter() {
+ return aaiAdapter;
+ }
+
+ public void setAaiAdapter(ActiveInventoryAdapter aaiAdapter) {
+ this.aaiAdapter = aaiAdapter;
+ }
+
+ public ElasticSearchAdapter getEsAdapter() {
+ return esAdapter;
+ }
+
+ public void setEsAdapter(ElasticSearchAdapter esAdapter) {
+ this.esAdapter = esAdapter;
+ }
+
+ public SuggestionEntityLookup getSuggestionEntityLookup() {
+ return suggestionEntityLookup;
+ }
+
+ public void setSuggestionEntityLookup(SuggestionEntityLookup suggestionEntityLookup) {
+ this.suggestionEntityLookup = suggestionEntityLookup;
+ }
+
+ public Map<String, String> getAggregationEntityToIndexMap() {
+ return aggregationEntityToIndexMap;
+ }
+
+ public void setAggregationEntityToIndexMap(Map<String, String> aggregationEntityToIndexMap) {
+ this.aggregationEntityToIndexMap = aggregationEntityToIndexMap;
+ }
+
+ public void buildControllers() {
+
+ if (syncControllerConfig.isEnabled()) {
+
+ Map<String, SuggestionEntityDescriptor> suggestionEntitites =
+ suggestionEntityLookup.getSuggestionSearchEntityDescriptors();
+ SyncControllerImpl aggregationSyncController = null;
+
+ for (String entityType : suggestionEntitites.keySet()) {
+
+ String indexName = aggregationEntityToIndexMap.get(entityType);
+
+ if (indexName == null) {
+ LOG.error(AaiUiMsgs.ERROR_GENERIC,
+ "Could not determine aggregation index name" + " for entity type: " + entityType);
+ continue;
+ }
+
+ try {
+
+ aggregationSyncController = new SyncControllerImpl(syncControllerConfig, entityType);
+
+ ElasticSearchSchemaConfig schemaConfig = indexNameToSchemaConfigMap.get(indexName);
+
+ if (schemaConfig == null) {
+ LOG.error(AaiUiMsgs.ERROR_GENERIC,
+ "Could not determine elastic search schema config for index name: " + indexName);
+ continue;
+ }
+
+ IndexIntegrityValidator aggregationIndexValidator = new IndexIntegrityValidator(esAdapter,
+ schemaConfig, elasticSearchEndpointConfig, elasticSearchSchemaFactory.getIndexSchema(schemaConfig));
+
+ aggregationSyncController.registerIndexValidator(aggregationIndexValidator);
+
+ AggregationSynchronizer aggSynchronizer = new AggregationSynchronizer(entityType,
+ schemaConfig, syncControllerConfig.getNumInternalSyncWorkers(),
+ syncControllerConfig.getNumSyncActiveInventoryWorkers(),
+ syncControllerConfig.getNumSyncElasticWorkers(), aaiStatConfig, esStatConfig,
+ oxmEntityLookup);
+
+ aggSynchronizer.setAaiAdapter(aaiAdapter);
+ aggSynchronizer.setElasticSearchAdapter(esAdapter);
+
+ aggregationSyncController.registerEntitySynchronizer(aggSynchronizer);
+
+ IndexCleaner entityDataIndexCleaner =
+ new ElasticSearchIndexCleaner(esAdapter, elasticSearchEndpointConfig, schemaConfig);
+
+ aggregationSyncController.registerIndexCleaner(entityDataIndexCleaner);
+
+ syncControllers.add(aggregationSyncController);
+ } catch (Exception exc) {
+
+ exc.printStackTrace();
+
+ LOG.error(AaiUiMsgs.ERROR_GENERIC,
+ "Failed to build aggregation sync controller. Error : " + exc.getMessage());
+ }
+
+ }
+ } else {
+ LOG.info(AaiUiMsgs.INFO_GENERIC, "Sync controller with name = "
+ + syncControllerConfig.getControllerName() + " is disabled");
+ }
+ }
+
+ @Override
+ public void registerController() {
+
+ buildControllers();
+
+ if ( syncControllerRegistry != null ) {
+ for ( SyncController controller : syncControllers ) {
+ syncControllerRegistry.registerSyncController(controller);
+ }
+ }
+
+ }
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/aggregation/sync/AggregationSynchronizer.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/aggregation/sync/AggregationSynchronizer.java
new file mode 100644
index 0000000..a438215
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/aggregation/sync/AggregationSynchronizer.java
@@ -0,0 +1,782 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.aggregation.sync;
+
+import static java.util.concurrent.CompletableFuture.supplyAsync;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Deque;
+import java.util.EnumSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentLinkedDeque;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Supplier;
+
+import org.onap.aai.cl.api.Logger;
+import org.onap.aai.cl.eelf.LoggerFactory;
+import org.onap.aai.cl.mdc.MdcContext;
+import org.onap.aai.restclient.client.OperationResult;
+import org.onap.aai.sparky.config.oxm.OxmEntityDescriptor;
+import org.onap.aai.sparky.config.oxm.OxmEntityLookup;
+import org.onap.aai.sparky.dal.ActiveInventoryAdapter;
+import org.onap.aai.sparky.dal.NetworkTransaction;
+import org.onap.aai.sparky.dal.rest.HttpMethod;
+import org.onap.aai.sparky.logging.AaiUiMsgs;
+import org.onap.aai.sparky.sync.AbstractEntitySynchronizer;
+import org.onap.aai.sparky.sync.IndexSynchronizer;
+import org.onap.aai.sparky.sync.SynchronizerConstants;
+import org.onap.aai.sparky.sync.config.ElasticSearchSchemaConfig;
+import org.onap.aai.sparky.sync.config.NetworkStatisticsConfig;
+import org.onap.aai.sparky.sync.entity.AggregationEntity;
+import org.onap.aai.sparky.sync.entity.MergableEntity;
+import org.onap.aai.sparky.sync.entity.SelfLinkDescriptor;
+import org.onap.aai.sparky.sync.enumeration.OperationState;
+import org.onap.aai.sparky.sync.enumeration.SynchronizerState;
+import org.onap.aai.sparky.sync.task.PerformActiveInventoryRetrieval;
+import org.onap.aai.sparky.sync.task.PerformElasticSearchPut;
+import org.onap.aai.sparky.sync.task.PerformElasticSearchRetrieval;
+import org.onap.aai.sparky.sync.task.PerformElasticSearchUpdate;
+import org.onap.aai.sparky.util.NodeUtils;
+import org.slf4j.MDC;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectReader;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+
+/**
+ * The Class AutosuggestionSynchronizer.
+ */
+public class AggregationSynchronizer extends AbstractEntitySynchronizer
+ implements IndexSynchronizer {
+
+ /**
+ * The Class RetryAggregationEntitySyncContainer.
+ */
+ private class RetryAggregationEntitySyncContainer {
+ NetworkTransaction txn;
+ AggregationEntity ae;
+
+ /**
+ * Instantiates a new retry aggregation entity sync container.
+ *
+ * @param txn the txn
+ * @param ae the se
+ */
+ public RetryAggregationEntitySyncContainer(NetworkTransaction txn, AggregationEntity ae) {
+ this.txn = txn;
+ this.ae = ae;
+ }
+
+ public NetworkTransaction getNetworkTransaction() {
+ return txn;
+ }
+
+ public AggregationEntity getAggregationEntity() {
+ return ae;
+ }
+ }
+
+ private static final Logger LOG =
+ LoggerFactory.getInstance().getLogger(AggregationSynchronizer.class);
+ private static final String INSERTION_DATE_TIME_FORMAT = "yyyyMMdd'T'HHmmssZ";
+
+ private boolean allWorkEnumerated;
+ private Deque<SelfLinkDescriptor> selflinks;
+ private Deque<RetryAggregationEntitySyncContainer> retryQueue;
+ private Map<String, Integer> retryLimitTracker;
+ protected ExecutorService esPutExecutor;
+ private ConcurrentHashMap<String, AtomicInteger> entityCounters;
+ private boolean syncInProgress;
+ private Map<String, String> contextMap;
+ private String entityType;
+ private ElasticSearchSchemaConfig schemaConfig;
+ private OxmEntityLookup oxmEntityLookup;
+
+ /**
+ * Instantiates a new entity aggregation synchronizer.
+ *
+ * @param indexName the index name
+ * @throws Exception the exception
+ */
+ public AggregationSynchronizer(String entityType, ElasticSearchSchemaConfig schemaConfig,
+ int numSyncWorkers, int numActiveInventoryWorkers, int numElasticWorkers,
+ NetworkStatisticsConfig aaiStatConfig, NetworkStatisticsConfig esStatConfig,
+ OxmEntityLookup oxmEntityLookup) throws Exception {
+
+ super(LOG, "AGGES-" + schemaConfig.getIndexName().toUpperCase(), numSyncWorkers,
+ numActiveInventoryWorkers, numElasticWorkers, schemaConfig.getIndexName(),aaiStatConfig, esStatConfig);
+
+ this.oxmEntityLookup = oxmEntityLookup;
+
+ this.schemaConfig = schemaConfig;
+ this.entityType = entityType;
+ this.allWorkEnumerated = false;
+ this.entityCounters = new ConcurrentHashMap<String, AtomicInteger>();
+ this.synchronizerName = "Entity Aggregation Synchronizer";
+ this.enabledStatFlags = EnumSet.of(StatFlag.AAI_REST_STATS, StatFlag.ES_REST_STATS);
+ this.syncInProgress = false;
+ this.allWorkEnumerated = false;
+ this.selflinks = new ConcurrentLinkedDeque<SelfLinkDescriptor>();
+ this.retryQueue = new ConcurrentLinkedDeque<RetryAggregationEntitySyncContainer>();
+ this.retryLimitTracker = new ConcurrentHashMap<String, Integer>();
+
+ this.esPutExecutor = NodeUtils.createNamedExecutor("AGGES-ES-PUT", 1, LOG);
+
+ this.aaiEntityStats.intializeEntityCounters(entityType);
+ this.esEntityStats.intializeEntityCounters(entityType);
+
+ this.contextMap = MDC.getCopyOfContextMap();
+ }
+
+ /**
+ * Collect all the work.
+ *
+ * @return the operation state
+ */
+ private OperationState collectAllTheWork() {
+ final Map<String, String> contextMap = MDC.getCopyOfContextMap();
+ final String entity = this.getEntityType();
+ try {
+
+ aaiWorkOnHand.set(1);
+
+ supplyAsync(new Supplier<Void>() {
+
+ @Override
+ public Void get() {
+ MDC.setContextMap(contextMap);
+ OperationResult typeLinksResult = null;
+ try {
+ typeLinksResult = aaiAdapter.getSelfLinksByEntityType(entity);
+ aaiWorkOnHand.decrementAndGet();
+ processEntityTypeSelfLinks(typeLinksResult);
+ } catch (Exception exc) {
+ LOG.error(AaiUiMsgs.ERROR_GENERIC, "Processing execption while building working set. Error:"
+ + exc.getMessage());
+ }
+
+ return null;
+ }
+
+ }, aaiExecutor).whenComplete((result, error) -> {
+
+ if (error != null) {
+ LOG.error(AaiUiMsgs.ERROR_GENERIC,
+ "An error occurred getting data from AAI. Error = " + error.getMessage());
+ }
+ });
+
+ while (aaiWorkOnHand.get() != 0) {
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug(AaiUiMsgs.WAIT_FOR_ALL_SELFLINKS_TO_BE_COLLECTED);
+ }
+
+ Thread.sleep(1000);
+ }
+
+ aaiWorkOnHand.set(selflinks.size());
+ allWorkEnumerated = true;
+ syncEntityTypes();
+
+ while (!isSyncDone()) {
+ performRetrySync();
+ Thread.sleep(1000);
+ }
+
+ /*
+ * Make sure we don't hang on to retries that failed which could cause issues during future
+ * syncs
+ */
+ retryLimitTracker.clear();
+
+ } catch (Exception exc) {
+ // TODO -> LOG, waht should be logged here?
+ }
+
+ return OperationState.OK;
+ }
+
+
+ /**
+ * Perform retry sync.
+ */
+ private void performRetrySync() {
+ while (retryQueue.peek() != null) {
+
+ RetryAggregationEntitySyncContainer rsc = retryQueue.poll();
+ if (rsc != null) {
+
+ AggregationEntity ae = rsc.getAggregationEntity();
+ NetworkTransaction txn = rsc.getNetworkTransaction();
+
+ String link = null;
+ try {
+ /*
+ * In this retry flow the se object has already derived its fields
+ */
+ link = elasticSearchAdapter.buildElasticSearchGetDocUrl(getIndexName(), ae.getId());
+ } catch (Exception exc) {
+ LOG.error(AaiUiMsgs.ES_FAILED_TO_CONSTRUCT_URI, exc.getLocalizedMessage());
+ }
+
+ if (link != null) {
+ NetworkTransaction retryTransaction = new NetworkTransaction();
+ retryTransaction.setLink(link);
+ retryTransaction.setEntityType(txn.getEntityType());
+ retryTransaction.setDescriptor(txn.getDescriptor());
+ retryTransaction.setOperationType(HttpMethod.GET);
+
+ /*
+ * IMPORTANT - DO NOT incrementAndGet the esWorkOnHand as this is a retry flow! We already
+ * called incrementAndGet when queuing the failed PUT!
+ */
+
+ supplyAsync(new PerformElasticSearchRetrieval(retryTransaction, elasticSearchAdapter),
+ esExecutor).whenComplete((result, error) -> {
+
+ esWorkOnHand.decrementAndGet();
+
+ if (error != null) {
+ LOG.error(AaiUiMsgs.ES_RETRIEVAL_FAILED_RESYNC, error.getLocalizedMessage());
+ } else {
+ updateElasticSearchCounters(result);
+ performDocumentUpsert(result, ae);
+ }
+ });
+ }
+
+ }
+ }
+ }
+
+ /**
+ * Perform document upsert.
+ *
+ * @param esGetTxn the es get txn
+ * @param ae the ae
+ */
+ protected void performDocumentUpsert(NetworkTransaction esGetTxn, AggregationEntity ae) {
+ /**
+ * <p>
+ * <ul>
+ * As part of the response processing we need to do the following:
+ * <li>1. Extract the version (if present), it will be the ETAG when we use the
+ * Search-Abstraction-Service
+ * <li>2. Spawn next task which is to do the PUT operation into elastic with or with the version
+ * tag
+ * <li>a) if version is null or RC=404, then standard put, no _update with version tag
+ * <li>b) if version != null, do PUT with _update?version= versionNumber in the URI to elastic
+ * </ul>
+ * </p>
+ */
+ String link = null;
+ try {
+ link = elasticSearchAdapter.buildElasticSearchGetDocUrl(getIndexName(), ae.getId());
+ } catch (Exception exc) {
+ LOG.error(AaiUiMsgs.ES_LINK_UPSERT, exc.getLocalizedMessage());
+ return;
+ }
+
+ String versionNumber = null;
+ boolean wasEntryDiscovered = false;
+ if (esGetTxn.getOperationResult().getResultCode() == 404) {
+ LOG.info(AaiUiMsgs.ES_SIMPLE_PUT, ae.getEntityPrimaryKeyValue());
+ } else if (esGetTxn.getOperationResult().getResultCode() == 200) {
+ wasEntryDiscovered = true;
+ try {
+ versionNumber = NodeUtils.extractFieldValueFromObject(
+ NodeUtils.convertJsonStrToJsonNode(esGetTxn.getOperationResult().getResult()),
+ "_version");
+ } catch (IOException exc) {
+ String message =
+ "Error extracting version number from response, aborting aggregation entity sync of "
+ + ae.getEntityPrimaryKeyValue() + ". Error - " + exc.getLocalizedMessage();
+ LOG.error(AaiUiMsgs.ERROR_EXTRACTING_FROM_RESPONSE, message);
+ return;
+ }
+ } else {
+ /*
+ * Not being a 200 does not mean a failure. eg 201 is returned for created. TODO -> Should we
+ * return.
+ */
+ LOG.error(AaiUiMsgs.ES_OPERATION_RETURN_CODE,
+ String.valueOf(esGetTxn.getOperationResult().getResultCode()));
+ return;
+ }
+
+ try {
+ String jsonPayload = null;
+ if (wasEntryDiscovered) {
+ try {
+ ArrayList<JsonNode> sourceObject = new ArrayList<JsonNode>();
+ NodeUtils.extractObjectsByKey(
+ NodeUtils.convertJsonStrToJsonNode(esGetTxn.getOperationResult().getResult()),
+ "_source", sourceObject);
+
+ if (!sourceObject.isEmpty()) {
+ String responseSource = NodeUtils.convertObjectToJson(sourceObject.get(0), false);
+ MergableEntity me = mapper.readValue(responseSource, MergableEntity.class);
+ ObjectReader updater = mapper.readerForUpdating(me);
+ MergableEntity merged = updater.readValue(ae.getAsJson());
+ jsonPayload = mapper.writeValueAsString(merged);
+ }
+ } catch (IOException exc) {
+ String message =
+ "Error extracting source value from response, aborting aggregation entity sync of "
+ + ae.getEntityPrimaryKeyValue() + ". Error - " + exc.getLocalizedMessage();
+ LOG.error(AaiUiMsgs.ERROR_EXTRACTING_FROM_RESPONSE, message);
+ return;
+ }
+ } else {
+ jsonPayload = ae.getAsJson();
+ }
+
+ if (wasEntryDiscovered) {
+ if (versionNumber != null && jsonPayload != null) {
+
+ String requestPayload =
+ elasticSearchAdapter.buildBulkImportOperationRequest(schemaConfig.getIndexName(),
+ schemaConfig.getIndexDocType(), ae.getId(), versionNumber, jsonPayload);
+
+ NetworkTransaction transactionTracker = new NetworkTransaction();
+ transactionTracker.setEntityType(esGetTxn.getEntityType());
+ transactionTracker.setDescriptor(esGetTxn.getDescriptor());
+ transactionTracker.setOperationType(HttpMethod.PUT);
+
+ esWorkOnHand.incrementAndGet();
+ supplyAsync(new PerformElasticSearchUpdate(elasticSearchAdapter.getBulkUrl(),
+ requestPayload, elasticSearchAdapter, transactionTracker), esPutExecutor)
+ .whenComplete((result, error) -> {
+
+ esWorkOnHand.decrementAndGet();
+
+ if (error != null) {
+ String message = "Aggregation entity sync UPDATE PUT error - "
+ + error.getLocalizedMessage();
+ LOG.error(AaiUiMsgs.ERROR_GENERIC, message);
+ } else {
+ updateElasticSearchCounters(result);
+ processStoreDocumentResult(result, esGetTxn, ae);
+ }
+ });
+ }
+
+ } else {
+ if (link != null && jsonPayload != null) {
+
+ NetworkTransaction updateElasticTxn = new NetworkTransaction();
+ updateElasticTxn.setLink(link);
+ updateElasticTxn.setEntityType(esGetTxn.getEntityType());
+ updateElasticTxn.setDescriptor(esGetTxn.getDescriptor());
+ updateElasticTxn.setOperationType(HttpMethod.PUT);
+
+ esWorkOnHand.incrementAndGet();
+ supplyAsync(new PerformElasticSearchPut(jsonPayload, updateElasticTxn, elasticSearchAdapter),
+ esPutExecutor).whenComplete((result, error) -> {
+
+ esWorkOnHand.decrementAndGet();
+
+ if (error != null) {
+ String message =
+ "Aggregation entity sync UPDATE PUT error - " + error.getLocalizedMessage();
+ LOG.error(AaiUiMsgs.ERROR_GENERIC, message);
+ } else {
+ updateElasticSearchCounters(result);
+ processStoreDocumentResult(result, esGetTxn, ae);
+ }
+ });
+ }
+ }
+ } catch (Exception exc) {
+ String message = "Exception caught during aggregation entity sync PUT operation. Message - "
+ + exc.getLocalizedMessage();
+ LOG.error(AaiUiMsgs.ERROR_GENERIC, message);
+ }
+ }
+
+ /**
+ * Should allow retry.
+ *
+ * @param id the id
+ * @return true, if successful
+ */
+ private boolean shouldAllowRetry(String id) {
+ boolean isRetryAllowed = true;
+ if (retryLimitTracker.get(id) != null) {
+ Integer currentCount = retryLimitTracker.get(id);
+ if (currentCount.intValue() >= RETRY_COUNT_PER_ENTITY_LIMIT.intValue()) {
+ isRetryAllowed = false;
+ String message = "Aggregation entity re-sync limit reached for " + id
+ + ", re-sync will no longer be attempted for this entity";
+ LOG.error(AaiUiMsgs.ERROR_GENERIC, message);
+ } else {
+ Integer newCount = new Integer(currentCount.intValue() + 1);
+ retryLimitTracker.put(id, newCount);
+ }
+ } else {
+ Integer firstRetryCount = new Integer(1);
+ retryLimitTracker.put(id, firstRetryCount);
+ }
+
+ return isRetryAllowed;
+ }
+
+ /**
+ * Process store document result.
+ *
+ * @param esPutResult the es put result
+ * @param esGetResult the es get result
+ * @param ae the ae
+ */
+ private void processStoreDocumentResult(NetworkTransaction esPutResult,
+ NetworkTransaction esGetResult, AggregationEntity ae) {
+
+ OperationResult or = esPutResult.getOperationResult();
+
+ if (!or.wasSuccessful()) {
+ if (or.getResultCode() == VERSION_CONFLICT_EXCEPTION_CODE) {
+
+ if (shouldAllowRetry(ae.getId())) {
+ esWorkOnHand.incrementAndGet();
+
+ RetryAggregationEntitySyncContainer rsc =
+ new RetryAggregationEntitySyncContainer(esGetResult, ae);
+ retryQueue.push(rsc);
+
+ String message = "Store document failed during aggregation entity synchronization"
+ + " due to version conflict. Entity will be re-synced.";
+ LOG.warn(AaiUiMsgs.ERROR_GENERIC, message);
+ }
+ } else {
+ String message =
+ "Store document failed during aggregation entity synchronization with result code "
+ + or.getResultCode() + " and result message " + or.getResult();
+ LOG.error(AaiUiMsgs.ERROR_GENERIC, message);
+ }
+ }
+ }
+
+ /**
+ * Sync entity types.
+ */
+ private void syncEntityTypes() {
+
+ while (selflinks.peek() != null) {
+
+ SelfLinkDescriptor linkDescriptor = selflinks.poll();
+ aaiWorkOnHand.decrementAndGet();
+
+ OxmEntityDescriptor descriptor = null;
+
+ if (linkDescriptor.getSelfLink() != null && linkDescriptor.getEntityType() != null) {
+
+ descriptor = oxmEntityLookup.getEntityDescriptors().get(linkDescriptor.getEntityType());
+
+ if (descriptor == null) {
+ LOG.error(AaiUiMsgs.MISSING_ENTITY_DESCRIPTOR, linkDescriptor.getEntityType());
+ // go to next element in iterator
+ continue;
+ }
+
+ NetworkTransaction txn = new NetworkTransaction();
+ txn.setDescriptor(descriptor);
+ txn.setLink(linkDescriptor.getSelfLink());
+ txn.setOperationType(HttpMethod.GET);
+ txn.setEntityType(linkDescriptor.getEntityType());
+
+ aaiWorkOnHand.incrementAndGet();
+
+ supplyAsync(new PerformActiveInventoryRetrieval(txn, aaiAdapter), aaiExecutor)
+ .whenComplete((result, error) -> {
+
+ aaiWorkOnHand.decrementAndGet();
+
+ if (error != null) {
+ LOG.error(AaiUiMsgs.AAI_RETRIEVAL_FAILED_GENERIC, error.getLocalizedMessage());
+ } else {
+ if (result == null) {
+ LOG.error(AaiUiMsgs.AAI_RETRIEVAL_FAILED_FOR_SELF_LINK,
+ linkDescriptor.getSelfLink());
+ } else {
+ updateActiveInventoryCounters(result);
+ fetchDocumentForUpsert(result);
+ }
+ }
+ });
+ }
+
+ }
+
+ }
+
+ /**
+ * Fetch document for upsert.
+ *
+ * @param txn the txn
+ */
+ private void fetchDocumentForUpsert(NetworkTransaction txn) {
+ // modified
+ if (!txn.getOperationResult().wasSuccessful()) {
+ String message = "Self link failure. Result - " + txn.getOperationResult().getResult();
+ LOG.error(AaiUiMsgs.ERROR_GENERIC, message);
+ return;
+ }
+
+ try {
+ final String jsonResult = txn.getOperationResult().getResult();
+ if (jsonResult != null && jsonResult.length() > 0) {
+
+ AggregationEntity ae = new AggregationEntity();
+ ae.setLink(ActiveInventoryAdapter.extractResourcePath(txn.getLink()));
+ populateAggregationEntityDocument(ae, jsonResult, txn.getDescriptor());
+ ae.deriveFields();
+
+ String link = null;
+ try {
+ link = elasticSearchAdapter.buildElasticSearchGetDocUrl(getIndexName(), ae.getId());
+ } catch (Exception exc) {
+ LOG.error(AaiUiMsgs.ES_FAILED_TO_CONSTRUCT_QUERY, exc.getLocalizedMessage());
+ }
+
+ if (link != null) {
+ NetworkTransaction n2 = new NetworkTransaction();
+ n2.setLink(link);
+ n2.setEntityType(txn.getEntityType());
+ n2.setDescriptor(txn.getDescriptor());
+ n2.setOperationType(HttpMethod.GET);
+
+ esWorkOnHand.incrementAndGet();
+
+ supplyAsync(new PerformElasticSearchRetrieval(n2, elasticSearchAdapter), esExecutor)
+ .whenComplete((result, error) -> {
+
+ esWorkOnHand.decrementAndGet();
+
+ if (error != null) {
+ LOG.error(AaiUiMsgs.ES_RETRIEVAL_FAILED, error.getLocalizedMessage());
+ } else {
+ updateElasticSearchCounters(result);
+ performDocumentUpsert(result, ae);
+ }
+ });
+ }
+ }
+
+ } catch (JsonProcessingException exc) {
+ LOG.error(AaiUiMsgs.ERROR_GENERIC,
+ "There was a JSON processing error fetching the elastic document for upsert. Error: "
+ + exc.getMessage());
+ } catch (IOException exc) {
+ LOG.error(AaiUiMsgs.ERROR_GENERIC,
+ "There was an IO error fetching the elastic document for upsert. Error: " + exc.getMessage());
+ }
+ }
+
+
+ /**
+ * Populate aggregation entity document.
+ *
+ * @param doc the doc
+ * @param result the result
+ * @param resultDescriptor the result descriptor
+ * @throws JsonProcessingException the json processing exception
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ protected void populateAggregationEntityDocument(AggregationEntity doc, String result,
+ OxmEntityDescriptor resultDescriptor) throws JsonProcessingException, IOException {
+ doc.setEntityType(resultDescriptor.getEntityName());
+ JsonNode entityNode = mapper.readTree(result);
+ Map<String, Object> map = mapper.convertValue(entityNode, Map.class);
+ doc.copyAttributeKeyValuePair(map);
+ }
+
+ /**
+ * Process entity type self links.
+ *
+ * @param operationResult the operation result
+ */
+ private void processEntityTypeSelfLinks(OperationResult operationResult) {
+
+ JsonNode rootNode = null;
+
+ if ( operationResult == null ) {
+ return;
+ }
+
+ final String jsonResult = operationResult.getResult();
+
+ if (jsonResult != null && jsonResult.length() > 0 && operationResult.wasSuccessful()) {
+
+ try {
+ rootNode = mapper.readTree(jsonResult);
+ } catch (IOException exc) {
+ String message =
+ "Could not deserialize JSON (representing operation result) as node tree. " +
+ "Operation result = " + jsonResult + ". " + exc.getLocalizedMessage();
+ LOG.error(AaiUiMsgs.JSON_PROCESSING_ERROR, message);
+ }
+
+ JsonNode resultData = rootNode.get("result-data");
+ ArrayNode resultDataArrayNode = null;
+
+ if (resultData.isArray()) {
+ resultDataArrayNode = (ArrayNode) resultData;
+
+ Iterator<JsonNode> elementIterator = resultDataArrayNode.elements();
+ JsonNode element = null;
+
+ while (elementIterator.hasNext()) {
+ element = elementIterator.next();
+
+ final String resourceType = NodeUtils.getNodeFieldAsText(element, "resource-type");
+ final String resourceLink = NodeUtils.getNodeFieldAsText(element, "resource-link");
+
+ OxmEntityDescriptor descriptor = null;
+
+ if (resourceType != null && resourceLink != null) {
+
+ descriptor = oxmEntityLookup.getEntityDescriptors().get(resourceType);
+
+ if (descriptor == null) {
+ LOG.error(AaiUiMsgs.MISSING_ENTITY_DESCRIPTOR, resourceType);
+ // go to next element in iterator
+ continue;
+ }
+
+ selflinks.add(new SelfLinkDescriptor(resourceLink, SynchronizerConstants.NODES_ONLY_MODIFIER, resourceType));
+
+
+ }
+ }
+ }
+ }
+
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.openecomp.sparky.synchronizer.IndexSynchronizer#doSync()
+ */
+ @Override
+ public OperationState doSync() {
+ this.syncDurationInMs = -1;
+ syncStartedTimeStampInMs = System.currentTimeMillis();
+ String txnID = NodeUtils.getRandomTxnId();
+ MdcContext.initialize(txnID, "AggregationSynchronizer", "", "Sync", "");
+
+ return collectAllTheWork();
+ }
+
+ @Override
+ public SynchronizerState getState() {
+
+ if (!isSyncDone()) {
+ return SynchronizerState.PERFORMING_SYNCHRONIZATION;
+ }
+
+ return SynchronizerState.IDLE;
+
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.openecomp.sparky.synchronizer.IndexSynchronizer#getStatReport(boolean)
+ */
+ @Override
+ public String getStatReport(boolean showFinalReport) {
+ syncDurationInMs = System.currentTimeMillis() - syncStartedTimeStampInMs;
+ return getStatReport(syncDurationInMs, showFinalReport);
+ }
+
+ public String getEntityType() {
+ return entityType;
+ }
+
+ public void setEntityType(String entityType) {
+ this.entityType = entityType;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.openecomp.sparky.synchronizer.IndexSynchronizer#shutdown()
+ */
+ @Override
+ public void shutdown() {
+ this.shutdownExecutors();
+ }
+
+ @Override
+ protected boolean isSyncDone() {
+
+ int totalWorkOnHand = aaiWorkOnHand.get() + esWorkOnHand.get();
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug(AaiUiMsgs.DEBUG_GENERIC, indexName + ", isSyncDone(), totalWorkOnHand = "
+ + totalWorkOnHand + " all work enumerated = " + allWorkEnumerated);
+ }
+
+ if (totalWorkOnHand > 0 || !allWorkEnumerated) {
+ return false;
+ }
+
+ this.syncInProgress = false;
+
+ return true;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.openecomp.sparky.synchronizer.AbstractEntitySynchronizer#clearCache()
+ */
+ @Override
+ public void clearCache() {
+
+ if (syncInProgress) {
+ LOG.debug(AaiUiMsgs.DEBUG_GENERIC,
+ "Autosuggestion Entity Summarizer in progress, request to clear cache ignored");
+ return;
+ }
+
+ super.clearCache();
+ this.resetCounters();
+ if (entityCounters != null) {
+ entityCounters.clear();
+ }
+
+ allWorkEnumerated = false;
+
+ }
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/aggregation/sync/HistoricalEntitySummarizer.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/aggregation/sync/HistoricalEntitySummarizer.java
new file mode 100644
index 0000000..9063e92
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/aggregation/sync/HistoricalEntitySummarizer.java
@@ -0,0 +1,384 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.aggregation.sync;
+
+import static java.util.concurrent.CompletableFuture.supplyAsync;
+
+import java.io.IOException;
+import java.sql.Timestamp;
+import java.text.SimpleDateFormat;
+import java.util.Collection;
+import java.util.EnumSet;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Supplier;
+
+import javax.json.Json;
+import javax.ws.rs.core.MediaType;
+
+import org.onap.aai.cl.api.Logger;
+import org.onap.aai.cl.eelf.LoggerFactory;
+import org.onap.aai.cl.mdc.MdcContext;
+import org.onap.aai.restclient.client.OperationResult;
+import org.onap.aai.sparky.config.oxm.SearchableEntityLookup;
+import org.onap.aai.sparky.config.oxm.SearchableOxmEntityDescriptor;
+import org.onap.aai.sparky.dal.rest.HttpMethod;
+import org.onap.aai.sparky.logging.AaiUiMsgs;
+import org.onap.aai.sparky.sync.AbstractEntitySynchronizer;
+import org.onap.aai.sparky.sync.IndexSynchronizer;
+import org.onap.aai.sparky.sync.config.ElasticSearchSchemaConfig;
+import org.onap.aai.sparky.sync.config.NetworkStatisticsConfig;
+import org.onap.aai.sparky.sync.enumeration.OperationState;
+import org.onap.aai.sparky.sync.enumeration.SynchronizerState;
+import org.onap.aai.sparky.util.NodeUtils;
+import org.slf4j.MDC;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+
+/**
+ * The Class HistoricalEntitySummarizer.
+ */
+public class HistoricalEntitySummarizer extends AbstractEntitySynchronizer
+ implements IndexSynchronizer {
+
+ private static final Logger LOG = LoggerFactory.getInstance().getLogger(HistoricalEntitySummarizer.class);
+ private static final String INSERTION_DATE_TIME_FORMAT = "yyyyMMdd'T'HHmmssZ";
+
+ private boolean allWorkEnumerated;
+ private ConcurrentHashMap<String, AtomicInteger> entityCounters;
+ private boolean syncInProgress;
+ private Map<String, String> contextMap;
+ private ElasticSearchSchemaConfig schemaConfig;
+ private SearchableEntityLookup searchableEntityLookup;
+
+ /**
+ * Instantiates a new historical entity summarizer.
+ *
+ * @param indexName the index name
+ * @throws Exception the exception
+ */
+ public HistoricalEntitySummarizer(ElasticSearchSchemaConfig schemaConfig, int internalSyncWorkers,
+ int aaiWorkers, int esWorkers, NetworkStatisticsConfig aaiStatConfig,
+ NetworkStatisticsConfig esStatConfig, SearchableEntityLookup searchableEntityLookup)
+ throws Exception {
+ super(LOG, "HES", internalSyncWorkers, aaiWorkers, esWorkers, schemaConfig.getIndexName(), aaiStatConfig, esStatConfig);
+
+ this.schemaConfig = schemaConfig;
+ this.allWorkEnumerated = false;
+ this.entityCounters = new ConcurrentHashMap<String, AtomicInteger>();
+ this.synchronizerName = "Historical Entity Summarizer";
+ this.enabledStatFlags = EnumSet.of(StatFlag.AAI_REST_STATS, StatFlag.ES_REST_STATS);
+ this.syncInProgress = false;
+ this.contextMap = MDC.getCopyOfContextMap();
+ this.syncDurationInMs = -1;
+ this.searchableEntityLookup = searchableEntityLookup;
+ }
+
+ /**
+ * Collect all the work.
+ *
+ * @return the operation state
+ */
+ private OperationState collectAllTheWork() {
+
+ Map<String, SearchableOxmEntityDescriptor> descriptorMap =
+ searchableEntityLookup.getSearchableEntityDescriptors();
+
+ if (descriptorMap.isEmpty()) {
+ LOG.error(AaiUiMsgs.OXM_FAILED_RETRIEVAL, "historical entities");
+
+ return OperationState.ERROR;
+ }
+
+ Collection<String> entityTypes = descriptorMap.keySet();
+
+ AtomicInteger asyncWoH = new AtomicInteger(0);
+
+ asyncWoH.set(entityTypes.size());
+
+ try {
+ for (String entityType : entityTypes) {
+
+ supplyAsync(new Supplier<Void>() {
+
+ @Override
+ public Void get() {
+ MDC.setContextMap(contextMap);
+ try {
+ OperationResult typeLinksResult =
+ aaiAdapter.getSelfLinksByEntityType(entityType);
+ updateActiveInventoryCounters(HttpMethod.GET, entityType, typeLinksResult);
+ processEntityTypeSelfLinks(entityType, typeLinksResult);
+ } catch (Exception exc) {
+ LOG.error(AaiUiMsgs.ERROR_GETTING_DATA_FROM_AAI, exc.getMessage());
+
+ }
+
+ return null;
+ }
+
+ }, aaiExecutor).whenComplete((result, error) -> {
+
+ asyncWoH.decrementAndGet();
+
+ if (error != null) {
+ LOG.error(AaiUiMsgs.HISTORICAL_COLLECT_ERROR, error.getMessage());
+ }
+
+ });
+
+ }
+
+
+ while (asyncWoH.get() > 0) {
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug(AaiUiMsgs.DEBUG_GENERIC, indexName + " summarizer waiting for all the links to be processed.");
+ }
+
+ Thread.sleep(250);
+ }
+
+ esWorkOnHand.set(entityCounters.size());
+
+ // start doing the real work
+ allWorkEnumerated = true;
+
+ insertEntityTypeCounters();
+
+ if (LOG.isDebugEnabled()) {
+
+ StringBuilder sb = new StringBuilder(128);
+
+ sb.append("\n\nHistorical Entity Counters:");
+
+ for (Entry<String, AtomicInteger> entry : entityCounters.entrySet()) {
+ sb.append("\n").append(entry.getKey()).append(" = ").append(entry.getValue().get());
+ }
+
+ LOG.debug(AaiUiMsgs.DEBUG_GENERIC, sb.toString());
+
+ }
+
+ } catch (Exception exc) {
+ LOG.error(AaiUiMsgs.HISTORICAL_COLLECT_ERROR, exc.getMessage());
+
+
+ esWorkOnHand.set(0);
+ allWorkEnumerated = true;
+
+ return OperationState.ERROR;
+ }
+
+ return OperationState.OK;
+
+ }
+
+ /* (non-Javadoc)
+ * @see org.openecomp.sparky.synchronizer.IndexSynchronizer#doSync()
+ */
+ @Override
+ public OperationState doSync() {
+ this.syncDurationInMs = -1;
+ String txnID = NodeUtils.getRandomTxnId();
+ MdcContext.initialize(txnID, "HistoricalEntitySynchronizer", "", "Sync", "");
+
+ if (syncInProgress) {
+ LOG.info(AaiUiMsgs.HISTORICAL_SYNC_PENDING);
+ return OperationState.PENDING;
+ }
+
+ clearCache();
+
+ syncInProgress = true;
+ this.syncStartedTimeStampInMs = System.currentTimeMillis();
+ allWorkEnumerated = false;
+
+ return collectAllTheWork();
+ }
+
+ /**
+ * Process entity type self links.
+ *
+ * @param entityType the entity type
+ * @param operationResult the operation result
+ */
+ private void processEntityTypeSelfLinks(String entityType, OperationResult operationResult) {
+
+ JsonNode rootNode = null;
+
+ final String jsonResult = operationResult.getResult();
+
+ if (jsonResult != null && jsonResult.length() > 0 && operationResult.wasSuccessful()) {
+
+ try {
+ rootNode = mapper.readTree(jsonResult);
+ } catch (IOException exc) {
+ LOG.error(AaiUiMsgs.JSON_PROCESSING_ERROR, exc.getMessage());
+ return;
+ }
+
+ JsonNode resultData = rootNode.get("result-data");
+ ArrayNode resultDataArrayNode = null;
+
+ if (resultData != null && resultData.isArray()) {
+ resultDataArrayNode = (ArrayNode) resultData;
+ entityCounters.put(entityType, new AtomicInteger(resultDataArrayNode.size()));
+ }
+ }
+
+ }
+
+ /**
+ * Insert entity type counters.
+ */
+ private void insertEntityTypeCounters() {
+
+ if (esWorkOnHand.get() <= 0) {
+ return;
+ }
+
+ SimpleDateFormat dateFormat = new SimpleDateFormat(INSERTION_DATE_TIME_FORMAT);
+ Timestamp timestamp = new Timestamp(System.currentTimeMillis());
+ String currentFormattedTimeStamp = dateFormat.format(timestamp);
+
+ Set<Entry<String, AtomicInteger>> entityCounterEntries = entityCounters.entrySet();
+
+ for (Entry<String, AtomicInteger> entityCounterEntry : entityCounterEntries) {
+
+ supplyAsync(new Supplier<Void>() {
+
+ @Override
+ public Void get() {
+ MDC.setContextMap(contextMap);
+ String jsonString = Json.createObjectBuilder().add(
+ "count", entityCounterEntry.getValue().get())
+ .add("entityType", entityCounterEntry.getKey())
+ .add("timestamp", currentFormattedTimeStamp).build().toString();
+
+ String link = null;
+ try {
+ link = elasticSearchAdapter.buildElasticSearchPostUrl(indexName);
+ OperationResult or = elasticSearchAdapter.doPost(link, jsonString, MediaType.APPLICATION_JSON_TYPE);
+ updateElasticSearchCounters(HttpMethod.POST, entityCounterEntry.getKey(), or);
+ } catch (Exception exc) {
+ LOG.error(AaiUiMsgs.ES_STORE_FAILURE, exc.getMessage() );
+ }
+
+ return null;
+ }
+
+ }, esExecutor).whenComplete((result, error) -> {
+
+ esWorkOnHand.decrementAndGet();
+
+ });
+
+ }
+
+ while (esWorkOnHand.get() > 0) {
+
+ try {
+ Thread.sleep(500);
+ } catch (InterruptedException exc) {
+ LOG.error(AaiUiMsgs.INTERRUPTED, "historical Entities", exc.getMessage());
+ }
+ }
+
+ }
+
+ @Override
+ public SynchronizerState getState() {
+
+ if (!isSyncDone()) {
+ return SynchronizerState.PERFORMING_SYNCHRONIZATION;
+ }
+
+ return SynchronizerState.IDLE;
+
+ }
+
+ /* (non-Javadoc)
+ * @see org.openecomp.sparky.synchronizer.IndexSynchronizer#getStatReport(boolean)
+ */
+ @Override
+ public String getStatReport(boolean showFinalReport) {
+ syncDurationInMs = System.currentTimeMillis() - syncStartedTimeStampInMs;
+ return this.getStatReport(syncDurationInMs, showFinalReport);
+ }
+
+ /* (non-Javadoc)
+ * @see org.openecomp.sparky.synchronizer.IndexSynchronizer#shutdown()
+ */
+ @Override
+ public void shutdown() {
+ this.shutdownExecutors();
+ }
+
+ @Override
+ protected boolean isSyncDone() {
+
+ int totalWorkOnHand = aaiWorkOnHand.get() + esWorkOnHand.get();
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug(AaiUiMsgs.DEBUG_GENERIC,indexName + ", isSyncDone(), totalWorkOnHand = " + totalWorkOnHand
+ + " all work enumerated = " + allWorkEnumerated);
+ }
+
+ if (totalWorkOnHand > 0 || !allWorkEnumerated) {
+ return false;
+ }
+
+ this.syncInProgress = false;
+
+ return true;
+ }
+
+ /* (non-Javadoc)
+ * @see org.openecomp.sparky.synchronizer.AbstractEntitySynchronizer#clearCache()
+ */
+ @Override
+ public void clearCache() {
+
+ if (syncInProgress) {
+ LOG.debug(AaiUiMsgs.DEBUG_GENERIC, "Historical Entity Summarizer in progress, request to clear cache ignored");
+ return;
+ }
+
+ super.clearCache();
+ this.resetCounters();
+ if (entityCounters != null) {
+ entityCounters.clear();
+ }
+
+ allWorkEnumerated = false;
+
+ }
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/aggregation/sync/HistoricalEntitySyncController.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/aggregation/sync/HistoricalEntitySyncController.java
new file mode 100644
index 0000000..eb42489
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/aggregation/sync/HistoricalEntitySyncController.java
@@ -0,0 +1,94 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.aggregation.sync;
+
+import org.onap.aai.sparky.config.oxm.SearchableEntityLookup;
+import org.onap.aai.sparky.dal.ActiveInventoryAdapter;
+import org.onap.aai.sparky.dal.ElasticSearchAdapter;
+import org.onap.aai.sparky.sync.ElasticSearchSchemaFactory;
+import org.onap.aai.sparky.sync.IndexIntegrityValidator;
+import org.onap.aai.sparky.sync.SyncControllerImpl;
+import org.onap.aai.sparky.sync.SyncControllerRegistrar;
+import org.onap.aai.sparky.sync.SyncControllerRegistry;
+import org.onap.aai.sparky.sync.config.ElasticSearchEndpointConfig;
+import org.onap.aai.sparky.sync.config.ElasticSearchSchemaConfig;
+import org.onap.aai.sparky.sync.config.NetworkStatisticsConfig;
+import org.onap.aai.sparky.sync.config.SyncControllerConfig;
+
+public class HistoricalEntitySyncController extends SyncControllerImpl
+ implements SyncControllerRegistrar {
+
+ private SyncControllerRegistry syncControllerRegistry;
+
+ public HistoricalEntitySyncController(SyncControllerConfig syncControllerConfig,
+ ActiveInventoryAdapter aaiAdapter, ElasticSearchAdapter esAdapter,
+ ElasticSearchSchemaConfig schemaConfig, ElasticSearchEndpointConfig endpointConfig,
+ int syncFrequencyInMinutes, NetworkStatisticsConfig aaiStatConfig,
+ NetworkStatisticsConfig esStatConfig, SearchableEntityLookup searchableEntityLookup,
+ ElasticSearchSchemaFactory elasticSearchSchemaFactory) throws Exception {
+ super(syncControllerConfig);
+
+ // final String controllerName = "Historical Entity Count Synchronizer";
+
+ long taskFrequencyInMs = syncFrequencyInMinutes * 60 * 1000;
+
+ setDelayInMs(taskFrequencyInMs);
+ setSyncFrequencyInMs(taskFrequencyInMs);
+
+ IndexIntegrityValidator entityCounterHistoryValidator = new IndexIntegrityValidator(esAdapter,
+ schemaConfig, endpointConfig, elasticSearchSchemaFactory.getIndexSchema(schemaConfig));
+
+ registerIndexValidator(entityCounterHistoryValidator);
+
+ HistoricalEntitySummarizer historicalSummarizer = new HistoricalEntitySummarizer(schemaConfig,
+ syncControllerConfig.getNumInternalSyncWorkers(),
+ syncControllerConfig.getNumSyncActiveInventoryWorkers(),
+ syncControllerConfig.getNumSyncElasticWorkers(),aaiStatConfig, esStatConfig,searchableEntityLookup);
+
+ historicalSummarizer.setAaiAdapter(aaiAdapter);
+ historicalSummarizer.setElasticSearchAdapter(esAdapter);
+
+ registerEntitySynchronizer(historicalSummarizer);
+
+ }
+
+ public SyncControllerRegistry getSyncControllerRegistry() {
+ return syncControllerRegistry;
+ }
+
+ public void setSyncControllerRegistry(SyncControllerRegistry syncControllerRegistry) {
+ this.syncControllerRegistry = syncControllerRegistry;
+ }
+
+ @Override
+ public void registerController() {
+ if ( syncControllerRegistry != null ) {
+ if ( syncControllerConfig.isEnabled()) {
+ syncControllerRegistry.registerSyncController(this);
+ }
+ }
+
+ }
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/analytics/AbstractStatistics.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/analytics/AbstractStatistics.java
new file mode 100644
index 0000000..8197398
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/analytics/AbstractStatistics.java
@@ -0,0 +1,178 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.analytics;
+
+import java.util.HashMap;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * The Class AbstractStatistics.
+ */
+public class AbstractStatistics implements ComponentStatistics {
+
+ private HashMap<String, AtomicInteger> namedCounters;
+ private HashMap<String, HistogramSampler> namedHistograms;
+
+ /**
+ * Instantiates a new abstract statistics.
+ */
+ protected AbstractStatistics() {
+ namedCounters = new HashMap<String, AtomicInteger>();
+ namedHistograms = new HashMap<String, HistogramSampler>();
+ }
+
+ /* (non-Javadoc)
+ * @see org.openecomp.sparky.analytics.ComponentStatistics#addCounter(java.lang.String)
+ */
+ /*
+ * sync-lock the creation of counters during initialization, but run time should not use lock
+ * synchronization, only thread safe types
+ *
+ */
+ @Override
+ public synchronized void addCounter(String key) {
+
+ AtomicInteger counter = namedCounters.get(key);
+
+ if (counter == null) {
+ counter = new AtomicInteger(0);
+ namedCounters.put(key, counter);
+ }
+
+ }
+
+ /* (non-Javadoc)
+ * @see org.openecomp.sparky.analytics.ComponentStatistics#pegCounter(java.lang.String)
+ */
+ @Override
+ public void pegCounter(String key) {
+
+ AtomicInteger counter = namedCounters.get(key);
+
+ if (counter != null) {
+ counter.incrementAndGet();
+ }
+
+ }
+
+ /* (non-Javadoc)
+ * @see org.openecomp.sparky.analytics.ComponentStatistics#incrementCounter(java.lang.String, int)
+ */
+ @Override
+ public void incrementCounter(String key, int value) {
+
+ AtomicInteger counter = namedCounters.get(key);
+
+ if (counter != null) {
+ counter.addAndGet(value);
+ }
+
+ }
+
+
+ /* (non-Javadoc)
+ * @see org.openecomp.sparky.analytics.ComponentStatistics#addHistogram(java.lang.String, java.lang.String, long, int, int)
+ */
+ @Override
+ public synchronized void addHistogram(String key, String histName, long maxYValue, int numBins,
+ int numDecimalPoints) {
+ HistogramSampler histSampler = namedHistograms.get(key);
+
+ if (histSampler == null) {
+ histSampler = new HistogramSampler(histName, maxYValue, numBins, numDecimalPoints);
+ namedHistograms.put(key, histSampler);
+ }
+
+ }
+
+ /* (non-Javadoc)
+ * @see org.openecomp.sparky.analytics.ComponentStatistics#updateHistogram(java.lang.String, long)
+ */
+ @Override
+ public void updateHistogram(String key, long value) {
+ HistogramSampler histSampler = namedHistograms.get(key);
+
+ if (histSampler != null) {
+ histSampler.track(value);
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.openecomp.sparky.analytics.ComponentStatistics#reset()
+ */
+ @Override
+ public void reset() {
+
+ for (HistogramSampler h : namedHistograms.values()) {
+ h.clear();
+ }
+
+ for (AtomicInteger c : namedCounters.values()) {
+ c.set(0);
+ }
+
+ }
+
+ /**
+ * Gets the counter value.
+ *
+ * @param key the key
+ * @return the counter value
+ */
+ protected int getCounterValue(String key) {
+
+ AtomicInteger counter = namedCounters.get(key);
+
+ if (counter == null) {
+ return -1;
+ }
+
+ return counter.get();
+
+ }
+
+ /**
+ * Gets the histogram stats.
+ *
+ * @param key the key
+ * @param verboseEnabled the verbose enabled
+ * @param indentPadding the indent padding
+ * @return the histogram stats
+ */
+ protected String getHistogramStats(String key, boolean verboseEnabled, String indentPadding) {
+
+ HistogramSampler histSampler = namedHistograms.get(key);
+
+ if (histSampler == null) {
+ return null;
+ }
+
+ return histSampler.getStats(verboseEnabled, indentPadding);
+
+ }
+
+
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/analytics/AveragingRingBuffer.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/analytics/AveragingRingBuffer.java
new file mode 100644
index 0000000..fd5f277
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/analytics/AveragingRingBuffer.java
@@ -0,0 +1,121 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.analytics;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * TODO: Fill in description.
+ *
+ * @author davea
+ */
+public class AveragingRingBuffer {
+
+ private int numElements;
+
+ private long[] data;
+
+ private AtomicInteger index;
+
+ private long average;
+
+ private boolean initialAverageCalculated;
+
+ /**
+ * Instantiates a new averaging ring buffer.
+ *
+ * @param size the size
+ */
+ public AveragingRingBuffer(int size) {
+
+ if (size == 0) {
+ throw new IllegalArgumentException("Size must be greater than zero");
+ }
+
+ this.initialAverageCalculated = false;
+ this.numElements = size;
+ this.data = new long[this.numElements];
+ this.index = new AtomicInteger(-1);
+ }
+
+ /**
+ * Calculate average.
+ *
+ * @param maxArrayIndex the max array index
+ */
+ private void calculateAverage(int maxArrayIndex) {
+
+ long sum = 0;
+
+ for (int i = 0; i <= maxArrayIndex; i++) {
+ sum += data[i];
+ }
+
+ average = (sum / (maxArrayIndex + 1));
+
+ }
+
+ public long getAvg() {
+
+ if (!initialAverageCalculated) {
+ /*
+ * until the index rolls once we will calculate the average from the data that has been added
+ * to the array, not including the zero elements
+ */
+ if (index.get() < 0) {
+ calculateAverage(0);
+ } else {
+ calculateAverage(index.get());
+ }
+
+ }
+
+ return average;
+ }
+
+ /**
+ * Adds the sample.
+ *
+ * @param value the value
+ */
+ public synchronized void addSample(long value) {
+
+ index.incrementAndGet();
+
+ data[index.get()] = value;
+
+ if (index.get() == (numElements - 1)) {
+ calculateAverage(numElements - 1);
+
+ if (!initialAverageCalculated) {
+ initialAverageCalculated = true;
+ }
+
+ index.set(-1);
+ }
+
+ }
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/analytics/ComponentStatistics.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/analytics/ComponentStatistics.java
new file mode 100644
index 0000000..ef78f9e
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/analytics/ComponentStatistics.java
@@ -0,0 +1,80 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.analytics;
+
+
+/**
+ * The Interface ComponentStatistics.
+ */
+public interface ComponentStatistics {
+
+ /**
+ * Adds the counter.
+ *
+ * @param key the key
+ */
+ public void addCounter(String key);
+
+ /**
+ * Peg counter.
+ *
+ * @param key the key
+ */
+ public void pegCounter(String key);
+
+ /**
+ * Increment counter.
+ *
+ * @param key the key
+ * @param value the value
+ */
+ public void incrementCounter(String key, int value);
+
+ /**
+ * Adds the histogram.
+ *
+ * @param key the key
+ * @param name the name
+ * @param maxYValue the max Y value
+ * @param numBins the num bins
+ * @param numDecimalPoints the num decimal points
+ */
+ public void addHistogram(String key, String name, long maxYValue, int numBins,
+ int numDecimalPoints);
+
+ /**
+ * Update histogram.
+ *
+ * @param key the key
+ * @param value the value
+ */
+ public void updateHistogram(String key, long value);
+
+ /**
+ * Reset.
+ */
+ public void reset();
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/analytics/HistogramSampler.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/analytics/HistogramSampler.java
new file mode 100644
index 0000000..55fb9d8
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/analytics/HistogramSampler.java
@@ -0,0 +1,286 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.analytics;
+
+/**
+ * A class that models a histogram for reporting and tracking long values with variable steps, bins,
+ * and floating point accuracy.
+ *
+ * @author davea.
+ */
+public final class HistogramSampler {
+
+ private String label;
+
+ private long binMaxValue;
+
+ private int numBins;
+
+ private double stepSize;
+
+ private long sampleValueTotal;
+
+ private long minValue = -1;
+
+ private long maxValue = 0;
+
+ private long numSamples = 0;
+
+ private long decimalPointAccuracy = 0;
+
+ private static String FORMAT_FLOAT_TEMPLATE = "%%.%df";
+
+ private String floatFormatStr;
+
+ private long[] histogramBins;
+
+ /**
+ * Instantiates a new histogram sampler.
+ *
+ * @param label the label
+ * @param maxValue the max value
+ * @param numBins the num bins
+ * @param decimalPointAccuracy the decimal point accuracy
+ */
+ public HistogramSampler(String label, long maxValue, int numBins, int decimalPointAccuracy) {
+ this.label = label;
+ this.binMaxValue = maxValue;
+ this.numBins = numBins;
+ this.stepSize = ((double) binMaxValue / (double) numBins);
+ this.decimalPointAccuracy = decimalPointAccuracy;
+ this.floatFormatStr = String.format(FORMAT_FLOAT_TEMPLATE, this.decimalPointAccuracy);
+
+ /*
+ * [numBins + 1] => last bin is catch-all for outliers
+ */
+
+ initializeHistogramBins(numBins + 1);
+
+ }
+
+ /**
+ * Initialize histogram bins.
+ *
+ * @param numBins the num bins
+ */
+ private void initializeHistogramBins(int numBins) {
+
+ histogramBins = new long[numBins];
+ int counter = 0;
+ while (counter < numBins) {
+ histogramBins[counter] = 0;
+ counter++;
+ }
+
+ }
+
+ /*
+ * Is it really necessary to synchronize the collection, or should we simply switch the underlying
+ * data type to an AtomicLong
+ */
+
+ /**
+ * Track.
+ *
+ * @param value the value
+ */
+ public synchronized void track(long value) {
+
+ if (value < 0) {
+ return;
+ }
+
+ sampleValueTotal += value;
+ numSamples++;
+
+ if (minValue == -1) {
+ minValue = value;
+ }
+
+ if (value < minValue) {
+ minValue = value;
+ }
+
+ if (value > maxValue) {
+ maxValue = value;
+ }
+
+ /*
+ * One step bin determination
+ */
+
+ if (value < (numBins * stepSize)) {
+
+ int index = (int) (value / stepSize);
+ histogramBins[index]++;
+
+ } else {
+ // peg the metric in the outlier bin
+ histogramBins[numBins - 1]++;
+ }
+
+ }
+
+ /**
+ * Clear.
+ */
+ public void clear() {
+
+ int counter = 0;
+ while (counter < numBins) {
+ histogramBins[counter] = 0;
+ counter++;
+ }
+
+ minValue = -1;
+ maxValue = 0;
+ numSamples = 0;
+ sampleValueTotal = 0;
+
+ }
+
+ /**
+ * Re initialize bins.
+ *
+ * @param label the label
+ * @param numBins the num bins
+ * @param maxValue the max value
+ * @param decimalPointAccuracy the decimal point accuracy
+ */
+ public void reInitializeBins(String label, int numBins, long maxValue, int decimalPointAccuracy) {
+ this.label = label;
+ this.decimalPointAccuracy = decimalPointAccuracy;
+ this.floatFormatStr = String.format(FORMAT_FLOAT_TEMPLATE, this.decimalPointAccuracy);
+ this.numBins = numBins;
+ this.minValue = -1;
+ this.maxValue = 0;
+ initializeHistogramBins(numBins);
+ this.stepSize = (maxValue / numBins);
+ clear();
+ }
+
+ public long getNumberOfSamples() {
+ return numSamples;
+ }
+
+ public long getTotalValueSum() {
+ return sampleValueTotal;
+ }
+
+ /**
+ * Gets the stats.
+ *
+ * @param formatted the formatted
+ * @param indentPadding the indent padding
+ * @return the stats
+ */
+ public String getStats(boolean formatted, String indentPadding) {
+
+ StringBuilder sb = new StringBuilder(128);
+
+
+ if (!formatted) {
+ // generate CSV in the following format
+
+ /*
+ * label,minValue,maxValue,avgValue,numSamples,stepSize,numSteps,stepCounters
+ */
+ sb.append(indentPadding);
+ sb.append(label).append(",");
+ sb.append(minValue).append(",");
+ sb.append(maxValue).append(",");
+ if (numSamples == 0) {
+ sb.append(0).append(",");
+ } else {
+ sb.append((sampleValueTotal / numSamples)).append(",");
+ }
+ sb.append(numSamples).append(",");
+ sb.append(numBins).append(",");
+ sb.append(String.format(floatFormatStr, stepSize));
+
+ int counter = 0;
+ while (counter < numBins) {
+
+ if (counter != (numBins)) {
+ sb.append(",");
+ }
+
+ sb.append(histogramBins[counter]);
+
+ counter++;
+
+ }
+
+ return sb.toString();
+
+ }
+
+ sb.append("\n");
+ sb.append(indentPadding).append("Label = ").append(label).append("\n");
+ sb.append(indentPadding).append("Min = ").append(minValue).append("\n");
+ sb.append(indentPadding).append("Max = ").append(maxValue).append("\n");
+ sb.append(indentPadding).append("numSamples = ").append(numSamples).append("\n");
+
+ if (numSamples == 0) {
+ sb.append(indentPadding).append("Avg = ").append(0).append("\n");
+ } else {
+ sb.append(indentPadding).append("Avg = ").append((sampleValueTotal / numSamples))
+ .append("\n");
+ }
+
+ sb.append(indentPadding).append("StepSize = ").append(String.format(floatFormatStr, stepSize))
+ .append("\n");
+
+ sb.append(indentPadding).append("Sample Histogram:").append("\n");
+
+ int counter = 0;
+ while (counter < numBins) {
+
+ if (counter == (numBins - 1)) {
+ // outlier bin
+ double leftBound = (stepSize * counter);
+ sb.append(indentPadding).append("\t")
+ .append(" x >= " + String.format(floatFormatStr, leftBound) + " : "
+ + histogramBins[counter])
+ .append("\n");
+
+ } else {
+ double leftBound = (stepSize * counter);
+ double rightBound = ((stepSize) * (counter + 1));
+ sb.append(indentPadding).append("\t")
+ .append((String.format(floatFormatStr, leftBound) + " < x < "
+ + String.format(floatFormatStr, rightBound) + " : " + histogramBins[counter]))
+ .append("\n");
+ }
+
+ counter++;
+
+ }
+
+ return sb.toString();
+
+ }
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/analytics/HistoricalCounter.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/analytics/HistoricalCounter.java
new file mode 100644
index 0000000..1a534e3
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/analytics/HistoricalCounter.java
@@ -0,0 +1,177 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.analytics;
+
+/**
+ * A simple class to model a historical counter. A set of values will be tracked and basic
+ * statistics will be calculated in real time (n, min, max, avg).
+ *
+ * @author davea
+ */
+public class HistoricalCounter {
+
+ private double min;
+
+ private double max;
+
+ private double totalOfSamples;
+
+ private long numSamples;
+
+ private double value;
+
+ private boolean maintainSingleValue;
+
+ /**
+ * Instantiates a new historical counter.
+ *
+ * @param trackSingleValue the track single value
+ */
+ public HistoricalCounter(boolean trackSingleValue) {
+ min = -1;
+ max = 0;
+ totalOfSamples = 0;
+ value = 0.0;
+ numSamples = 0;
+ this.maintainSingleValue = trackSingleValue;
+ }
+
+ public boolean isSingleValue() {
+ return maintainSingleValue;
+ }
+
+ /**
+ * Update.
+ *
+ * @param value the value
+ */
+ public synchronized void update(double value) {
+
+ if (value < 0) {
+ return;
+ }
+
+ if (maintainSingleValue) {
+
+ this.value = value;
+
+ } else {
+
+ if (min == -1) {
+ min = value;
+ }
+
+ if (value < min) {
+ min = value;
+ }
+
+ if (value > max) {
+ max = value;
+ }
+
+ totalOfSamples += value;
+ numSamples++;
+ }
+ }
+
+ public double getValue() {
+ return value;
+ }
+
+ public double getMin() {
+ return min;
+ }
+
+ public double getMax() {
+ return max;
+ }
+
+ public long getNumSamples() {
+ return numSamples;
+ }
+
+ public double getAvg() {
+ if (numSamples == 0) {
+ return 0;
+ }
+
+ return (totalOfSamples / numSamples);
+ }
+ public void setMin(double min) {
+ this.min = min;
+ }
+
+ public void setMax(double max) {
+ this.max = max;
+ }
+
+ public double getTotalOfSamples() {
+ return totalOfSamples;
+ }
+
+ public void setTotalOfSamples(double totalOfSamples) {
+ this.totalOfSamples = totalOfSamples;
+ }
+
+ public void setNumSamples(long numSamples) {
+ this.numSamples = numSamples;
+ }
+
+ public void setMaintainSingleValue(boolean maintainSingleValue) {
+ this.maintainSingleValue = maintainSingleValue;
+ }
+
+
+ /**
+ * Reset.
+ */
+ public synchronized void reset() {
+ min = -1;
+ max = 0;
+ numSamples = 0;
+ totalOfSamples = 0;
+ value = 0.0;
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder(32);
+
+ if (maintainSingleValue) {
+ sb.append("[ Val=").append(value).append(" ]");
+ } else {
+ sb.append("[ NumSamples=").append(numSamples).append(",");
+ sb.append(" Min=").append(min).append(",");
+ sb.append(" Max=").append(max).append(",");
+ sb.append(" Avg=").append(getAvg()).append(" ]");
+ }
+
+ return sb.toString();
+ }
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/autosuggestion/sync/AutoSuggestionSyncController.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/autosuggestion/sync/AutoSuggestionSyncController.java
new file mode 100644
index 0000000..05ce775
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/autosuggestion/sync/AutoSuggestionSyncController.java
@@ -0,0 +1,105 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.autosuggestion.sync;
+
+import org.onap.aai.sparky.config.oxm.OxmEntityLookup;
+import org.onap.aai.sparky.config.oxm.SuggestionEntityLookup;
+import org.onap.aai.sparky.dal.ActiveInventoryAdapter;
+import org.onap.aai.sparky.dal.ElasticSearchAdapter;
+import org.onap.aai.sparky.search.filters.config.FiltersConfig;
+import org.onap.aai.sparky.sync.ElasticSearchIndexCleaner;
+import org.onap.aai.sparky.sync.ElasticSearchSchemaFactory;
+import org.onap.aai.sparky.sync.IndexCleaner;
+import org.onap.aai.sparky.sync.IndexIntegrityValidator;
+import org.onap.aai.sparky.sync.SyncControllerImpl;
+import org.onap.aai.sparky.sync.SyncControllerRegistrar;
+import org.onap.aai.sparky.sync.SyncControllerRegistry;
+import org.onap.aai.sparky.sync.config.ElasticSearchEndpointConfig;
+import org.onap.aai.sparky.sync.config.ElasticSearchSchemaConfig;
+import org.onap.aai.sparky.sync.config.NetworkStatisticsConfig;
+import org.onap.aai.sparky.sync.config.SyncControllerConfig;
+import org.springframework.beans.factory.annotation.Autowired;
+
+public class AutoSuggestionSyncController extends SyncControllerImpl implements SyncControllerRegistrar {
+
+ private SyncControllerRegistry syncControllerRegistry;
+
+ public AutoSuggestionSyncController(SyncControllerConfig syncControllerConfig,
+ ActiveInventoryAdapter aaiAdapter, ElasticSearchAdapter esAdapter,
+ ElasticSearchSchemaConfig schemaConfig, ElasticSearchEndpointConfig endpointConfig,
+ NetworkStatisticsConfig aaiStatConfig, NetworkStatisticsConfig esStatConfig,
+ OxmEntityLookup oxmEntityLookup, SuggestionEntityLookup suggestionEntityLookup,
+ FiltersConfig filtersConfig,
+ ElasticSearchSchemaFactory elasticSearchSchemaFactory) throws Exception {
+ super(syncControllerConfig);
+
+ // final String controllerName = "Auto Suggestion Synchronizer";
+
+ IndexIntegrityValidator autoSuggestionIndexValidator = new IndexIntegrityValidator(esAdapter,
+ schemaConfig, endpointConfig, elasticSearchSchemaFactory.getIndexSchema(schemaConfig));
+
+ registerIndexValidator(autoSuggestionIndexValidator);
+
+ AutosuggestionSynchronizer suggestionSynchronizer = new AutosuggestionSynchronizer(schemaConfig,
+ syncControllerConfig.getNumInternalSyncWorkers(),
+ syncControllerConfig.getNumSyncActiveInventoryWorkers(),
+ syncControllerConfig.getNumSyncElasticWorkers(), aaiStatConfig, esStatConfig,
+ oxmEntityLookup, suggestionEntityLookup, filtersConfig);
+
+ suggestionSynchronizer.setAaiAdapter(aaiAdapter);
+ suggestionSynchronizer.setElasticSearchAdapter(esAdapter);
+
+ registerEntitySynchronizer(suggestionSynchronizer);
+
+ IndexCleaner autosuggestIndexCleaner =
+ new ElasticSearchIndexCleaner(esAdapter, endpointConfig, schemaConfig);
+
+ registerIndexCleaner(autosuggestIndexCleaner);
+
+ }
+
+ public SyncControllerRegistry getSyncControllerRegistry() {
+ return syncControllerRegistry;
+ }
+
+
+
+ public void setSyncControllerRegistry(SyncControllerRegistry syncControllerRegistry) {
+ this.syncControllerRegistry = syncControllerRegistry;
+ }
+
+
+
+ @Override
+ public void registerController() {
+
+ if ( syncControllerRegistry != null ) {
+ if ( syncControllerConfig.isEnabled()) {
+ syncControllerRegistry.registerSyncController(this);
+ }
+ }
+
+ }
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/autosuggestion/sync/AutosuggestionSynchronizer.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/autosuggestion/sync/AutosuggestionSynchronizer.java
new file mode 100644
index 0000000..baffa54
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/autosuggestion/sync/AutosuggestionSynchronizer.java
@@ -0,0 +1,776 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.autosuggestion.sync;
+
+import static java.util.concurrent.CompletableFuture.supplyAsync;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Deque;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentLinkedDeque;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Supplier;
+
+import org.onap.aai.cl.api.Logger;
+import org.onap.aai.cl.eelf.LoggerFactory;
+import org.onap.aai.cl.mdc.MdcContext;
+import org.onap.aai.restclient.client.OperationResult;
+import org.onap.aai.sparky.config.oxm.OxmEntityDescriptor;
+import org.onap.aai.sparky.config.oxm.OxmEntityLookup;
+import org.onap.aai.sparky.config.oxm.SuggestionEntityDescriptor;
+import org.onap.aai.sparky.config.oxm.SuggestionEntityLookup;
+import org.onap.aai.sparky.dal.ActiveInventoryAdapter;
+import org.onap.aai.sparky.dal.NetworkTransaction;
+import org.onap.aai.sparky.dal.rest.HttpMethod;
+import org.onap.aai.sparky.logging.AaiUiMsgs;
+import org.onap.aai.sparky.search.filters.config.FiltersConfig;
+import org.onap.aai.sparky.sync.AbstractEntitySynchronizer;
+import org.onap.aai.sparky.sync.IndexSynchronizer;
+import org.onap.aai.sparky.sync.SynchronizerConstants;
+import org.onap.aai.sparky.sync.config.ElasticSearchSchemaConfig;
+import org.onap.aai.sparky.sync.config.NetworkStatisticsConfig;
+import org.onap.aai.sparky.sync.entity.SelfLinkDescriptor;
+import org.onap.aai.sparky.sync.entity.SuggestionSearchEntity;
+import org.onap.aai.sparky.sync.enumeration.OperationState;
+import org.onap.aai.sparky.sync.enumeration.SynchronizerState;
+import org.onap.aai.sparky.sync.task.PerformActiveInventoryRetrieval;
+import org.onap.aai.sparky.sync.task.PerformElasticSearchPut;
+import org.onap.aai.sparky.sync.task.PerformElasticSearchRetrieval;
+import org.onap.aai.sparky.util.NodeUtils;
+import org.onap.aai.sparky.util.SuggestionsPermutation;
+import org.slf4j.MDC;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+
+/**
+ * The Class AutosuggestionSynchronizer.
+ */
+public class AutosuggestionSynchronizer extends AbstractEntitySynchronizer
+ implements IndexSynchronizer {
+
+ private class RetrySuggestionEntitySyncContainer {
+ NetworkTransaction txn;
+ SuggestionSearchEntity ssec;
+
+ /**
+ * Instantiates a new RetrySuggestionEntitySyncContainer.
+ *
+ * @param txn the txn
+ * @param icer the icer
+ */
+ public RetrySuggestionEntitySyncContainer(NetworkTransaction txn, SuggestionSearchEntity icer) {
+ this.txn = txn;
+ this.ssec = icer;
+ }
+
+ public NetworkTransaction getNetworkTransaction() {
+ return txn;
+ }
+
+ public SuggestionSearchEntity getSuggestionSearchEntity() {
+ return ssec;
+ }
+ }
+
+ private static final Logger LOG =
+ LoggerFactory.getInstance().getLogger(AutosuggestionSynchronizer.class);
+ private static final String INSERTION_DATE_TIME_FORMAT = "yyyyMMdd'T'HHmmssZ";
+
+ private boolean allWorkEnumerated;
+ private Deque<SelfLinkDescriptor> selflinks;
+ private ConcurrentHashMap<String, AtomicInteger> entityCounters;
+ private boolean syncInProgress;
+ private Map<String, String> contextMap;
+ protected ExecutorService esPutExecutor;
+ private Deque<RetrySuggestionEntitySyncContainer> retryQueue;
+ private Map<String, Integer> retryLimitTracker;
+ private OxmEntityLookup oxmEntityLookup;
+ private SuggestionEntityLookup suggestionEntityLookup;
+ private FiltersConfig filtersConfig;
+
+ /**
+ * Instantiates a new historical entity summarizer.
+ *
+ * @param indexName the index name
+ * @throws Exception the exception
+ */
+ public AutosuggestionSynchronizer(ElasticSearchSchemaConfig schemaConfig, int internalSyncWorkers,
+ int aaiWorkers, int esWorkers, NetworkStatisticsConfig aaiStatConfig,
+ NetworkStatisticsConfig esStatConfig, OxmEntityLookup oxmEntityLookup,
+ SuggestionEntityLookup suggestionEntityLookup, FiltersConfig filtersConfig) throws Exception {
+
+ super(LOG, "ASES-" + schemaConfig.getIndexName().toUpperCase(), internalSyncWorkers, aaiWorkers,
+ esWorkers, schemaConfig.getIndexName(), aaiStatConfig, esStatConfig);
+
+ this.oxmEntityLookup = oxmEntityLookup;
+ this.suggestionEntityLookup = suggestionEntityLookup;
+ this.allWorkEnumerated = false;
+ this.selflinks = new ConcurrentLinkedDeque<SelfLinkDescriptor>();
+ this.entityCounters = new ConcurrentHashMap<String, AtomicInteger>();
+ this.synchronizerName = "Autosuggestion Entity Synchronizer";
+ this.enabledStatFlags = EnumSet.of(StatFlag.AAI_REST_STATS, StatFlag.ES_REST_STATS);
+ this.syncInProgress = false;
+ this.contextMap = MDC.getCopyOfContextMap();
+ this.esPutExecutor = NodeUtils.createNamedExecutor("SUES-ES-PUT", 5, LOG);
+ this.retryQueue = new ConcurrentLinkedDeque<RetrySuggestionEntitySyncContainer>();
+ this.retryLimitTracker = new ConcurrentHashMap<String, Integer>();
+ this.syncDurationInMs = -1;
+ this.filtersConfig = filtersConfig;
+ }
+
+ /**
+ * Collect all the work.
+ *
+ * @return the operation state
+ */
+ private OperationState collectAllTheWork() {
+ final Map<String, String> contextMap = MDC.getCopyOfContextMap();
+ Map<String, SuggestionEntityDescriptor> descriptorMap =
+ suggestionEntityLookup.getSuggestionSearchEntityDescriptors();
+
+ if (descriptorMap.isEmpty()) {
+ LOG.error(AaiUiMsgs.ERROR_LOADING_OXM_SUGGESTIBLE_ENTITIES);
+ LOG.info(AaiUiMsgs.ERROR_LOADING_OXM_SUGGESTIBLE_ENTITIES);
+ return OperationState.ERROR;
+ }
+
+ Collection<String> syncTypes = descriptorMap.keySet();
+
+ try {
+
+ /*
+ * launch a parallel async thread to process the documents for each entity-type (to max the of
+ * the configured executor anyway)
+ */
+
+ aaiWorkOnHand.set(syncTypes.size());
+
+ for (String key : syncTypes) {
+
+ supplyAsync(new Supplier<Void>() {
+
+ @Override
+ public Void get() {
+ MDC.setContextMap(contextMap);
+ OperationResult typeLinksResult = null;
+ try {
+ typeLinksResult = aaiAdapter.getSelfLinksByEntityType(key);
+ aaiWorkOnHand.decrementAndGet();
+ processEntityTypeSelfLinks(typeLinksResult);
+ } catch (Exception exc) {
+ LOG.error(AaiUiMsgs.ERROR_GENERIC,
+ "An error occurred while processing entity self-links. Error: "
+ + exc.getMessage());
+ }
+
+ return null;
+ }
+
+ }, aaiExecutor).whenComplete((result, error) -> {
+
+ if (error != null) {
+ LOG.error(AaiUiMsgs.ERROR_GENERIC,
+ "An error occurred getting data from AAI. Error = " + error.getMessage());
+ }
+ });
+
+ }
+
+ while (aaiWorkOnHand.get() != 0) {
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug(AaiUiMsgs.WAIT_FOR_ALL_SELFLINKS_TO_BE_COLLECTED);
+ }
+
+ Thread.sleep(1000);
+ }
+
+ aaiWorkOnHand.set(selflinks.size());
+ allWorkEnumerated = true;
+ syncEntityTypes();
+
+ while (!isSyncDone()) {
+ performRetrySync();
+ Thread.sleep(1000);
+ }
+
+ /*
+ * Make sure we don't hang on to retries that failed which could cause issues during future
+ * syncs
+ */
+ retryLimitTracker.clear();
+
+ } catch (Exception exc) {
+ LOG.error(AaiUiMsgs.ERROR_GENERIC,
+ "An error occurred while performing the sync. Error: " + exc.getMessage());
+ }
+
+ return OperationState.OK;
+
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.openecomp.sparky.synchronizer.IndexSynchronizer#doSync()
+ */
+ @Override
+ public OperationState doSync() {
+ this.syncDurationInMs = -1;
+ syncStartedTimeStampInMs = System.currentTimeMillis();
+ String txnID = NodeUtils.getRandomTxnId();
+ MdcContext.initialize(txnID, "AutosuggestionSynchronizer", "", "Sync", "");
+
+ return collectAllTheWork();
+ }
+
+ /**
+ * Process entity type self links.
+ *
+ * @param operationResult the operation result
+ */
+ private void processEntityTypeSelfLinks(OperationResult operationResult) {
+
+ JsonNode rootNode = null;
+
+ if ( operationResult == null ) {
+ return;
+ }
+
+ final String jsonResult = operationResult.getResult();
+
+ if (jsonResult != null && jsonResult.length() > 0 && operationResult.wasSuccessful()) {
+
+ try {
+ rootNode = mapper.readTree(jsonResult);
+ } catch (IOException exc) {
+ String message = "Could not deserialize JSON (representing operation result) as node tree. "
+ + "Operation result = " + jsonResult + ". " + exc.getLocalizedMessage();
+ LOG.error(AaiUiMsgs.JSON_PROCESSING_ERROR, message);
+ }
+
+ JsonNode resultData = rootNode.get("result-data");
+ ArrayNode resultDataArrayNode = null;
+
+ if (resultData.isArray()) {
+ resultDataArrayNode = (ArrayNode) resultData;
+
+ Iterator<JsonNode> elementIterator = resultDataArrayNode.elements();
+ JsonNode element = null;
+
+ while (elementIterator.hasNext()) {
+ element = elementIterator.next();
+
+ final String resourceType = NodeUtils.getNodeFieldAsText(element, "resource-type");
+ final String resourceLink = NodeUtils.getNodeFieldAsText(element, "resource-link");
+
+ OxmEntityDescriptor descriptor = null;
+
+ if (resourceType != null && resourceLink != null) {
+
+ descriptor = oxmEntityLookup.getEntityDescriptors().get(resourceType);
+
+ if (descriptor == null) {
+ LOG.error(AaiUiMsgs.MISSING_ENTITY_DESCRIPTOR, resourceType);
+ // go to next element in iterator
+ continue;
+ }
+ selflinks.add(new SelfLinkDescriptor(resourceLink,
+ SynchronizerConstants.NODES_ONLY_MODIFIER, resourceType));
+
+
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Sync entity types.
+ */
+ private void syncEntityTypes() {
+
+ while (selflinks.peek() != null) {
+
+ SelfLinkDescriptor linkDescriptor = selflinks.poll();
+ aaiWorkOnHand.decrementAndGet();
+
+ OxmEntityDescriptor descriptor = null;
+
+ if (linkDescriptor.getSelfLink() != null && linkDescriptor.getEntityType() != null) {
+
+ descriptor = oxmEntityLookup.getEntityDescriptors().get(linkDescriptor.getEntityType());
+
+ if (descriptor == null) {
+ LOG.error(AaiUiMsgs.MISSING_ENTITY_DESCRIPTOR, linkDescriptor.getEntityType());
+ // go to next element in iterator
+ continue;
+ }
+
+ NetworkTransaction txn = new NetworkTransaction();
+ txn.setDescriptor(descriptor);
+ txn.setLink(linkDescriptor.getSelfLink());
+ txn.setOperationType(HttpMethod.GET);
+ txn.setEntityType(linkDescriptor.getEntityType());
+
+ aaiWorkOnHand.incrementAndGet();
+
+ supplyAsync(new PerformActiveInventoryRetrieval(txn, aaiAdapter), aaiExecutor)
+ .whenComplete((result, error) -> {
+
+ aaiWorkOnHand.decrementAndGet();
+
+ if (error != null) {
+ LOG.error(AaiUiMsgs.AAI_RETRIEVAL_FAILED_GENERIC, error.getLocalizedMessage());
+ } else {
+ if (result == null) {
+ LOG.error(AaiUiMsgs.AAI_RETRIEVAL_FAILED_FOR_SELF_LINK,
+ linkDescriptor.getSelfLink());
+ } else {
+ updateActiveInventoryCounters(result);
+ fetchDocumentForUpsert(result);
+ }
+ }
+ });
+ }
+
+ }
+
+ }
+
+ /*
+ * Return a set of valid suggestion attributes for the provided entityName that are present in the
+ * JSON
+ *
+ * @param node JSON node in which the attributes should be found
+ *
+ * @param entityName Name of the entity
+ *
+ * @return List of all valid suggestion attributes(key's)
+ */
+ public List<String> getSuggestableAttrNamesFromReponse(JsonNode node, String entityName) {
+ List<String> suggestableAttr = new ArrayList<String>();
+
+ HashMap<String, String> desc =
+ suggestionEntityLookup.getSuggestionSearchEntityOxmModel().get(entityName);
+
+ if (desc != null) {
+
+ String attr = desc.get("suggestibleAttributes");
+
+ if (attr != null) {
+ suggestableAttr = Arrays.asList(attr.split(","));
+ List<String> suggestableValue = new ArrayList<String>();
+ for (String attribute : suggestableAttr) {
+ if (node.get(attribute) != null && node.get(attribute).asText().length() > 0) {
+ suggestableValue.add(attribute);
+ }
+ }
+ return suggestableValue;
+ }
+ }
+
+ return new ArrayList<String>();
+ }
+
+ /**
+ * Fetch all the documents for upsert. Based on the number of permutations that are available the
+ * number of documents will be different
+ *
+ * @param txn the txn
+ */
+ private void fetchDocumentForUpsert(NetworkTransaction txn) {
+ if (!txn.getOperationResult().wasSuccessful()) {
+ String message = "Self link failure. Result - " + txn.getOperationResult().getResult();
+ LOG.error(AaiUiMsgs.ERROR_GENERIC, message);
+ return;
+ }
+ try {
+ final String jsonResult = txn.getOperationResult().getResult();
+
+ if (jsonResult != null && jsonResult.length() > 0) {
+
+ // Step 1: Calculate the number of possible permutations of attributes
+ String entityName = txn.getDescriptor().getEntityName();
+ JsonNode entityNode = mapper.readTree(jsonResult);
+
+ List<String> availableSuggestableAttrName =
+ getSuggestableAttrNamesFromReponse(entityNode, entityName);
+
+ ArrayList<ArrayList<String>> uniqueLists =
+ SuggestionsPermutation.getNonEmptyUniqueLists(availableSuggestableAttrName);
+ // Now we have a list of all possible permutations for the status that are
+ // defined for this entity type. Try inserting a document for every combination.
+ for (ArrayList<String> uniqueList : uniqueLists) {
+
+ SuggestionSearchEntity sse = new SuggestionSearchEntity(filtersConfig, suggestionEntityLookup);
+ sse.setSuggestableAttr(uniqueList);
+ sse.setFilterBasedPayloadFromResponse(entityNode, entityName, uniqueList);
+ sse.setLink(ActiveInventoryAdapter.extractResourcePath(txn.getLink()));
+ populateSuggestionSearchEntityDocument(sse, jsonResult, txn);
+ // The unique id for the document will be created at derive fields
+ sse.deriveFields();
+ // Insert the document only if it has valid statuses
+ if (sse.isSuggestableDoc()) {
+ String link = null;
+ try {
+ link = elasticSearchAdapter.buildElasticSearchGetDocUrl(getIndexName(), sse.getId());
+ } catch (Exception exc) {
+ LOG.error(AaiUiMsgs.ES_FAILED_TO_CONSTRUCT_QUERY, exc.getLocalizedMessage());
+ }
+
+ if (link != null) {
+ NetworkTransaction n2 = new NetworkTransaction();
+ n2.setLink(link);
+ n2.setEntityType(txn.getEntityType());
+ n2.setDescriptor(txn.getDescriptor());
+ n2.setOperationType(HttpMethod.GET);
+
+ esWorkOnHand.incrementAndGet();
+
+ supplyAsync(new PerformElasticSearchRetrieval(n2, elasticSearchAdapter), esExecutor)
+ .whenComplete((result, error) -> {
+
+ esWorkOnHand.decrementAndGet();
+
+ if (error != null) {
+ LOG.error(AaiUiMsgs.ES_RETRIEVAL_FAILED, error.getLocalizedMessage());
+ } else {
+ updateElasticSearchCounters(result);
+ performDocumentUpsert(result, sse);
+ }
+ });
+ }
+ }
+ }
+ }
+ } catch (JsonProcessingException exc) {
+ LOG.error(AaiUiMsgs.ERROR_GENERIC, "There was a json processing error while processing the result from elasticsearch. Error: " + exc.getMessage());
+ } catch (IOException exc) {
+ LOG.error(AaiUiMsgs.ERROR_GENERIC, "There was a io processing error while processing the result from elasticsearch. Error: " + exc.getMessage());
+ }
+ }
+
+ protected void populateSuggestionSearchEntityDocument(SuggestionSearchEntity sse, String result,
+ NetworkTransaction txn) throws JsonProcessingException, IOException {
+
+ OxmEntityDescriptor resultDescriptor = txn.getDescriptor();
+
+ sse.setEntityType(resultDescriptor.getEntityName());
+
+ JsonNode entityNode = mapper.readTree(result);
+
+ List<String> primaryKeyValues = new ArrayList<String>();
+ String pkeyValue = null;
+
+ for (String keyName : resultDescriptor.getPrimaryKeyAttributeNames()) {
+ pkeyValue = NodeUtils.getNodeFieldAsText(entityNode, keyName);
+ if (pkeyValue != null) {
+ primaryKeyValues.add(pkeyValue);
+ } else {
+ String message = "populateSuggestionSearchEntityDocument(),"
+ + " pKeyValue is null for entityType = " + resultDescriptor.getEntityName();
+ LOG.warn(AaiUiMsgs.WARN_GENERIC, message);
+ }
+ }
+
+ final String primaryCompositeKeyValue = NodeUtils.concatArray(primaryKeyValues, "/");
+ sse.setEntityPrimaryKeyValue(primaryCompositeKeyValue);
+ sse.generateSuggestionInputPermutations();
+ }
+
+ protected void performDocumentUpsert(NetworkTransaction esGetTxn, SuggestionSearchEntity sse) {
+ /**
+ * <p>
+ * <ul>
+ * As part of the response processing we need to do the following:
+ * <li>1. Extract the version (if present), it will be the ETAG when we use the
+ * Search-Abstraction-Service
+ * <li>2. Spawn next task which is to do the PUT operation into elastic with or with the version
+ * tag
+ * <li>a) if version is null or RC=404, then standard put, no _update with version tag
+ * <li>b) if version != null, do PUT with _update?version= versionNumber in the URI to elastic
+ * </ul>
+ * </p>
+ */
+ String link = null;
+ try {
+ link = elasticSearchAdapter.buildElasticSearchGetDocUrl(getIndexName(), sse.getId());
+ } catch (Exception exc) {
+ LOG.error(AaiUiMsgs.ES_LINK_UPSERT, exc.getLocalizedMessage());
+ return;
+ }
+
+ boolean wasEntryDiscovered = false;
+ if (esGetTxn.getOperationResult().getResultCode() == 404) {
+ LOG.info(AaiUiMsgs.ES_SIMPLE_PUT, sse.getEntityPrimaryKeyValue());
+ } else if (esGetTxn.getOperationResult().getResultCode() == 200) {
+ wasEntryDiscovered = true;
+ } else {
+ /*
+ * Not being a 200 does not mean a failure. eg 201 is returned for created. and 500 for es not
+ * found TODO -> Should we return.
+ */
+ LOG.error(AaiUiMsgs.ES_OPERATION_RETURN_CODE,
+ String.valueOf(esGetTxn.getOperationResult().getResultCode()));
+ return;
+ }
+ // Insert a new document only if the paylod is different.
+ // This is determined by hashing the payload and using it as a id for the document
+ //
+ if (!wasEntryDiscovered) {
+ try {
+ String jsonPayload = null;
+
+ jsonPayload = sse.getAsJson();
+ if (link != null && jsonPayload != null) {
+
+ NetworkTransaction updateElasticTxn = new NetworkTransaction();
+ updateElasticTxn.setLink(link);
+ updateElasticTxn.setEntityType(esGetTxn.getEntityType());
+ updateElasticTxn.setDescriptor(esGetTxn.getDescriptor());
+ updateElasticTxn.setOperationType(HttpMethod.PUT);
+
+ esWorkOnHand.incrementAndGet();
+ supplyAsync(new PerformElasticSearchPut(jsonPayload, updateElasticTxn, elasticSearchAdapter),
+ esPutExecutor).whenComplete((result, error) -> {
+
+ esWorkOnHand.decrementAndGet();
+
+ if (error != null) {
+ String message = "Suggestion search entity sync UPDATE PUT error - "
+ + error.getLocalizedMessage();
+ LOG.error(AaiUiMsgs.ES_SUGGESTION_SEARCH_ENTITY_SYNC_ERROR, message);
+ } else {
+ updateElasticSearchCounters(result);
+ processStoreDocumentResult(result, esGetTxn, sse);
+ }
+ });
+ }
+ } catch (Exception exc) {
+ String message =
+ "Exception caught during suggestion search entity sync PUT operation. Message - "
+ + exc.getLocalizedMessage();
+ LOG.error(AaiUiMsgs.ES_SUGGESTION_SEARCH_ENTITY_SYNC_ERROR, message);
+ }
+ }
+ }
+
+ private void processStoreDocumentResult(NetworkTransaction esPutResult,
+ NetworkTransaction esGetResult, SuggestionSearchEntity sse) {
+
+ OperationResult or = esPutResult.getOperationResult();
+
+ if (!or.wasSuccessful()) {
+ if (or.getResultCode() == VERSION_CONFLICT_EXCEPTION_CODE) {
+
+ if (shouldAllowRetry(sse.getId())) {
+ esWorkOnHand.incrementAndGet();
+
+ RetrySuggestionEntitySyncContainer rssec =
+ new RetrySuggestionEntitySyncContainer(esGetResult, sse);
+ retryQueue.push(rssec);
+
+ String message = "Store document failed during suggestion search entity synchronization"
+ + " due to version conflict. Entity will be re-synced.";
+ LOG.warn(AaiUiMsgs.ES_SUGGESTION_SEARCH_ENTITY_SYNC_ERROR, message);
+ }
+ } else {
+ String message =
+ "Store document failed during suggestion search entity synchronization with result code "
+ + or.getResultCode() + " and result message " + or.getResult();
+ LOG.error(AaiUiMsgs.ES_SUGGESTION_SEARCH_ENTITY_SYNC_ERROR, message);
+ }
+ }
+ }
+
+ /**
+ * Perform retry sync.
+ */
+ private void performRetrySync() {
+ while (retryQueue.peek() != null) {
+
+ RetrySuggestionEntitySyncContainer susc = retryQueue.poll();
+ if (susc != null) {
+
+ SuggestionSearchEntity sus = susc.getSuggestionSearchEntity();
+ NetworkTransaction txn = susc.getNetworkTransaction();
+
+ String link = null;
+ try {
+ /*
+ * In this retry flow the se object has already derived its fields
+ */
+ link = elasticSearchAdapter.buildElasticSearchGetDocUrl(getIndexName(), sus.getId());
+ } catch (Exception exc) {
+ LOG.error(AaiUiMsgs.ES_FAILED_TO_CONSTRUCT_URI, exc.getLocalizedMessage());
+ }
+
+ if (link != null) {
+ NetworkTransaction retryTransaction = new NetworkTransaction();
+ retryTransaction.setLink(link);
+ retryTransaction.setEntityType(txn.getEntityType());
+ retryTransaction.setDescriptor(txn.getDescriptor());
+ retryTransaction.setOperationType(HttpMethod.GET);
+
+ /*
+ * IMPORTANT - DO NOT incrementAndGet the esWorkOnHand as this is a retry flow! We already
+ * called incrementAndGet when queuing the failed PUT!
+ */
+
+ supplyAsync(new PerformElasticSearchRetrieval(retryTransaction, elasticSearchAdapter),
+ esExecutor).whenComplete((result, error) -> {
+
+ esWorkOnHand.decrementAndGet();
+
+ if (error != null) {
+ LOG.error(AaiUiMsgs.ES_RETRIEVAL_FAILED_RESYNC, error.getLocalizedMessage());
+ } else {
+ updateElasticSearchCounters(result);
+ performDocumentUpsert(result, sus);
+ }
+ });
+ }
+
+ }
+ }
+ }
+
+ /**
+ * Should allow retry.
+ *
+ * @param id the id
+ * @return true, if successful
+ */
+ private boolean shouldAllowRetry(String id) {
+ boolean isRetryAllowed = true;
+ if (retryLimitTracker.get(id) != null) {
+ Integer currentCount = retryLimitTracker.get(id);
+ if (currentCount.intValue() >= RETRY_COUNT_PER_ENTITY_LIMIT.intValue()) {
+ isRetryAllowed = false;
+ String message = "Searchable entity re-sync limit reached for " + id
+ + ", re-sync will no longer be attempted for this entity";
+ LOG.error(AaiUiMsgs.ES_SEARCHABLE_ENTITY_SYNC_ERROR, message);
+ } else {
+ Integer newCount = new Integer(currentCount.intValue() + 1);
+ retryLimitTracker.put(id, newCount);
+ }
+ } else {
+ Integer firstRetryCount = new Integer(1);
+ retryLimitTracker.put(id, firstRetryCount);
+ }
+
+ return isRetryAllowed;
+ }
+
+
+
+ @Override
+ public SynchronizerState getState() {
+
+ if (!isSyncDone()) {
+ return SynchronizerState.PERFORMING_SYNCHRONIZATION;
+ }
+
+ return SynchronizerState.IDLE;
+
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.openecomp.sparky.synchronizer.IndexSynchronizer#getStatReport(boolean)
+ */
+ @Override
+ public String getStatReport(boolean showFinalReport) {
+ syncDurationInMs = System.currentTimeMillis() - syncStartedTimeStampInMs;
+ return getStatReport(syncDurationInMs, showFinalReport);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.openecomp.sparky.synchronizer.IndexSynchronizer#shutdown()
+ */
+ @Override
+ public void shutdown() {
+ this.shutdownExecutors();
+ }
+
+ @Override
+ protected boolean isSyncDone() {
+
+ int totalWorkOnHand = aaiWorkOnHand.get() + esWorkOnHand.get();
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug(AaiUiMsgs.DEBUG_GENERIC, indexName + ", isSyncDone(), totalWorkOnHand = "
+ + totalWorkOnHand + " all work enumerated = " + allWorkEnumerated);
+ }
+
+ if (totalWorkOnHand > 0 || !allWorkEnumerated) {
+ return false;
+ }
+
+ this.syncInProgress = false;
+
+ return true;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.openecomp.sparky.synchronizer.AbstractEntitySynchronizer#clearCache()
+ */
+ @Override
+ public void clearCache() {
+
+ if (syncInProgress) {
+ LOG.debug(AaiUiMsgs.DEBUG_GENERIC,
+ "Autosuggestion Entity Summarizer in progress, request to clear cache ignored");
+ return;
+ }
+
+ super.clearCache();
+ this.resetCounters();
+ if (entityCounters != null) {
+ entityCounters.clear();
+ }
+
+ allWorkEnumerated = false;
+
+ }
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/autosuggestion/sync/VnfAliasSuggestionSynchronizer.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/autosuggestion/sync/VnfAliasSuggestionSynchronizer.java
new file mode 100644
index 0000000..7226c27
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/autosuggestion/sync/VnfAliasSuggestionSynchronizer.java
@@ -0,0 +1,197 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.autosuggestion.sync;
+
+import static java.util.concurrent.CompletableFuture.supplyAsync;
+
+import java.util.Map;
+import java.util.concurrent.ExecutorService;
+
+import org.onap.aai.cl.api.Logger;
+import org.onap.aai.cl.eelf.LoggerFactory;
+import org.onap.aai.cl.mdc.MdcContext;
+import org.onap.aai.restclient.client.OperationResult;
+import org.onap.aai.sparky.dal.NetworkTransaction;
+import org.onap.aai.sparky.dal.rest.HttpMethod;
+import org.onap.aai.sparky.logging.AaiUiMsgs;
+import org.onap.aai.sparky.search.filters.config.FiltersConfig;
+import org.onap.aai.sparky.sync.AbstractEntitySynchronizer;
+import org.onap.aai.sparky.sync.IndexSynchronizer;
+import org.onap.aai.sparky.sync.config.ElasticSearchSchemaConfig;
+import org.onap.aai.sparky.sync.config.NetworkStatisticsConfig;
+import org.onap.aai.sparky.sync.entity.AggregationSuggestionEntity;
+import org.onap.aai.sparky.sync.enumeration.OperationState;
+import org.onap.aai.sparky.sync.enumeration.SynchronizerState;
+import org.onap.aai.sparky.sync.task.PerformElasticSearchPut;
+import org.onap.aai.sparky.util.NodeUtils;
+import org.slf4j.MDC;
+
+
+public class VnfAliasSuggestionSynchronizer extends AbstractEntitySynchronizer
+ implements IndexSynchronizer {
+
+ private static final Logger LOG =
+ LoggerFactory.getInstance().getLogger(VnfAliasSuggestionSynchronizer.class);
+
+ private boolean isSyncInProgress;
+ private boolean shouldPerformRetry;
+ private Map<String, String> contextMap;
+ protected ExecutorService esPutExecutor;
+ private FiltersConfig filtersConfig;
+
+ public VnfAliasSuggestionSynchronizer(ElasticSearchSchemaConfig schemaConfig,
+ int internalSyncWorkers, int aaiWorkers, int esWorkers, NetworkStatisticsConfig aaiStatConfig,
+ NetworkStatisticsConfig esStatConfig, FiltersConfig filtersConfig) throws Exception {
+ super(LOG, "VASS-" + schemaConfig.getIndexName().toUpperCase(), internalSyncWorkers, aaiWorkers,
+ esWorkers, schemaConfig.getIndexName(), aaiStatConfig, esStatConfig);
+
+ this.isSyncInProgress = false;
+ this.shouldPerformRetry = false;
+ this.synchronizerName = "VNFs Alias Suggestion Synchronizer";
+ this.contextMap = MDC.getCopyOfContextMap();
+ this.esPutExecutor = NodeUtils.createNamedExecutor("ASS-ES-PUT", 2, LOG);
+ this.filtersConfig = filtersConfig;
+ }
+
+ @Override
+ protected boolean isSyncDone() {
+ int totalWorkOnHand = esWorkOnHand.get();
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug(AaiUiMsgs.DEBUG_GENERIC,
+ indexName + ", isSyncDone(), totalWorkOnHand = " + totalWorkOnHand);
+ }
+
+ if (totalWorkOnHand > 0 || !isSyncInProgress) {
+ return false;
+ }
+
+ return true;
+ }
+
+ @Override
+ public OperationState doSync() {
+ isSyncInProgress = true;
+ this.syncDurationInMs = -1;
+ syncStartedTimeStampInMs = System.currentTimeMillis();
+
+ syncEntity();
+
+ while (!isSyncDone()) {
+ try {
+ if (shouldPerformRetry) {
+ syncEntity();
+ }
+ Thread.sleep(1000);
+ } catch (Exception exc) {
+ // We don't care about this exception
+ }
+ }
+
+ return OperationState.OK;
+ }
+
+ private void syncEntity() {
+ String txnId = NodeUtils.getRandomTxnId();
+ MdcContext.initialize(txnId, synchronizerName, "", "Sync", "");
+
+ AggregationSuggestionEntity syncEntity = new AggregationSuggestionEntity(filtersConfig);
+ syncEntity.deriveFields();
+ syncEntity.initializeFilters();
+
+ String link = null;
+ try {
+ link = elasticSearchAdapter.buildElasticSearchGetDocUrl(getIndexName(), syncEntity.getId());
+ } catch (Exception exc) {
+ LOG.error(AaiUiMsgs.ES_LINK_UPSERT, exc.getLocalizedMessage());
+ }
+
+ try {
+ String jsonPayload = null;
+ jsonPayload = syncEntity.getAsJson();
+ if (link != null && jsonPayload != null) {
+
+ NetworkTransaction elasticPutTxn = new NetworkTransaction();
+ elasticPutTxn.setLink(link);
+ elasticPutTxn.setOperationType(HttpMethod.PUT);
+
+ esWorkOnHand.incrementAndGet();
+ final Map<String, String> contextMap = MDC.getCopyOfContextMap();
+ supplyAsync(new PerformElasticSearchPut(jsonPayload, elasticPutTxn,
+ elasticSearchAdapter, contextMap), esPutExecutor).whenComplete((result, error) -> {
+
+ esWorkOnHand.decrementAndGet();
+
+ if (error != null) {
+ String message = "Aggregation suggestion entity sync UPDATE PUT error - "
+ + error.getLocalizedMessage();
+ LOG.error(AaiUiMsgs.ES_AGGREGATION_SUGGESTION_ENTITY_SYNC_ERROR, message);
+ } else {
+ updateElasticSearchCounters(result);
+ wasEsOperationSuccessful(result);
+ }
+ });
+ }
+ } catch (Exception exc) {
+ String message =
+ "Exception caught during aggregation suggestion entity sync PUT operation. Message - "
+ + exc.getLocalizedMessage();
+ LOG.error(AaiUiMsgs.ES_AGGREGATION_SUGGESTION_ENTITY_SYNC_ERROR, message);
+ }
+ }
+
+ private void wasEsOperationSuccessful(NetworkTransaction result) {
+ if (result != null) {
+ OperationResult opResult = result.getOperationResult();
+
+ if (!opResult.wasSuccessful()) {
+ shouldPerformRetry = true;
+ } else {
+ isSyncInProgress = false;
+ shouldPerformRetry = false;
+ }
+ }
+ }
+
+ @Override
+ public SynchronizerState getState() {
+ if (!isSyncDone()) {
+ return SynchronizerState.PERFORMING_SYNCHRONIZATION;
+ }
+
+ return SynchronizerState.IDLE;
+ }
+
+ @Override
+ public String getStatReport(boolean shouldDisplayFinalReport) {
+ syncDurationInMs = System.currentTimeMillis() - syncStartedTimeStampInMs;
+ return getStatReport(syncDurationInMs, shouldDisplayFinalReport);
+ }
+
+ @Override
+ public void shutdown() {
+ this.shutdownExecutors();
+ }
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/autosuggestion/sync/VnfAliasSyncController.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/autosuggestion/sync/VnfAliasSyncController.java
new file mode 100644
index 0000000..f6504ad
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/autosuggestion/sync/VnfAliasSyncController.java
@@ -0,0 +1,99 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.autosuggestion.sync;
+
+import org.onap.aai.sparky.dal.ActiveInventoryAdapter;
+import org.onap.aai.sparky.dal.ElasticSearchAdapter;
+import org.onap.aai.sparky.search.filters.config.FiltersConfig;
+import org.onap.aai.sparky.sync.ElasticSearchIndexCleaner;
+import org.onap.aai.sparky.sync.ElasticSearchSchemaFactory;
+import org.onap.aai.sparky.sync.IndexCleaner;
+import org.onap.aai.sparky.sync.IndexIntegrityValidator;
+import org.onap.aai.sparky.sync.SyncControllerImpl;
+import org.onap.aai.sparky.sync.SyncControllerRegistrar;
+import org.onap.aai.sparky.sync.SyncControllerRegistry;
+import org.onap.aai.sparky.sync.config.ElasticSearchEndpointConfig;
+import org.onap.aai.sparky.sync.config.ElasticSearchSchemaConfig;
+import org.onap.aai.sparky.sync.config.NetworkStatisticsConfig;
+import org.onap.aai.sparky.sync.config.SyncControllerConfig;
+
+public class VnfAliasSyncController extends SyncControllerImpl implements SyncControllerRegistrar {
+
+ private SyncControllerRegistry syncControllerRegistry;
+
+ public VnfAliasSyncController(SyncControllerConfig syncControllerConfig,
+ ActiveInventoryAdapter aaiAdapter, ElasticSearchAdapter esAdapter,
+ ElasticSearchSchemaConfig schemaConfig, ElasticSearchEndpointConfig endpointConfig,
+ NetworkStatisticsConfig aaiStatConfig, NetworkStatisticsConfig esStatConfig,
+ FiltersConfig filtersConfig,
+ ElasticSearchSchemaFactory elasticSearchSchemaFactory) throws Exception {
+ super(syncControllerConfig);
+
+ // final String controllerName = "VNFs Alias Suggestion Synchronizer";
+
+ IndexIntegrityValidator indexValidator = new IndexIntegrityValidator(esAdapter, schemaConfig,
+ endpointConfig, elasticSearchSchemaFactory.getIndexSchema(schemaConfig));
+
+ registerIndexValidator(indexValidator);
+
+ VnfAliasSuggestionSynchronizer synchronizer = new VnfAliasSuggestionSynchronizer(schemaConfig,
+ syncControllerConfig.getNumInternalSyncWorkers(),
+ syncControllerConfig.getNumSyncActiveInventoryWorkers(),
+ syncControllerConfig.getNumSyncElasticWorkers(), aaiStatConfig, esStatConfig, filtersConfig);
+
+ synchronizer.setAaiAdapter(aaiAdapter);
+ synchronizer.setElasticSearchAdapter(esAdapter);
+
+ registerEntitySynchronizer(synchronizer);
+
+
+ IndexCleaner indexCleaner =
+ new ElasticSearchIndexCleaner(esAdapter, endpointConfig, schemaConfig);
+
+ registerIndexCleaner(indexCleaner);
+
+ }
+
+ public SyncControllerRegistry getSyncControllerRegistry() {
+ return syncControllerRegistry;
+ }
+
+ public void setSyncControllerRegistry(SyncControllerRegistry syncControllerRegistry) {
+ this.syncControllerRegistry = syncControllerRegistry;
+ }
+
+ @Override
+ public void registerController() {
+
+ if ( syncControllerRegistry != null ) {
+ if ( syncControllerConfig.isEnabled()) {
+ syncControllerRegistry.registerSyncController(this);
+ }
+ }
+
+ }
+
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/common/search/CommonSearchSuggestion.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/common/search/CommonSearchSuggestion.java
new file mode 100644
index 0000000..624573f
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/common/search/CommonSearchSuggestion.java
@@ -0,0 +1,90 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.common.search;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.onap.aai.sparky.search.entity.SearchSuggestion;
+import org.onap.aai.sparky.search.filters.entity.UiFilterValueEntity;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonInclude.Include;
+
+@JsonInclude(Include.NON_NULL)
+public class CommonSearchSuggestion implements SearchSuggestion {
+ protected String hashId;
+ protected String route;
+ protected String text;
+ protected List<UiFilterValueEntity> filterValues = new ArrayList<>();
+
+ public CommonSearchSuggestion() {}
+
+ public CommonSearchSuggestion(String hashId, String route, String text, String perspective,
+ List<UiFilterValueEntity> filterValues) {
+ this.hashId = hashId;
+ this.route = route;
+ this.text = text;
+ this.filterValues = filterValues;
+ }
+
+ public List<UiFilterValueEntity> getFilterValues() {
+ return filterValues;
+ }
+
+ public String getHashId() {
+ return hashId;
+ }
+
+ public String getRoute() {
+ return route;
+ }
+
+ public String getText() {
+ return text;
+ }
+
+ public void setHashId(String hashId) {
+ this.hashId = hashId;
+ }
+
+ public void setRoute(String route) {
+ this.route = route;
+ }
+
+ public void setText(String text) {
+ this.text = text;
+ }
+
+ @Override
+ public String toString() {
+ return "CommonSearchSuggestion [" + (hashId != null ? "hashId=" + hashId + ", " : "")
+ + (route != null ? "route=" + route + ", " : "")
+ + (text != null ? "text=" + text + ", " : "")
+ + (filterValues != null ? "filterValues=" + filterValues : "") + "]";
+ }
+
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/config/SparkyResourceLoader.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/config/SparkyResourceLoader.java
new file mode 100644
index 0000000..286b445
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/config/SparkyResourceLoader.java
@@ -0,0 +1,125 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.config;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+
+import org.springframework.context.ResourceLoaderAware;
+import org.springframework.core.io.Resource;
+import org.springframework.core.io.ResourceLoader;
+
+public class SparkyResourceLoader implements ResourceLoaderAware {
+
+
+ private static final String FILE_URI = "file:";
+ private ResourceLoader resourceLoader;
+ private String configHomeEnvVar;
+
+ // private static Logger LOG = LoggerFactory.getInstance().getLogger(SparkyResourceLoader.class);
+
+ @Override
+ public void setResourceLoader(ResourceLoader resourceLoader) {
+ this.resourceLoader = resourceLoader;
+ }
+
+ public String getFullFileUri(String uriFilePath) {
+ return FILE_URI + System.getProperty(configHomeEnvVar) + uriFilePath;
+ }
+
+ public String getAbsolutePath(String uriFilePath) {
+ return System.getProperty(configHomeEnvVar) + uriFilePath;
+ }
+
+ protected Resource getResource(String uriFilePath, boolean isRelative) {
+
+ String fileUri = uriFilePath;
+
+ if (!uriFilePath.startsWith("file:")) {
+ fileUri = "file:" + uriFilePath;
+ }
+
+ if (isRelative) {
+ return resourceLoader.getResource(getFullFileUri(fileUri));
+ } else {
+ return resourceLoader.getResource(fileUri);
+ }
+
+ }
+
+ public File getResourceAsFile(String uriFilePath, boolean isRelativePath) throws IOException {
+
+ Resource resource = getResource(uriFilePath, isRelativePath);
+
+ if (resource.exists()) {
+ return resource.getFile();
+ }
+
+ return null;
+
+ }
+
+ public byte[] getResourceAsBytes(String uriFilePath, boolean isRelativePath) throws IOException {
+
+ Resource resource = getResource(uriFilePath, isRelativePath);
+
+ if (resource.exists()) {
+ return getResourceAsBytes(resource);
+ }
+
+ return null;
+ }
+
+ public byte[] getResourceAsBytes(Resource resource) throws IOException {
+
+ if ( resource != null && resource.exists()) {
+ return Files.readAllBytes(Paths.get(resource.getFile().getAbsolutePath()));
+ }
+
+ return null;
+ }
+
+ public String getResourceAsString(String uriFilePath, boolean isRelativePath) throws IOException {
+
+ Resource resource = getResource(uriFilePath, isRelativePath);
+
+ if (resource.exists()) {
+ return new String(getResourceAsBytes(resource));
+ }
+
+ return null;
+ }
+
+ public String getConfigHomeEnvVar() {
+ return configHomeEnvVar;
+ }
+
+ public void setConfigHomeEnvVar(String configHomeEnvVar) {
+ this.configHomeEnvVar = configHomeEnvVar;
+ }
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/config/oxm/CrossEntityReference.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/config/oxm/CrossEntityReference.java
new file mode 100644
index 0000000..d632c5a
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/config/oxm/CrossEntityReference.java
@@ -0,0 +1,78 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.config.oxm;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * The Class CrossEntityReference.
+ */
+public class CrossEntityReference {
+ private String targetEntityType;
+ private List<String> referenceAttributes;
+
+ /**
+ * Instantiates a new cross entity reference.
+ */
+ public CrossEntityReference() {
+ targetEntityType = null;
+ referenceAttributes = new ArrayList<String>();
+ }
+
+ public String getTargetEntityType() {
+ return targetEntityType;
+ }
+
+ public void setTargetEntityType(String targetEntityType) {
+ this.targetEntityType = targetEntityType;
+ }
+
+ public List<String> getReferenceAttributes() {
+ return referenceAttributes;
+ }
+
+ public void setReferenceAttributes(List<String> referenceAttributes) {
+ this.referenceAttributes = referenceAttributes;
+ }
+
+ /**
+ * Adds the reference attribute.
+ *
+ * @param additionalAttribute the additional attribute
+ */
+ public void addReferenceAttribute(String additionalAttribute) {
+ referenceAttributes.add(additionalAttribute);
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ return "CrossEntityReference [targetEntityType=" + targetEntityType + ", referenceAttributes="
+ + referenceAttributes + "]";
+ }
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/config/oxm/CrossEntityReferenceDescriptor.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/config/oxm/CrossEntityReferenceDescriptor.java
new file mode 100644
index 0000000..c44b1f4
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/config/oxm/CrossEntityReferenceDescriptor.java
@@ -0,0 +1,67 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.config.oxm;
+
+public class CrossEntityReferenceDescriptor extends OxmEntityDescriptor {
+ protected CrossEntityReference crossEntityReference;
+
+ public CrossEntityReference getCrossEntityReference() {
+ return crossEntityReference;
+ }
+
+ public void setCrossEntityReference(CrossEntityReference crossEntityReference) {
+ this.crossEntityReference = crossEntityReference;
+ }
+
+ /**
+ * Checks for cross entity references.
+ *
+ * @return true, if successful
+ */
+ public boolean hasCrossEntityReferences() {
+ if (this.crossEntityReference == null) {
+ return false;
+ }
+ if (!this.crossEntityReference.getReferenceAttributes().isEmpty()) {
+ return true;
+ }
+ return false;
+ }
+
+
+ @Override
+ public String toString() {
+ return "CrossEntityReferenceDescriptor ["
+ + (crossEntityReference != null ? "crossEntityReference=" + crossEntityReference + ", "
+ : "")
+ + (entityName != null ? "entityName=" + entityName + ", " : "")
+ + (primaryKeyAttributeNames != null ? "primaryKeyAttributeNames=" + primaryKeyAttributeNames
+ : "")
+ + "]";
+ }
+
+
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/config/oxm/CrossEntityReferenceLookup.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/config/oxm/CrossEntityReferenceLookup.java
new file mode 100644
index 0000000..603b93d
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/config/oxm/CrossEntityReferenceLookup.java
@@ -0,0 +1,136 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.config.oxm;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.eclipse.persistence.dynamic.DynamicType;
+import org.eclipse.persistence.internal.oxm.mappings.Descriptor;
+import org.eclipse.persistence.jaxb.dynamic.DynamicJAXBContext;
+
+public class CrossEntityReferenceLookup implements OxmModelProcessor {
+
+ private Map<String, HashMap<String, String>> crossReferenceEntityOxmModel;
+ private Map<String, CrossEntityReferenceDescriptor> crossReferenceEntityDescriptors;
+
+
+ public CrossEntityReferenceLookup() {
+ crossReferenceEntityOxmModel = new LinkedHashMap<String, HashMap<String, String>>();
+ crossReferenceEntityDescriptors = new HashMap<String, CrossEntityReferenceDescriptor>();
+ }
+
+ @Override
+ public void processOxmModel(DynamicJAXBContext jaxbContext) {
+
+ @SuppressWarnings("rawtypes")
+ List<Descriptor> descriptorsList = jaxbContext.getXMLContext().getDescriptors();
+
+ for (@SuppressWarnings("rawtypes")
+ Descriptor desc : descriptorsList) {
+
+ DynamicType entity = jaxbContext.getDynamicType(desc.getAlias());
+
+ LinkedHashMap<String, String> oxmProperties = new LinkedHashMap<String, String>();
+
+ // Not all fields have key attributes
+ if (desc.getPrimaryKeyFields() != null) {
+ oxmProperties.put("primaryKeyAttributeNames", desc.getPrimaryKeyFields().toString()
+ .replaceAll("/text\\(\\)", "").replaceAll("\\[", "").replaceAll("\\]", ""));
+ }
+
+ String entityName = desc.getDefaultRootElement();
+
+ // add entityName
+ oxmProperties.put("entityName", entityName);
+
+ Map<String, String> properties = entity.getDescriptor().getProperties();
+ if (properties != null) {
+ for (Map.Entry<String, String> entry : properties.entrySet()) {
+
+ if (entry.getKey().equalsIgnoreCase("crossEntityReference")) {
+ oxmProperties.put("crossEntityReference", entry.getValue());
+ }
+ }
+ }
+
+ if (oxmProperties.containsKey("crossEntityReference")) {
+ crossReferenceEntityOxmModel.put(entityName, oxmProperties);
+ }
+
+ }
+
+ for (Entry<String, HashMap<String, String>> crossRefModel : crossReferenceEntityOxmModel
+ .entrySet()) {
+ HashMap<String, String> attribute = crossRefModel.getValue();
+ CrossEntityReferenceDescriptor entity = new CrossEntityReferenceDescriptor();
+ entity.setEntityName(attribute.get("entityName"));
+ entity.setPrimaryKeyAttributeNames(
+ Arrays.asList(attribute.get("primaryKeyAttributeNames").replace(" ", "").split(",")));
+
+ List<String> crossEntityRefTokens =
+ Arrays.asList(attribute.get("crossEntityReference").split(","));
+
+ if (crossEntityRefTokens.size() >= 2) {
+ CrossEntityReference entityRef = new CrossEntityReference();
+ entityRef.setTargetEntityType(crossEntityRefTokens.get(0));
+
+ for (int i = 1; i < crossEntityRefTokens.size(); i++) {
+ entityRef.addReferenceAttribute(crossEntityRefTokens.get(i));
+ }
+
+ entity.setCrossEntityReference(entityRef);
+ }
+ crossReferenceEntityDescriptors.put(attribute.get("entityName"), entity);
+ }
+
+ }
+
+ public Map<String, HashMap<String, String>> getCrossReferenceEntityOxmModel() {
+ return crossReferenceEntityOxmModel;
+ }
+
+ public void setCrossReferenceEntityOxmModel(
+ Map<String, HashMap<String, String>> crossReferenceEntityOxmModel) {
+ this.crossReferenceEntityOxmModel = crossReferenceEntityOxmModel;
+ }
+
+ public Map<String, CrossEntityReferenceDescriptor> getCrossReferenceEntityDescriptors() {
+ return crossReferenceEntityDescriptors;
+ }
+
+ public void setCrossReferenceEntityDescriptors(
+ Map<String, CrossEntityReferenceDescriptor> crossReferenceEntityDescriptors) {
+ this.crossReferenceEntityDescriptors = crossReferenceEntityDescriptors;
+ }
+
+
+
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/config/oxm/GeoEntityDescriptor.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/config/oxm/GeoEntityDescriptor.java
new file mode 100644
index 0000000..4e995a5
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/config/oxm/GeoEntityDescriptor.java
@@ -0,0 +1,61 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.config.oxm;
+
+public class GeoEntityDescriptor extends OxmEntityDescriptor {
+
+ protected String geoLatName;
+
+ protected String geoLongName;
+
+ public String getGeoLatName() {
+ return geoLatName;
+ }
+
+ public void setGeoLatName(String geoLatName) {
+ this.geoLatName = geoLatName;
+ }
+
+ public String getGeoLongName() {
+ return geoLongName;
+ }
+
+ public void setGeoLongName(String geoLongName) {
+ this.geoLongName = geoLongName;
+ }
+
+ @Override
+ public String toString() {
+ return "GeoEntityDescriptor [" + (geoLatName != null ? "geoLatName=" + geoLatName + ", " : "")
+ + (geoLongName != null ? "geoLongName=" + geoLongName + ", " : "")
+ + (entityName != null ? "entityName=" + entityName + ", " : "")
+ + (primaryKeyAttributeNames != null ? "primaryKeyAttributeNames=" + primaryKeyAttributeNames
+ : "")
+ + "]";
+ }
+
+
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/config/oxm/GeoEntityLookup.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/config/oxm/GeoEntityLookup.java
new file mode 100644
index 0000000..1e61345
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/config/oxm/GeoEntityLookup.java
@@ -0,0 +1,137 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.config.oxm;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.eclipse.persistence.dynamic.DynamicType;
+import org.eclipse.persistence.internal.oxm.mappings.Descriptor;
+import org.eclipse.persistence.jaxb.dynamic.DynamicJAXBContext;
+
+public class GeoEntityLookup implements OxmModelProcessor {
+
+ private Map<String, HashMap<String, String>> geoEntityOxmModel;
+
+ private Map<String, GeoOxmEntityDescriptor> geoEntityDescriptors;
+
+ public GeoEntityLookup() {
+ geoEntityOxmModel = new LinkedHashMap<String, HashMap<String, String>>();
+ geoEntityDescriptors = new HashMap<String, GeoOxmEntityDescriptor>();
+ }
+
+ public Map<String, HashMap<String, String>> getGeoEntityOxmModel() {
+ return geoEntityOxmModel;
+ }
+
+ public void setGeoEntityOxmModel(Map<String, HashMap<String, String>> geoEntityOxmModel) {
+ this.geoEntityOxmModel = geoEntityOxmModel;
+ }
+
+ public Map<String, GeoOxmEntityDescriptor> getGeoEntityDescriptors() {
+ return geoEntityDescriptors;
+ }
+
+ public void setGeoEntityDescriptors(Map<String, GeoOxmEntityDescriptor> geoEntityDescriptors) {
+ this.geoEntityDescriptors = geoEntityDescriptors;
+ }
+
+ @Override
+ public void processOxmModel(DynamicJAXBContext jaxbContext) {
+
+ @SuppressWarnings("rawtypes")
+ List<Descriptor> descriptorsList = jaxbContext.getXMLContext().getDescriptors();
+
+ for (@SuppressWarnings("rawtypes")
+ Descriptor desc : descriptorsList) {
+
+ DynamicType entity = jaxbContext.getDynamicType(desc.getAlias());
+
+ LinkedHashMap<String, String> oxmProperties = new LinkedHashMap<String, String>();
+
+ // Not all fields have key attributes
+ if (desc.getPrimaryKeyFields() != null) {
+ oxmProperties.put("primaryKeyAttributeNames", desc.getPrimaryKeyFields().toString()
+ .replaceAll("/text\\(\\)", "").replaceAll("\\[", "").replaceAll("\\]", ""));
+ }
+
+ String entityName = desc.getDefaultRootElement();
+
+ // add entityName
+ oxmProperties.put("entityName", entityName);
+
+ Map<String, String> properties = entity.getDescriptor().getProperties();
+
+ if (properties != null) {
+ for (Map.Entry<String, String> entry : properties.entrySet()) {
+
+ if (entry.getKey().equalsIgnoreCase("geoLat")) {
+ if (entry.getValue().length() > 0) {
+ oxmProperties.put("geoLat", entry.getValue());
+ }
+ } else if (entry.getKey().equalsIgnoreCase("geoLong")) {
+ if (entry.getValue().length() > 0) {
+ oxmProperties.put("geoLong", entry.getValue());
+ }
+ }
+ }
+ }
+
+ if (oxmProperties.containsKey("geoLat") && oxmProperties.containsKey("geoLong")) {
+ geoEntityOxmModel.put(entityName, oxmProperties);
+ }
+
+ }
+
+ for (Entry<String, HashMap<String, String>> entityModel : geoEntityOxmModel.entrySet()) {
+
+ HashMap<String, String> attribute = entityModel.getValue();
+
+ GeoOxmEntityDescriptor entity = new GeoOxmEntityDescriptor();
+
+ entity.setEntityName(attribute.get("entityName"));
+
+ if (attribute.containsKey("primaryKeyAttributeNames")) {
+
+ entity.setPrimaryKeyAttributeNames(
+ Arrays.asList(attribute.get("primaryKeyAttributeNames").replace(" ", "").split(",")));
+
+ if (attribute.containsKey("geoLat") || attribute.containsKey("geoLong")) {
+ entity.setGeoLatName(attribute.get("geoLat"));
+ entity.setGeoLongName(attribute.get("geoLong"));
+ }
+
+ geoEntityDescriptors.put(attribute.get("entityName"), entity);
+ }
+ }
+
+ }
+
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/config/oxm/GeoOxmEntityDescriptor.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/config/oxm/GeoOxmEntityDescriptor.java
new file mode 100644
index 0000000..03fb9d6
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/config/oxm/GeoOxmEntityDescriptor.java
@@ -0,0 +1,71 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.config.oxm;
+
+public class GeoOxmEntityDescriptor extends OxmEntityDescriptor {
+
+ private String geoLatName;
+
+ private String geoLongName;
+
+ public String getGeoLatName() {
+ return geoLatName;
+ }
+
+ public void setGeoLatName(String geoLatName) {
+ this.geoLatName = geoLatName;
+ }
+
+ public String getGeoLongName() {
+ return geoLongName;
+ }
+
+ public void setGeoLongName(String geoLongName) {
+ this.geoLongName = geoLongName;
+ }
+
+ /**
+ * Checks for geo entity.
+ *
+ * @return true, if successful
+ */
+ public boolean hasGeoEntity() {
+ return (this.geoLongName != null && this.geoLatName != null);
+ }
+
+ @Override
+ public String toString() {
+ return "GeoOxmEntityDescriptor ["
+ + (geoLatName != null ? "geoLatName=" + geoLatName + ", " : "")
+ + (geoLongName != null ? "geoLongName=" + geoLongName + ", " : "")
+ + (entityName != null ? "entityName=" + entityName + ", " : "")
+ + (primaryKeyAttributeNames != null ? "primaryKeyAttributeNames=" + primaryKeyAttributeNames
+ : "")
+ + "]";
+ }
+
+
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/config/oxm/OxmEntityDescriptor.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/config/oxm/OxmEntityDescriptor.java
new file mode 100644
index 0000000..fd071d1
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/config/oxm/OxmEntityDescriptor.java
@@ -0,0 +1,68 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.config.oxm;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class OxmEntityDescriptor {
+
+ protected String entityName;
+
+ protected List<String> primaryKeyAttributeNames;
+
+ public OxmEntityDescriptor() {
+ primaryKeyAttributeNames = new ArrayList<String>();
+ }
+
+ public String getEntityName() {
+ return entityName;
+ }
+
+ public void setEntityName(String entityName) {
+ this.entityName = entityName;
+ }
+
+ public List<String> getPrimaryKeyAttributeNames() {
+ return primaryKeyAttributeNames;
+ }
+
+ public void setPrimaryKeyAttributeNames(List<String> primaryKeyAttributeNames) {
+ this.primaryKeyAttributeNames = primaryKeyAttributeNames;
+ }
+
+ public void addPrimaryKeyName(String name) {
+ primaryKeyAttributeNames.add(name);
+ }
+
+ @Override
+ public String toString() {
+ return "OxmEntityDescriptor [" + (entityName != null ? "entityName=" + entityName + ", " : "")
+ + (primaryKeyAttributeNames != null ? "primaryKeyAttributeNames=" + primaryKeyAttributeNames
+ : "")
+ + "]";
+ }
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/config/oxm/OxmEntityLookup.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/config/oxm/OxmEntityLookup.java
new file mode 100644
index 0000000..09326a8
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/config/oxm/OxmEntityLookup.java
@@ -0,0 +1,132 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.config.oxm;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.eclipse.persistence.dynamic.DynamicType;
+import org.eclipse.persistence.internal.oxm.mappings.Descriptor;
+import org.eclipse.persistence.jaxb.dynamic.DynamicJAXBContext;
+
+public class OxmEntityLookup implements OxmModelProcessor {
+
+ private Map<String, HashMap<String, String>> oxmModel;
+
+ private Map<String, DynamicType> entityTypeLookup;
+
+ private Map<String, OxmEntityDescriptor> entityDescriptors;
+
+
+ public OxmEntityLookup() {
+ oxmModel = new LinkedHashMap<String, HashMap<String, String>>();
+ entityTypeLookup = new LinkedHashMap<String, DynamicType>();
+ entityDescriptors = new HashMap<String, OxmEntityDescriptor>();
+ }
+
+ @Override
+ public void processOxmModel(DynamicJAXBContext jaxbContext) {
+
+ @SuppressWarnings("rawtypes")
+ List<Descriptor> descriptorsList = jaxbContext.getXMLContext().getDescriptors();
+
+ for (@SuppressWarnings("rawtypes")
+ Descriptor desc : descriptorsList) {
+
+ DynamicType entity = jaxbContext.getDynamicType(desc.getAlias());
+
+ LinkedHashMap<String, String> oxmProperties = new LinkedHashMap<String, String>();
+
+ // Not all fields have key attributes
+ if (desc.getPrimaryKeyFields() != null) {
+ oxmProperties.put("primaryKeyAttributeNames", desc.getPrimaryKeyFields().toString()
+ .replaceAll("/text\\(\\)", "").replaceAll("\\[", "").replaceAll("\\]", ""));
+ }
+
+ String entityName = desc.getDefaultRootElement();
+
+ entityTypeLookup.put(entityName, entity);
+
+ // add entityName
+ oxmProperties.put("entityName", entityName);
+
+ Map<String, String> properties = entity.getDescriptor().getProperties();
+
+ oxmModel.put(entityName, oxmProperties);
+
+ }
+
+ for (Entry<String, HashMap<String, String>> entityModel : oxmModel.entrySet()) {
+ HashMap<String, String> attribute = entityModel.getValue();
+ OxmEntityDescriptor entity = new OxmEntityDescriptor();
+
+ entity.setEntityName(attribute.get("entityName"));
+
+ if (attribute.containsKey("primaryKeyAttributeNames")) {
+
+ entity.setPrimaryKeyAttributeNames(
+ Arrays.asList(attribute.get("primaryKeyAttributeNames").replace(" ", "").split(",")));
+
+ entityDescriptors.put(attribute.get("entityName"), entity);
+ }
+ }
+
+ }
+
+ public Map<String, HashMap<String, String>> getOxmModel() {
+ return oxmModel;
+ }
+
+ public void setOxmModel(Map<String, HashMap<String, String>> oxmModel) {
+ this.oxmModel = oxmModel;
+ }
+
+ public Map<String, DynamicType> getEntityTypeLookup() {
+ return entityTypeLookup;
+ }
+
+ public void setEntityTypeLookup(Map<String, DynamicType> entityTypeLookup) {
+ this.entityTypeLookup = entityTypeLookup;
+ }
+
+ public Map<String, OxmEntityDescriptor> getEntityDescriptors() {
+ return entityDescriptors;
+ }
+
+ public void setEntityDescriptors(Map<String, OxmEntityDescriptor> entityDescriptors) {
+ this.entityDescriptors = entityDescriptors;
+ }
+
+ public void addEntityDescriptor(String type, OxmEntityDescriptor descriptor) {
+ if ( this.entityDescriptors != null ) {
+ this.entityDescriptors.put(type, descriptor);
+ }
+ }
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/config/oxm/OxmModelLoader.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/config/oxm/OxmModelLoader.java
new file mode 100644
index 0000000..475fe8f
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/config/oxm/OxmModelLoader.java
@@ -0,0 +1,195 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.config.oxm;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.eclipse.persistence.jaxb.JAXBContextProperties;
+import org.eclipse.persistence.jaxb.dynamic.DynamicJAXBContext;
+import org.eclipse.persistence.jaxb.dynamic.DynamicJAXBContextFactory;
+import org.onap.aai.cl.api.Logger;
+import org.onap.aai.cl.eelf.LoggerFactory;
+import org.onap.aai.sparky.logging.AaiUiMsgs;
+import org.springframework.core.io.Resource;
+import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
+import org.springframework.core.io.support.ResourcePatternResolver;
+
+public class OxmModelLoader {
+
+ private static final Logger LOG = LoggerFactory.getInstance().getLogger(OxmModelLoader.class);
+
+ /*
+ * The intent of this parameter is to be able to programmatically over-ride the latest AAI schema
+ * version discovered from the aai-schema jar file. This property is optional, but if set on the
+ * bean or by another class in the system, then it will override the spec version that is loaded.
+ *
+ * If the latestVersionOverride is greater than 0 then it will set the latest version to the
+ * specified version, and that stream will be returned if available.
+ */
+
+ protected int oxmApiVersionOverride;
+ protected Set<OxmModelProcessor> processors;
+ private int latestVersionNum = 0;
+
+ private final static Pattern p = Pattern.compile("aai_oxm_(v)(.*).xml");
+
+ public OxmModelLoader() {
+ this(-1, new HashSet<OxmModelProcessor>());
+ }
+
+ public OxmModelLoader(int apiVersionOverride,Set<OxmModelProcessor> oxmModelProcessors) {
+ this.oxmApiVersionOverride = apiVersionOverride;
+ this.processors = oxmModelProcessors;
+ }
+
+ protected synchronized Map<Integer, InputStream> getStreamHandlesForOxmFromResource() {
+ Map<Integer, InputStream> listOfOxmFiles = new HashMap<Integer, InputStream>();
+ ClassLoader oxmClassLoader = OxmModelLoader.class.getClassLoader();
+ ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(oxmClassLoader);
+ Resource[] resources = null;
+ try {
+ resources = resolver.getResources("classpath*:/oxm/aai_oxm*.xml");
+ } catch (IOException ex) {
+ LOG.error(AaiUiMsgs.OXM_LOADING_ERROR, ex.getMessage());
+ }
+
+ if (resources == null) {
+ LOG.error(AaiUiMsgs.OXM_LOADING_ERROR, "No OXM schema files found on classpath");
+ }
+
+ for (Resource resource : resources) {
+ Matcher m = p.matcher(resource.getFilename());
+
+ if (m.matches()) {
+ try {
+ listOfOxmFiles.put(new Integer(m.group(2)), resource.getInputStream());
+ } catch (Exception e) {
+ LOG.error(AaiUiMsgs.OXM_LOADING_ERROR,
+ resource.getFilename(), e.getMessage());
+ }
+ }
+ }
+ return listOfOxmFiles;
+ }
+
+ /**
+ * Load an oxm model.
+ * @param inputStream file handle for oxm
+ */
+ protected void loadModel(InputStream inputStream) {
+ Map<String, Object> properties = new HashMap<String, Object>();
+ properties.put(JAXBContextProperties.OXM_METADATA_SOURCE, inputStream);
+ try {
+ final DynamicJAXBContext oxmContext = DynamicJAXBContextFactory
+ .createContextFromOXM(Thread.currentThread().getContextClassLoader(), properties);
+
+ parseOxmContext(oxmContext);
+ // populateSearchableOxmModel();
+ LOG.info(AaiUiMsgs.OXM_LOAD_SUCCESS, String.valueOf(latestVersionNum));
+ } catch (Exception exc) {
+ LOG.info(AaiUiMsgs.OXM_PARSE_ERROR_NONVERBOSE);
+ LOG.error(AaiUiMsgs.OXM_PARSE_ERROR_VERBOSE, "OXM v" + latestVersionNum, exc.getMessage());
+ }
+ }
+
+ /**
+ * Load the latest oxm model.
+ */
+ public synchronized void loadLatestOxmModel() {
+
+ LOG.info(AaiUiMsgs.INITIALIZE_OXM_MODEL_LOADER);
+
+ // find handles for available oxm models
+ final Map<Integer, InputStream> listOfOxmStreams = getStreamHandlesForOxmFromResource();
+ if (listOfOxmStreams.isEmpty()) {
+ LOG.error(AaiUiMsgs.OXM_FILE_NOT_FOUND);
+ return;
+ }
+
+ InputStream stream = null;
+
+ if (oxmApiVersionOverride > 0) {
+ latestVersionNum = oxmApiVersionOverride;
+ LOG.warn(AaiUiMsgs.WARN_GENERIC, "Overriding AAI Schema with version = " + latestVersionNum);
+ stream = listOfOxmStreams.get(latestVersionNum);
+ } else {
+
+ for (Integer key : listOfOxmStreams.keySet()) {
+ if (key.intValue() > latestVersionNum) {
+ latestVersionNum = key.intValue();
+ stream = listOfOxmStreams.get(key);
+ }
+ }
+ }
+
+ // load the latest oxm file
+ loadModel(stream);
+
+ }
+
+ public int getLatestVersionNum() {
+ return latestVersionNum;
+ }
+
+ public void setLatestVersionNum(int latestVersionNum) {
+ this.latestVersionNum = latestVersionNum;
+ }
+
+ /**
+ * Parses the oxm context.
+ *
+ * @param oxmContext the oxm context
+ */
+ private void parseOxmContext(DynamicJAXBContext oxmContext) {
+
+ if (processors != null && processors.size() > 0) {
+
+ for (OxmModelProcessor processor : processors) {
+
+ try {
+
+ processor.processOxmModel(oxmContext);
+
+ } catch (Exception exc) {
+
+ LOG.warn(AaiUiMsgs.WARN_GENERIC,
+ "OxmModelProcessor experienced an error. Error: " + exc.getMessage());
+
+ }
+
+ }
+
+ }
+
+ }
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/config/oxm/OxmModelProcessor.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/config/oxm/OxmModelProcessor.java
new file mode 100644
index 0000000..9e250b7
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/config/oxm/OxmModelProcessor.java
@@ -0,0 +1,33 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.config.oxm;
+
+import org.eclipse.persistence.jaxb.dynamic.DynamicJAXBContext;
+
+public interface OxmModelProcessor {
+
+ public void processOxmModel(DynamicJAXBContext jaxbContext);
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/config/oxm/SearchableEntityLookup.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/config/oxm/SearchableEntityLookup.java
new file mode 100644
index 0000000..7833ee0
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/config/oxm/SearchableEntityLookup.java
@@ -0,0 +1,119 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.config.oxm;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.eclipse.persistence.dynamic.DynamicType;
+import org.eclipse.persistence.internal.oxm.mappings.Descriptor;
+import org.eclipse.persistence.jaxb.dynamic.DynamicJAXBContext;
+
+public class SearchableEntityLookup implements OxmModelProcessor {
+
+ private Map<String, HashMap<String, String>> searchableOxmModel;
+ private Map<String, SearchableOxmEntityDescriptor> searchableEntityDescriptors;
+
+ public SearchableEntityLookup() {
+ searchableOxmModel = new LinkedHashMap<String, HashMap<String, String>>();
+ searchableEntityDescriptors = new HashMap<String, SearchableOxmEntityDescriptor>();
+ }
+
+ @Override
+ public void processOxmModel(DynamicJAXBContext jaxbContext) {
+
+ @SuppressWarnings("rawtypes")
+ List<Descriptor> descriptorsList = jaxbContext.getXMLContext().getDescriptors();
+
+ for (@SuppressWarnings("rawtypes")
+ Descriptor desc : descriptorsList) {
+
+ DynamicType entity = jaxbContext.getDynamicType(desc.getAlias());
+
+ LinkedHashMap<String, String> oxmProperties = new LinkedHashMap<String, String>();
+
+ // Not all fields have key attributes
+ if (desc.getPrimaryKeyFields() != null) {
+ oxmProperties.put("primaryKeyAttributeNames", desc.getPrimaryKeyFields().toString()
+ .replaceAll("/text\\(\\)", "").replaceAll("\\[", "").replaceAll("\\]", ""));
+ }
+
+ String entityName = desc.getDefaultRootElement();
+
+ // add entityName
+ oxmProperties.put("entityName", entityName);
+
+ Map<String, String> properties = entity.getDescriptor().getProperties();
+ if (properties != null) {
+ for (Map.Entry<String, String> entry : properties.entrySet()) {
+
+ if (entry.getKey().equalsIgnoreCase("searchable")) {
+ oxmProperties.put("searchableAttributes", entry.getValue());
+ }
+ }
+ }
+
+ // Add all searchable entity types for reserve lookup
+ if (oxmProperties.containsKey("searchableAttributes")) {
+ searchableOxmModel.put(entityName, oxmProperties);
+ }
+
+ }
+
+ for (Entry<String, HashMap<String, String>> searchableModel : searchableOxmModel.entrySet()) {
+ HashMap<String, String> attribute = searchableModel.getValue();
+ SearchableOxmEntityDescriptor entity = new SearchableOxmEntityDescriptor();
+ entity.setEntityName(attribute.get("entityName"));
+ entity.setPrimaryKeyAttributeNames(
+ Arrays.asList(attribute.get("primaryKeyAttributeNames").replace(" ", "").split(",")));
+ entity
+ .setSearchableAttributes(Arrays.asList(attribute.get("searchableAttributes").split(",")));
+ searchableEntityDescriptors.put(attribute.get("entityName"), entity);
+ }
+
+ }
+
+ public Map<String, HashMap<String, String>> getSearchableOxmModel() {
+ return searchableOxmModel;
+ }
+
+ public void setSearchableOxmModel(Map<String, HashMap<String, String>> searchableOxmModel) {
+ this.searchableOxmModel = searchableOxmModel;
+ }
+
+ public Map<String, SearchableOxmEntityDescriptor> getSearchableEntityDescriptors() {
+ return searchableEntityDescriptors;
+ }
+
+ public void setSearchableEntityDescriptors(
+ Map<String, SearchableOxmEntityDescriptor> searchableEntityDescriptors) {
+ this.searchableEntityDescriptors = searchableEntityDescriptors;
+ }
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/config/oxm/SearchableOxmEntityDescriptor.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/config/oxm/SearchableOxmEntityDescriptor.java
new file mode 100644
index 0000000..9f2809f
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/config/oxm/SearchableOxmEntityDescriptor.java
@@ -0,0 +1,75 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.config.oxm;
+
+import java.util.List;
+
+public class SearchableOxmEntityDescriptor extends OxmEntityDescriptor {
+
+ protected List<String> searchableAttributes;
+
+ public List<String> getSearchableAttributes() {
+ return searchableAttributes;
+ }
+
+ public void setSearchableAttributes(List<String> searchableAttributes) {
+ this.searchableAttributes = searchableAttributes;
+ }
+
+ public void addSearchableAttribute(String attributeName) {
+ searchableAttributes.add(attributeName);
+ }
+
+ /**
+ * Checks for searchable attributes.
+ *
+ * @return true, if successful
+ */
+ public boolean hasSearchableAttributes() {
+
+ if (this.searchableAttributes == null) {
+ return false;
+ }
+
+ if (this.searchableAttributes.size() > 0) {
+ return true;
+ }
+
+ return false;
+
+ }
+
+ @Override
+ public String toString() {
+ return "SearchableOxmEntityDescriptor ["
+ + (searchableAttributes != null ? "searchableAttributes=" + searchableAttributes + ", "
+ : "")
+ + (entityName != null ? "entityName=" + entityName + ", " : "")
+ + (primaryKeyAttributeNames != null ? "primaryKeyAttributeNames=" + primaryKeyAttributeNames
+ : "")
+ + "]";
+ }
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/config/oxm/SuggestionEntityDescriptor.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/config/oxm/SuggestionEntityDescriptor.java
new file mode 100644
index 0000000..774f6b0
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/config/oxm/SuggestionEntityDescriptor.java
@@ -0,0 +1,54 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.config.oxm;
+
+import org.onap.aai.sparky.sync.entity.SuggestionSearchEntity;
+
+public class SuggestionEntityDescriptor extends OxmEntityDescriptor {
+
+ protected SuggestionSearchEntity suggestionSearchEntity;
+
+ public SuggestionSearchEntity getSuggestionSearchEntity() {
+ return suggestionSearchEntity;
+ }
+
+ public void setSuggestionSearchEntity(SuggestionSearchEntity suggestionSearchEntity) {
+ this.suggestionSearchEntity = suggestionSearchEntity;
+ }
+
+ @Override
+ public String toString() {
+ return "SuggestionEntityDescriptor ["
+ + (suggestionSearchEntity != null
+ ? "suggestionSearchEntity=" + suggestionSearchEntity + ", " : "")
+ + (entityName != null ? "entityName=" + entityName + ", " : "")
+ + (primaryKeyAttributeNames != null ? "primaryKeyAttributeNames=" + primaryKeyAttributeNames
+ : "")
+ + "]";
+ }
+
+
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/config/oxm/SuggestionEntityLookup.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/config/oxm/SuggestionEntityLookup.java
new file mode 100644
index 0000000..fde1b6a
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/config/oxm/SuggestionEntityLookup.java
@@ -0,0 +1,181 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.config.oxm;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Vector;
+
+import org.eclipse.persistence.dynamic.DynamicType;
+import org.eclipse.persistence.internal.oxm.mappings.Descriptor;
+import org.eclipse.persistence.jaxb.dynamic.DynamicJAXBContext;
+import org.eclipse.persistence.mappings.DatabaseMapping;
+import org.onap.aai.sparky.search.filters.config.FiltersConfig;
+import org.onap.aai.sparky.sync.entity.SuggestionSearchEntity;
+
+public class SuggestionEntityLookup implements OxmModelProcessor {
+
+ private Map<String, HashMap<String, String>> suggestionSearchEntityOxmModel;
+ private Map<String, SuggestionEntityDescriptor> suggestionSearchEntityDescriptors;
+ private FiltersConfig filtersConfig;
+
+ public SuggestionEntityLookup(FiltersConfig filtersConfig) {
+ suggestionSearchEntityOxmModel = new LinkedHashMap<String, HashMap<String, String>>();
+ suggestionSearchEntityDescriptors = new HashMap<String, SuggestionEntityDescriptor>();
+ this.filtersConfig = filtersConfig;
+ }
+
+ @Override
+ public void processOxmModel(DynamicJAXBContext jaxbContext) {
+
+ @SuppressWarnings("rawtypes")
+ List<Descriptor> descriptorsList = jaxbContext.getXMLContext().getDescriptors();
+
+ for (@SuppressWarnings("rawtypes")
+ Descriptor desc : descriptorsList) {
+
+ DynamicType entity = jaxbContext.getDynamicType(desc.getAlias());
+
+ LinkedHashMap<String, String> oxmProperties = new LinkedHashMap<String, String>();
+
+ // Not all fields have key attributes
+ if (desc.getPrimaryKeyFields() != null) {
+ oxmProperties.put("primaryKeyAttributeNames", desc.getPrimaryKeyFields().toString()
+ .replaceAll("/text\\(\\)", "").replaceAll("\\[", "").replaceAll("\\]", ""));
+ }
+
+ String entityName = desc.getDefaultRootElement();
+
+ // add entityName
+ oxmProperties.put("entityName", entityName);
+
+ Map<String, String> properties = entity.getDescriptor().getProperties();
+ if (properties != null) {
+ for (Map.Entry<String, String> entry : properties.entrySet()) {
+
+
+ if (entry.getKey().equalsIgnoreCase("containsSuggestibleProps")) {
+
+ oxmProperties.put("containsSuggestibleProps", "true");
+
+ Vector<DatabaseMapping> descriptorMaps = entity.getDescriptor().getMappings();
+ List<String> listOfSuggestableAttributes = new ArrayList<String>();
+
+ for (DatabaseMapping descMap : descriptorMaps) {
+ if (descMap.isAbstractDirectMapping()) {
+
+ if (descMap.getProperties().get("suggestibleOnSearch") != null) {
+ String suggestableOnSearchString =
+ String.valueOf(descMap.getProperties().get("suggestibleOnSearch"));
+
+ boolean isSuggestibleOnSearch = Boolean.valueOf(suggestableOnSearchString);
+
+ if (isSuggestibleOnSearch) {
+ /* Grab attribute types for suggestion */
+ String attributeName =
+ descMap.getField().getName().replaceAll("/text\\(\\)", "");
+ listOfSuggestableAttributes.add(attributeName);
+
+ if (descMap.getProperties().get("suggestionVerbs") != null) {
+ String suggestionVerbsString =
+ String.valueOf(descMap.getProperties().get("suggestionVerbs"));
+
+ oxmProperties.put("suggestionVerbs", suggestionVerbsString);
+ }
+ }
+ }
+ }
+ }
+
+ if (!listOfSuggestableAttributes.isEmpty()) {
+ oxmProperties.put("suggestibleAttributes",
+ String.join(",", listOfSuggestableAttributes));
+ }
+ } else if (entry.getKey().equalsIgnoreCase("suggestionAliases")) {
+ oxmProperties.put("suggestionAliases", entry.getValue());
+ }
+ }
+ }
+
+ if (oxmProperties.containsKey("containsSuggestibleProps")) {
+ suggestionSearchEntityOxmModel.put(entityName, oxmProperties);
+ }
+ }
+
+ for (Entry<String, HashMap<String, String>> suggestionEntityModel : suggestionSearchEntityOxmModel
+ .entrySet()) {
+ HashMap<String, String> attribute = suggestionEntityModel.getValue();
+
+ String entityName = attribute.get("entityName");
+ SuggestionSearchEntity suggestionSearchEntity = new SuggestionSearchEntity(filtersConfig, this);
+ suggestionSearchEntity.setEntityType(entityName);
+
+ if (attribute.get("suggestionAliases") != null) {
+ suggestionSearchEntity
+ .setSuggestionAliases(Arrays.asList(attribute.get("suggestionAliases").split(",")));
+ }
+
+ if (attribute.get("suggestibleAttributes") != null) {
+ suggestionSearchEntity.setSuggestionPropertyTypes(
+ Arrays.asList(attribute.get("suggestibleAttributes").split(",")));
+ }
+
+ SuggestionEntityDescriptor entity = new SuggestionEntityDescriptor();
+ entity.setSuggestionSearchEntity(suggestionSearchEntity);
+ entity.setEntityName(entityName);
+
+ if (attribute.get("primaryKeyAttributeNames") != null) {
+ entity.setPrimaryKeyAttributeNames(
+ Arrays.asList(attribute.get("primaryKeyAttributeNames").replace(" ", "").split(",")));
+ }
+
+ suggestionSearchEntityDescriptors.put(entityName, entity);
+ }
+ }
+
+ public Map<String, HashMap<String, String>> getSuggestionSearchEntityOxmModel() {
+ return suggestionSearchEntityOxmModel;
+ }
+
+ public void setSuggestionSearchEntityOxmModel(
+ Map<String, HashMap<String, String>> suggestionSearchEntityOxmModel) {
+ this.suggestionSearchEntityOxmModel = suggestionSearchEntityOxmModel;
+ }
+
+ public Map<String, SuggestionEntityDescriptor> getSuggestionSearchEntityDescriptors() {
+ return suggestionSearchEntityDescriptors;
+ }
+
+ public void setSuggestionSearchEntityDescriptors(
+ Map<String, SuggestionEntityDescriptor> suggestionSearchEntityDescriptors) {
+ this.suggestionSearchEntityDescriptors = suggestionSearchEntityDescriptors;
+ }
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/crossentityreference/sync/CrossEntityReferenceSynchronizer.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/crossentityreference/sync/CrossEntityReferenceSynchronizer.java
new file mode 100644
index 0000000..604c74c
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/crossentityreference/sync/CrossEntityReferenceSynchronizer.java
@@ -0,0 +1,937 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.crossentityreference.sync;
+
+import static java.util.concurrent.CompletableFuture.supplyAsync;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Deque;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentLinkedDeque;
+import java.util.concurrent.ExecutorService;
+import java.util.function.Supplier;
+
+import org.onap.aai.cl.api.Logger;
+import org.onap.aai.cl.eelf.LoggerFactory;
+import org.onap.aai.cl.mdc.MdcContext;
+import org.onap.aai.restclient.client.OperationResult;
+import org.onap.aai.sparky.config.oxm.CrossEntityReference;
+import org.onap.aai.sparky.config.oxm.CrossEntityReferenceDescriptor;
+import org.onap.aai.sparky.config.oxm.CrossEntityReferenceLookup;
+import org.onap.aai.sparky.config.oxm.OxmEntityDescriptor;
+import org.onap.aai.sparky.config.oxm.OxmEntityLookup;
+import org.onap.aai.sparky.config.oxm.SearchableEntityLookup;
+import org.onap.aai.sparky.config.oxm.SearchableOxmEntityDescriptor;
+import org.onap.aai.sparky.dal.ActiveInventoryAdapter;
+import org.onap.aai.sparky.dal.NetworkTransaction;
+import org.onap.aai.sparky.dal.rest.HttpMethod;
+import org.onap.aai.sparky.logging.AaiUiMsgs;
+import org.onap.aai.sparky.sync.AbstractEntitySynchronizer;
+import org.onap.aai.sparky.sync.IndexSynchronizer;
+import org.onap.aai.sparky.sync.SynchronizerConstants;
+import org.onap.aai.sparky.sync.config.ElasticSearchSchemaConfig;
+import org.onap.aai.sparky.sync.config.NetworkStatisticsConfig;
+import org.onap.aai.sparky.sync.entity.IndexableCrossEntityReference;
+import org.onap.aai.sparky.sync.entity.MergableEntity;
+import org.onap.aai.sparky.sync.entity.SelfLinkDescriptor;
+import org.onap.aai.sparky.sync.enumeration.OperationState;
+import org.onap.aai.sparky.sync.enumeration.SynchronizerState;
+import org.onap.aai.sparky.sync.task.PerformActiveInventoryRetrieval;
+import org.onap.aai.sparky.sync.task.PerformElasticSearchPut;
+import org.onap.aai.sparky.sync.task.PerformElasticSearchRetrieval;
+import org.onap.aai.sparky.sync.task.PerformElasticSearchUpdate;
+import org.onap.aai.sparky.util.NodeUtils;
+import org.slf4j.MDC;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectReader;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+
+/**
+ * The Class CrossEntityReferenceSynchronizer.
+ */
+public class CrossEntityReferenceSynchronizer extends AbstractEntitySynchronizer
+ implements IndexSynchronizer {
+
+ /**
+ * The Class RetryCrossEntitySyncContainer.
+ */
+ private class RetryCrossEntitySyncContainer {
+ NetworkTransaction txn;
+ IndexableCrossEntityReference icer;
+
+ /**
+ * Instantiates a new retry cross entity sync container.
+ *
+ * @param txn the txn
+ * @param icer the icer
+ */
+ public RetryCrossEntitySyncContainer(NetworkTransaction txn,
+ IndexableCrossEntityReference icer) {
+ this.txn = txn;
+ this.icer = icer;
+ }
+
+ public NetworkTransaction getNetworkTransaction() {
+ return txn;
+ }
+
+ public IndexableCrossEntityReference getIndexableCrossEntityReference() {
+ return icer;
+ }
+ }
+
+ private static final Logger LOG =
+ LoggerFactory.getInstance().getLogger(CrossEntityReferenceSynchronizer.class);
+
+ private static final String SERVICE_INSTANCE = "service-instance";
+
+ private Deque<SelfLinkDescriptor> selflinks;
+ private Deque<RetryCrossEntitySyncContainer> retryQueue;
+ private Map<String, Integer> retryLimitTracker;
+ private boolean isAllWorkEnumerated;
+ protected ExecutorService esPutExecutor;
+ private CrossEntityReferenceLookup crossEntityReferenceLookup;
+ private OxmEntityLookup oxmEntityLookup;
+ private SearchableEntityLookup searchableEntityLookup;
+
+
+ /**
+ * Instantiates a new cross entity reference synchronizer.
+ *
+ * @param indexName the index name
+ * @throws Exception the exception
+ */
+ public CrossEntityReferenceSynchronizer(ElasticSearchSchemaConfig schemaConfig,
+ int internalSyncWorkers, int aaiWorkers, int esWorkers, NetworkStatisticsConfig aaiStatConfig,
+ NetworkStatisticsConfig esStatConfig, CrossEntityReferenceLookup crossEntityReferenceLookup,
+ OxmEntityLookup oxmEntityLookup, SearchableEntityLookup searchableEntityLookup) throws Exception {
+ super(LOG, "CERS", internalSyncWorkers, aaiWorkers, esWorkers, schemaConfig.getIndexName(),
+ aaiStatConfig, esStatConfig);
+ this.crossEntityReferenceLookup = crossEntityReferenceLookup;
+ this.oxmEntityLookup = oxmEntityLookup;
+ this.searchableEntityLookup = searchableEntityLookup;
+ this.selflinks = new ConcurrentLinkedDeque<SelfLinkDescriptor>();
+ this.retryQueue = new ConcurrentLinkedDeque<RetryCrossEntitySyncContainer>();
+ this.retryLimitTracker = new ConcurrentHashMap<String, Integer>();
+ this.synchronizerName = "Cross Reference Entity Synchronizer";
+ this.isAllWorkEnumerated = false;
+ this.esPutExecutor = NodeUtils.createNamedExecutor("CERS-ES-PUT", 5, LOG);
+ this.aaiEntityStats.intializeEntityCounters(
+ crossEntityReferenceLookup.getCrossReferenceEntityDescriptors().keySet());
+
+ this.esEntityStats.intializeEntityCounters(
+ crossEntityReferenceLookup.getCrossReferenceEntityDescriptors().keySet());
+ this.syncDurationInMs = -1;
+ }
+
+ /* (non-Javadoc)
+ * @see org.openecomp.sparky.synchronizer.IndexSynchronizer#doSync()
+ */
+ @Override
+ public OperationState doSync() {
+ this.syncDurationInMs = -1;
+ String txnID = NodeUtils.getRandomTxnId();
+ MdcContext.initialize(txnID, "CrossEntitySynchronizer", "", "Sync", "");
+
+ resetCounters();
+ syncStartedTimeStampInMs = System.currentTimeMillis();
+ launchSyncFlow();
+ return OperationState.OK;
+ }
+
+ @Override
+ public SynchronizerState getState() {
+ if (!isSyncDone()) {
+ return SynchronizerState.PERFORMING_SYNCHRONIZATION;
+ }
+
+ return SynchronizerState.IDLE;
+ }
+
+ /* (non-Javadoc)
+ * @see org.openecomp.sparky.synchronizer.IndexSynchronizer#getStatReport(boolean)
+ */
+ @Override
+ public String getStatReport(boolean showFinalReport) {
+ syncDurationInMs = System.currentTimeMillis() - syncStartedTimeStampInMs;
+ return getStatReport(syncDurationInMs, showFinalReport);
+ }
+
+ /* (non-Javadoc)
+ * @see org.openecomp.sparky.synchronizer.IndexSynchronizer#shutdown()
+ */
+ @Override
+ public void shutdown() {
+ this.shutdownExecutors();
+ }
+
+ @Override
+ protected boolean isSyncDone() {
+ int totalWorkOnHand = aaiWorkOnHand.get() + esWorkOnHand.get();
+
+ if (totalWorkOnHand > 0 || !isAllWorkEnumerated) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Launch sync flow.
+ *
+ * @return the operation state
+ */
+ private OperationState launchSyncFlow() {
+ final Map<String,String> contextMap = MDC.getCopyOfContextMap();
+ Map<String, CrossEntityReferenceDescriptor> descriptorMap =
+ crossEntityReferenceLookup.getCrossReferenceEntityDescriptors();
+
+ if (descriptorMap.isEmpty()) {
+ LOG.error(AaiUiMsgs.ERROR_LOADING_OXM);
+
+ return OperationState.ERROR;
+ }
+
+ Collection<String> syncTypes = descriptorMap.keySet();
+
+ try {
+
+ /*
+ * launch a parallel async thread to process the documents for each entity-type (to max the of
+ * the configured executor anyway)
+ */
+
+ aaiWorkOnHand.set(syncTypes.size());
+
+ for (String key : syncTypes) {
+
+ supplyAsync(new Supplier<Void>() {
+
+ @Override
+ public Void get() {
+ MDC.setContextMap(contextMap);
+ OperationResult typeLinksResult = null;
+ try {
+ typeLinksResult = aaiAdapter.getSelfLinksByEntityType(key);
+ aaiWorkOnHand.decrementAndGet();
+ processEntityTypeSelfLinks(typeLinksResult);
+ } catch (Exception exc) {
+ LOG.error(AaiUiMsgs.ERROR_GENERIC,
+ "An error occurred processing entity selflinks. Error: " + exc.getMessage());
+ }
+
+ return null;
+ }
+
+ }, aaiExecutor).whenComplete((result, error) -> {
+ if (error != null) {
+ LOG.error(AaiUiMsgs.ERROR_GETTING_DATA_FROM_AAI, error.getMessage());
+ }
+ });
+ }
+
+ while (aaiWorkOnHand.get() != 0) {
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug(AaiUiMsgs.WAIT_FOR_ALL_SELFLINKS_TO_BE_COLLECTED);
+ }
+
+ Thread.sleep(1000);
+ }
+
+ aaiWorkOnHand.set(selflinks.size());
+ isAllWorkEnumerated = true;
+ performSync();
+
+ while (!isSyncDone()) {
+ performRetrySync();
+ Thread.sleep(1000);
+ }
+
+ /*
+ * Make sure we don't hang on to retries that failed which could cause issues during future
+ * syncs
+ */
+ retryLimitTracker.clear();
+
+ } catch (Exception exc) {
+ LOG.error(AaiUiMsgs.ERROR_GENERIC,
+ "An error occurred during entity synchronization. Error: " + exc.getMessage());
+
+ }
+
+ return OperationState.OK;
+ }
+
+ /**
+ * Perform sync.
+ */
+ private void performSync() {
+ while (selflinks.peek() != null) {
+
+ SelfLinkDescriptor linkDescriptor = selflinks.poll();
+ aaiWorkOnHand.decrementAndGet();
+
+ CrossEntityReferenceDescriptor descriptor = null;
+
+ if (linkDescriptor.getSelfLink() != null && linkDescriptor.getEntityType() != null) {
+
+ descriptor = crossEntityReferenceLookup.getCrossReferenceEntityDescriptors()
+ .get(linkDescriptor.getEntityType());
+
+ if (descriptor == null) {
+ LOG.error(AaiUiMsgs.MISSING_ENTITY_DESCRIPTOR, linkDescriptor.getEntityType());
+ // go to next element in iterator
+ continue;
+ }
+
+ if (descriptor.hasCrossEntityReferences()) {
+
+ NetworkTransaction txn = new NetworkTransaction();
+ txn.setDescriptor(descriptor);
+ txn.setLink(linkDescriptor.getSelfLink());
+ txn.setQueryParameters(linkDescriptor.getDepthModifier());
+ txn.setOperationType(HttpMethod.GET);
+ txn.setEntityType(linkDescriptor.getEntityType());
+
+ aaiWorkOnHand.incrementAndGet();
+
+ supplyAsync(new PerformActiveInventoryRetrieval(txn, aaiAdapter), aaiExecutor)
+ .whenComplete((result, error) -> {
+
+ aaiWorkOnHand.decrementAndGet();
+
+ if (error != null) {
+ LOG.error(AaiUiMsgs.SELF_LINK_GET, error.getLocalizedMessage());
+ } else {
+ if (result == null) {
+ LOG.error(AaiUiMsgs.SELF_LINK_CROSS_REF_SYNC);
+ } else {
+ updateActiveInventoryCounters(result);
+ fetchDocumentForUpsert(result);
+ }
+ }
+ });
+ }
+ }
+ }
+ }
+
+ /**
+ * Process entity type self links.
+ *
+ * @param operationResult the operation result
+ */
+ private void processEntityTypeSelfLinks(OperationResult operationResult) {
+
+ JsonNode rootNode = null;
+
+ final String jsonResult = operationResult.getResult();
+
+ if (jsonResult != null && jsonResult.length() > 0) {
+
+ try {
+ rootNode = mapper.readTree(jsonResult);
+ } catch (IOException exc) {
+ // TODO // TODO -> LOG, waht should be logged here?
+ }
+
+ JsonNode resultData = rootNode.get("result-data");
+ ArrayNode resultDataArrayNode = null;
+
+ if (resultData.isArray()) {
+ resultDataArrayNode = (ArrayNode) resultData;
+
+ Iterator<JsonNode> elementIterator = resultDataArrayNode.elements();
+ JsonNode element = null;
+
+ while (elementIterator.hasNext()) {
+ element = elementIterator.next();
+
+ final String resourceType = NodeUtils.getNodeFieldAsText(element, "resource-type");
+ final String resourceLink = NodeUtils.getNodeFieldAsText(element, "resource-link");
+
+ CrossEntityReferenceDescriptor descriptor = null;
+
+ if (resourceType != null && resourceLink != null) {
+ descriptor = crossEntityReferenceLookup.getCrossReferenceEntityDescriptors().get(resourceType);
+
+ if (descriptor == null) {
+ LOG.error(AaiUiMsgs.MISSING_ENTITY_DESCRIPTOR, resourceType);
+ // go to next element in iterator
+ continue;
+ }
+ if (descriptor.hasCrossEntityReferences()) {
+ selflinks.add(new SelfLinkDescriptor(
+ resourceLink,SynchronizerConstants.DEPTH_ALL_MODIFIER, resourceType));
+ }
+ }
+ }
+ }
+ }
+ }
+
+
+
+ /**
+ * By providing the entity type and a json node for the entity, determine the
+ * primary key name(s) + primary key value(s) sufficient to build an entity query string
+ * of the following format:
+ *
+ * <entityType>.<primaryKeyNames>:<primaryKeyValues>
+ *
+ * @return - a composite string in the above format or null
+ */
+ private String determineEntityQueryString(String entityType, JsonNode entityJsonNode) {
+
+ OxmEntityDescriptor entityDescriptor =
+ oxmEntityLookup.getEntityDescriptors().get(entityType);
+
+ String queryString = null;
+
+ if ( entityDescriptor != null ) {
+
+ final List<String> primaryKeyNames = entityDescriptor.getPrimaryKeyAttributeNames();
+ final List<String> keyValues = new ArrayList<String>();
+ NodeUtils.extractFieldValuesFromObject(entityJsonNode, primaryKeyNames, keyValues);
+
+ queryString = entityType + "." + NodeUtils.concatArray(primaryKeyNames,"/") + ":" + NodeUtils.concatArray(keyValues);
+
+ }
+
+ return queryString;
+
+
+ }
+
+ /**
+ * Fetch document for upsert.
+ *
+ * @param txn the txn
+ */
+ private void fetchDocumentForUpsert(NetworkTransaction txn) {
+
+ if (!txn.getOperationResult().wasSuccessful()) {
+ LOG.error(AaiUiMsgs.SELF_LINK_GET, txn.getOperationResult().getResult());
+ return;
+ }
+
+ CrossEntityReferenceDescriptor cerDescriptor = crossEntityReferenceLookup
+ .getCrossReferenceEntityDescriptors().get(txn.getDescriptor().getEntityName());
+
+ if (cerDescriptor != null && cerDescriptor.hasCrossEntityReferences()) {
+
+ final String jsonResult = txn.getOperationResult().getResult();
+
+ if (jsonResult != null && jsonResult.length() > 0) {
+
+ /**
+ * Here's what we are going to do:
+ *
+ * <li>Extract primary key name and value from the parent type.
+ * <li>Extract the primary key and value from the nested child instance.
+ * <li>Build a generic query to discover the self-link for the nested-child-instance using
+ * parent and child.
+ * <li>Set the self-link on the child.
+ * <li>Generate the id that will allow the elastic-search upsert to work.
+ * <li>Rinse and repeat.
+ */
+
+ CrossEntityReference cerDefinition = cerDescriptor.getCrossEntityReference();
+
+ if (cerDefinition != null) {
+ JsonNode convertedNode = null;
+ try {
+ convertedNode = NodeUtils.convertJsonStrToJsonNode(txn.getOperationResult().getResult());
+
+ final String parentEntityQueryString = determineEntityQueryString(txn.getEntityType(), convertedNode);
+
+ List<String> extractedParentEntityAttributeValues = new ArrayList<String>();
+
+ NodeUtils.extractFieldValuesFromObject(convertedNode,
+ cerDefinition.getReferenceAttributes(),
+ extractedParentEntityAttributeValues);
+
+ List<JsonNode> nestedTargetEntityInstances = new ArrayList<JsonNode>();
+ NodeUtils.extractObjectsByKey(convertedNode, cerDefinition.getTargetEntityType(),
+ nestedTargetEntityInstances);
+
+ for (JsonNode targetEntityInstance : nestedTargetEntityInstances) {
+
+ if (cerDescriptor != null) {
+
+ String childEntityType = cerDefinition.getTargetEntityType();
+ OxmEntityDescriptor childDesciptor = oxmEntityLookup.getEntityDescriptors().get(childEntityType);
+
+ List<String> childPrimaryKeyNames = null;
+
+ if (childDesciptor != null) {
+ childPrimaryKeyNames = childDesciptor.getPrimaryKeyAttributeNames();
+ } else {
+ childPrimaryKeyNames = new ArrayList<String>();
+ }
+
+ List<String> childKeyValues = new ArrayList<String>();
+ NodeUtils.extractFieldValuesFromObject(targetEntityInstance, childPrimaryKeyNames, childKeyValues);
+
+ String childEntityQueryKeyString = childEntityType + "." + NodeUtils.concatArray(childPrimaryKeyNames,"/") + ":" + NodeUtils.concatArray(childKeyValues);
+
+ /**
+ * Build generic-query to query child instance self-link from AAI
+ */
+ List<String> orderedQueryKeyParams = new ArrayList<String>();
+
+ /**
+ * At present, there is an issue with resolving the self-link using the
+ * generic-query with nothing more than the service-instance identifier and the
+ * service-subscription. There is another level of detail we don't have access to
+ * unless we parse it out of the service-subscription self-link, which is a
+ * coupling I would like to avoid. Fortunately, there is a workaround, but only
+ * for service-instances, which is presently our only use-case for the
+ * cross-entity-reference in R1707. Going forwards hopefully there will be other
+ * ways to resolve a child self-link using parental embedded meta data that we
+ * don't currently have.
+ *
+ * The work-around with the service-instance entity-type is that it's possible to
+ * request the self-link using only the service-instance-id because of a
+ * historical AAI functional query requirement that it be possible to query a
+ * service-instance only by it's service-instance-id. This entity type is the only
+ * one in the system that can be queried this way which makes it a very limited
+ * workaround, but good enough for the current release.
+ */
+
+ if (SERVICE_INSTANCE.equals(childEntityType)) {
+ orderedQueryKeyParams.clear();
+ orderedQueryKeyParams.add(childEntityQueryKeyString);
+ } else {
+ orderedQueryKeyParams.add(parentEntityQueryString);
+ orderedQueryKeyParams.add(childEntityQueryKeyString);
+ }
+
+ String genericQueryStr = null;
+ try {
+ genericQueryStr = aaiAdapter.getGenericQueryForSelfLink(childEntityType, orderedQueryKeyParams);
+
+ if (genericQueryStr != null) {
+ aaiWorkOnHand.incrementAndGet();
+
+ OperationResult aaiQueryResult = aaiAdapter.queryActiveInventoryWithRetries(
+ genericQueryStr, "application/json",
+ aaiAdapter.getEndpointConfig().getNumRequestRetries());
+
+ aaiWorkOnHand.decrementAndGet();
+
+ if (aaiQueryResult!= null && aaiQueryResult.wasSuccessful()) {
+
+ Collection<JsonNode> entityLinks = new ArrayList<JsonNode>();
+ JsonNode genericQueryResult = null;
+ try {
+ genericQueryResult = NodeUtils.convertJsonStrToJsonNode(aaiQueryResult.getResult());
+
+ if ( genericQueryResult != null ) {
+
+ NodeUtils.extractObjectsByKey(genericQueryResult, "resource-link", entityLinks);
+
+ String selfLink = null;
+
+ if (entityLinks.size() != 1) {
+ /**
+ * an ambiguity exists where we can't reliably determine the self
+ * link, this should be a permanent error
+ */
+ LOG.error(AaiUiMsgs.ENTITY_SYNC_FAILED_SELFLINK_AMBIGUITY, String.valueOf(entityLinks.size()));
+ } else {
+ selfLink = ((JsonNode) entityLinks.toArray()[0]).asText();
+
+
+ IndexableCrossEntityReference icer =
+ getPopulatedDocument(targetEntityInstance, cerDescriptor);
+
+ for (String parentCrossEntityReferenceAttributeValue : extractedParentEntityAttributeValues) {
+ icer.addCrossEntityReferenceValue(
+ parentCrossEntityReferenceAttributeValue);
+ }
+
+ icer.setLink(ActiveInventoryAdapter.extractResourcePath(selfLink));
+
+ icer.deriveFields();
+
+ String link = null;
+ try {
+ link = elasticSearchAdapter
+ .buildElasticSearchGetDocUrl(getIndexName(), icer.getId());
+ } catch (Exception exc) {
+ LOG.error(AaiUiMsgs.ES_FAILED_TO_CONSTRUCT_QUERY,
+ exc.getLocalizedMessage());
+ }
+
+ if (link != null) {
+ NetworkTransaction n2 = new NetworkTransaction();
+ n2.setLink(link);
+ n2.setEntityType(txn.getEntityType());
+ n2.setDescriptor(txn.getDescriptor());
+ n2.setOperationType(HttpMethod.GET);
+
+ esWorkOnHand.incrementAndGet();
+
+ supplyAsync(
+ new PerformElasticSearchRetrieval(n2, elasticSearchAdapter),
+ esExecutor).whenComplete((result, error) -> {
+
+ esWorkOnHand.decrementAndGet();
+
+ if (error != null) {
+ LOG.error(AaiUiMsgs.ES_RETRIEVAL_FAILED,
+ error.getLocalizedMessage());
+ } else {
+ updateElasticSearchCounters(result);
+ performDocumentUpsert(result, icer);
+ }
+ });
+ }
+
+ }
+ } else {
+ LOG.error(AaiUiMsgs.ENTITY_SYNC_FAILED_DURING_AAI_RESPONSE_CONVERSION);
+ }
+
+ } catch (Exception exc) {
+ LOG.error(AaiUiMsgs.JSON_CONVERSION_ERROR, JsonNode.class.toString(), exc.getLocalizedMessage());
+ }
+
+ } else {
+ String message = "Entity sync failed because AAI query failed with error " + aaiQueryResult.getResult();
+ LOG.error(AaiUiMsgs.ENTITY_SYNC_FAILED_QUERY_ERROR, message);
+ }
+
+ } else {
+ String message = "Entity Sync failed because generic query str could not be determined.";
+ LOG.error(AaiUiMsgs.ENTITY_SYNC_FAILED_QUERY_ERROR, message);
+ }
+ } catch (Exception exc) {
+ String message = "Failed to sync entity because generation of generic query failed with error = " + exc.getMessage();
+ LOG.error(AaiUiMsgs.ENTITY_SYNC_FAILED_QUERY_ERROR, message);
+ }
+
+ }
+ }
+
+ } catch (IOException ioe) {
+ LOG.error(AaiUiMsgs.JSON_PROCESSING_ERROR, ioe.getMessage());
+ }
+ }
+
+ }
+
+ } else {
+ LOG.error(AaiUiMsgs.ENTITY_SYNC_FAILED_DESCRIPTOR_NOT_FOUND, txn.getEntityType());
+ }
+ }
+
+ /**
+ * Perform document upsert.
+ *
+ * @param esGetResult the es get result
+ * @param icer the icer
+ */
+ protected void performDocumentUpsert(NetworkTransaction esGetResult,
+ IndexableCrossEntityReference icer) {
+ /**
+ * <p>
+ * <ul>
+ * As part of the response processing we need to do the following:
+ * <li>1. Extract the version (if present), it will be the ETAG when we use the
+ * Search-Abstraction-Service
+ * <li>2. Spawn next task which is to do the PUT operation into elastic with or with the version
+ * tag
+ * <li>a) if version is null or RC=404, then standard put, no _update with version tag
+ * <li>b) if version != null, do PUT with _update?version= (versionNumber) in the URI to elastic
+ * </ul>
+ * </p>
+ */
+ String link = null;
+ try {
+ link = elasticSearchAdapter.buildElasticSearchGetDocUrl(getIndexName(), icer.getId());
+ } catch (Exception exc) {
+ LOG.error(AaiUiMsgs.ES_LINK_UPSERT, exc.getLocalizedMessage());
+ return;
+ }
+
+ boolean wasEntryDiscovered = false;
+ String versionNumber = null;
+ if (esGetResult.getOperationResult().getResultCode() == 404) {
+ LOG.info(AaiUiMsgs.ES_SIMPLE_PUT, icer.getEntityPrimaryKeyValue());
+ } else if (esGetResult.getOperationResult().getResultCode() == 200) {
+ wasEntryDiscovered = true;
+ try {
+ versionNumber = NodeUtils.extractFieldValueFromObject(
+ NodeUtils.convertJsonStrToJsonNode(esGetResult.getOperationResult().getResult()),
+ "_version");
+ } catch (IOException exc) {
+ LOG.error(AaiUiMsgs.ES_ABORT_CROSS_ENTITY_REF_SYNC, "version Number",
+ icer.getEntityPrimaryKeyValue(), exc.getLocalizedMessage());
+ return;
+ }
+ } else {
+ /*
+ * Not being a 200 does not mean a failure. eg 201 is returned for created. TODO -> Should we
+ * return.
+ */
+ LOG.info(AaiUiMsgs.ES_OPERATION_RETURN_CODE,
+ String.valueOf(esGetResult.getOperationResult().getResultCode()));
+ return;
+ }
+
+ try {
+ String jsonPayload = null;
+ if (wasEntryDiscovered) {
+ try {
+ ArrayList<JsonNode> sourceObject = new ArrayList<JsonNode>();
+ NodeUtils.extractObjectsByKey(
+ NodeUtils.convertJsonStrToJsonNode(esGetResult.getOperationResult().getResult()),
+ "_source", sourceObject);
+
+ if (!sourceObject.isEmpty()) {
+ String responseSource = NodeUtils.convertObjectToJson(sourceObject.get(0), false);
+ MergableEntity me = mapper.readValue(responseSource, MergableEntity.class);
+ ObjectReader updater = mapper.readerForUpdating(me);
+ MergableEntity merged = updater.readValue(icer.getAsJson());
+ jsonPayload = mapper.writeValueAsString(merged);
+ }
+ } catch (IOException exc) {
+ LOG.error(AaiUiMsgs.ES_ABORT_CROSS_ENTITY_REF_SYNC, "source value",
+ icer.getEntityPrimaryKeyValue(), exc.getLocalizedMessage());
+ return;
+ }
+ } else {
+ jsonPayload = icer.getAsJson();
+ }
+
+ if (wasEntryDiscovered) {
+ if (versionNumber != null && jsonPayload != null) {
+
+ String requestPayload = elasticSearchAdapter.buildBulkImportOperationRequest(getIndexName(),
+ "default", icer.getId(), versionNumber, jsonPayload);
+
+ NetworkTransaction transactionTracker = new NetworkTransaction();
+ transactionTracker.setEntityType(esGetResult.getEntityType());
+ transactionTracker.setDescriptor(esGetResult.getDescriptor());
+ transactionTracker.setOperationType(HttpMethod.PUT);
+
+ esWorkOnHand.incrementAndGet();
+ supplyAsync(new PerformElasticSearchUpdate(elasticSearchAdapter.getBulkUrl(),
+ requestPayload, elasticSearchAdapter, transactionTracker), esPutExecutor)
+ .whenComplete((result, error) -> {
+
+ esWorkOnHand.decrementAndGet();
+
+ if (error != null) {
+ LOG.error(AaiUiMsgs.ES_CROSS_ENTITY_REF_PUT, error.getLocalizedMessage());
+ } else {
+ updateElasticSearchCounters(result);
+ processStoreDocumentResult(result, esGetResult, icer);
+ }
+ });
+ }
+
+ } else {
+ if (link != null && jsonPayload != null) {
+
+ NetworkTransaction updateElasticTxn = new NetworkTransaction();
+ updateElasticTxn.setLink(link);
+ updateElasticTxn.setEntityType(esGetResult.getEntityType());
+ updateElasticTxn.setDescriptor(esGetResult.getDescriptor());
+ updateElasticTxn.setOperationType(HttpMethod.PUT);
+
+ esWorkOnHand.incrementAndGet();
+ supplyAsync(new PerformElasticSearchPut(jsonPayload, updateElasticTxn, elasticSearchAdapter),
+ esPutExecutor).whenComplete((result, error) -> {
+
+ esWorkOnHand.decrementAndGet();
+
+ if (error != null) {
+ LOG.error(AaiUiMsgs.ES_CROSS_ENTITY_REF_PUT, error.getLocalizedMessage());
+ } else {
+ updateElasticSearchCounters(result);
+ processStoreDocumentResult(result, esGetResult, icer);
+ }
+ });
+ }
+ }
+ } catch (Exception exc) {
+ LOG.error(AaiUiMsgs.ES_CROSS_ENTITY_REF_PUT, exc.getLocalizedMessage());
+ }
+ }
+
+ /**
+ * Process store document result.
+ *
+ * @param esPutResult the es put result
+ * @param esGetResult the es get result
+ * @param icer the icer
+ */
+ private void processStoreDocumentResult(NetworkTransaction esPutResult,
+ NetworkTransaction esGetResult, IndexableCrossEntityReference icer) {
+
+ OperationResult or = esPutResult.getOperationResult();
+
+ if (!or.wasSuccessful()) {
+ if (or.getResultCode() == VERSION_CONFLICT_EXCEPTION_CODE) {
+
+ if (shouldAllowRetry(icer.getId())) {
+
+ esWorkOnHand.incrementAndGet();
+
+ RetryCrossEntitySyncContainer rsc = new RetryCrossEntitySyncContainer(esGetResult, icer);
+ retryQueue.push(rsc);
+
+ LOG.warn(AaiUiMsgs.ES_CROSS_REF_SYNC_VERSION_CONFLICT);
+ }
+ } else {
+ LOG.error(AaiUiMsgs.ES_CROSS_REF_SYNC_FAILURE, String.valueOf(or.getResultCode()),
+ or.getResult());
+ }
+ }
+ }
+
+ /**
+ * Perform retry sync.
+ */
+ private void performRetrySync() {
+ while (retryQueue.peek() != null) {
+
+ RetryCrossEntitySyncContainer rsc = retryQueue.poll();
+ if (rsc != null) {
+
+ IndexableCrossEntityReference icer = rsc.getIndexableCrossEntityReference();
+ NetworkTransaction txn = rsc.getNetworkTransaction();
+
+ String link = null;
+ try {
+ // In this retry flow the icer object has already
+ // derived its fields
+ link = elasticSearchAdapter.buildElasticSearchGetDocUrl(getIndexName(), icer.getId());
+ } catch (Exception exc) {
+ LOG.error(AaiUiMsgs.ES_FAILED_TO_CONSTRUCT_URI, exc.getLocalizedMessage());
+ }
+
+ if (link != null) {
+ NetworkTransaction retryTransaction = new NetworkTransaction();
+ retryTransaction.setLink(link);
+ retryTransaction.setEntityType(txn.getEntityType());
+ retryTransaction.setDescriptor(txn.getDescriptor());
+ retryTransaction.setOperationType(HttpMethod.GET);
+
+ /*
+ * IMPORTANT - DO NOT incrementAndGet the esWorkOnHand as this is a retry flow and we did
+ * that for this request already when queuing the failed PUT!
+ */
+
+ supplyAsync(new PerformElasticSearchRetrieval(retryTransaction, elasticSearchAdapter),
+ esExecutor).whenComplete((result, error) -> {
+
+ esWorkOnHand.decrementAndGet();
+
+ if (error != null) {
+ LOG.error(AaiUiMsgs.ES_RETRIEVAL_FAILED_RESYNC, error.getLocalizedMessage());
+ } else {
+ updateElasticSearchCounters(result);
+ performDocumentUpsert(result, icer);
+ }
+ });
+ }
+
+ }
+ }
+ }
+
+ /**
+ * Should allow retry.
+ *
+ * @param id the id
+ * @return true, if successful
+ */
+ private boolean shouldAllowRetry(String id) {
+ boolean isRetryAllowed = true;
+ if (retryLimitTracker.get(id) != null) {
+ Integer currentCount = retryLimitTracker.get(id);
+ if (currentCount.intValue() >= RETRY_COUNT_PER_ENTITY_LIMIT.intValue()) {
+ isRetryAllowed = false;
+ LOG.error(AaiUiMsgs.ES_CROSS_ENTITY_RESYNC_LIMIT, id);
+ } else {
+ Integer newCount = new Integer(currentCount.intValue() + 1);
+ retryLimitTracker.put(id, newCount);
+ }
+
+ } else {
+ Integer firstRetryCount = new Integer(1);
+ retryLimitTracker.put(id, firstRetryCount);
+ }
+
+ return isRetryAllowed;
+ }
+
+ /**
+ * Gets the populated document.
+ *
+ * @param entityNode the entity node
+ * @param resultDescriptor the result descriptor
+ * @return the populated document
+ * @throws JsonProcessingException the json processing exception
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ protected IndexableCrossEntityReference getPopulatedDocument(JsonNode entityNode,
+ OxmEntityDescriptor resultDescriptor) throws JsonProcessingException, IOException {
+
+ IndexableCrossEntityReference icer = new IndexableCrossEntityReference();
+
+ icer.setEntityType(resultDescriptor.getEntityName());
+
+ List<String> primaryKeyValues = new ArrayList<String>();
+ String pkeyValue = null;
+
+ for (String keyName : resultDescriptor.getPrimaryKeyAttributeNames()) {
+ pkeyValue = NodeUtils.getNodeFieldAsText(entityNode, keyName);
+ if (pkeyValue != null) {
+ primaryKeyValues.add(pkeyValue);
+ } else {
+ LOG.warn(AaiUiMsgs.ES_PKEYVALUE_NULL, resultDescriptor.getEntityName());
+ }
+ }
+
+ final String primaryCompositeKeyValue = NodeUtils.concatArray(primaryKeyValues, "/");
+ icer.setEntityPrimaryKeyValue(primaryCompositeKeyValue);
+
+ return icer;
+
+ }
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/dal/ActiveInventoryAdapter.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/dal/ActiveInventoryAdapter.java
new file mode 100644
index 0000000..dded79f
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/dal/ActiveInventoryAdapter.java
@@ -0,0 +1,404 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.dal;
+
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URLEncoder;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.NoSuchElementException;
+
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.UriBuilder;
+
+import org.apache.http.client.utils.URIBuilder;
+import org.onap.aai.cl.api.Logger;
+import org.onap.aai.cl.eelf.LoggerFactory;
+import org.onap.aai.restclient.client.OperationResult;
+import org.onap.aai.restclient.client.RestClient;
+import org.onap.aai.restclient.enums.RestAuthenticationMode;
+import org.onap.aai.sparky.config.oxm.OxmEntityDescriptor;
+import org.onap.aai.sparky.config.oxm.OxmEntityLookup;
+import org.onap.aai.sparky.config.oxm.OxmModelLoader;
+import org.onap.aai.sparky.dal.exception.ElasticSearchOperationException;
+import org.onap.aai.sparky.dal.rest.RestClientConstructionException;
+import org.onap.aai.sparky.dal.rest.RestClientFactory;
+import org.onap.aai.sparky.dal.rest.config.RestEndpointConfig;
+import org.onap.aai.sparky.logging.AaiUiMsgs;
+import org.onap.aai.sparky.util.NodeUtils;
+
+/**
+ * The Class ActiveInventoryAdapter.
+ */
+
+public class ActiveInventoryAdapter {
+
+ private static final Logger LOG =
+ LoggerFactory.getInstance().getLogger(ActiveInventoryAdapter.class);
+
+ private static final String HEADER_TRANS_ID = "X-TransactionId";
+ private static final String HEADER_FROM_APP_ID = "X-FromAppId";
+ private static final String HEADER_AUTHORIZATION = "Authorization";
+
+ private static final String HTTP_SCHEME = "http";
+ private static final String HTTPS_SCHEME = "https";
+
+ private static final String TRANSACTION_ID_PREFIX = "txnId-";
+ private static final String UI_APP_NAME = "AAI-UI";
+
+ private OxmModelLoader oxmModelLoader;
+ private OxmEntityLookup oxmEntityLookup;
+ private RestEndpointConfig endpointConfig;
+
+ private RestClient restClient;
+
+ /**
+ * Instantiates a new active inventory adapter.
+ * @throws RestClientConstructionException
+ *
+ */
+
+ public ActiveInventoryAdapter(OxmModelLoader oxmModelLoader, OxmEntityLookup oxmEntityLookup,
+ RestEndpointConfig endpointConfig)
+ throws ElasticSearchOperationException, IOException, RestClientConstructionException {
+
+ this.oxmModelLoader = oxmModelLoader;
+ this.oxmEntityLookup = oxmEntityLookup;
+ this.endpointConfig = endpointConfig;
+ this.restClient = RestClientFactory.buildClient(endpointConfig);
+
+ }
+
+ protected Map<String, List<String>> getMessageHeaders() {
+
+ Map<String, List<String>> headers = new HashMap<String, List<String>>();
+
+ headers.putIfAbsent(HEADER_FROM_APP_ID, new ArrayList<String>());
+ headers.get(HEADER_FROM_APP_ID).add(UI_APP_NAME);
+
+ headers.putIfAbsent(HEADER_TRANS_ID, new ArrayList<String>());
+ headers.get(HEADER_TRANS_ID).add(TRANSACTION_ID_PREFIX + NodeUtils.getRandomTxnId());
+
+ if (endpointConfig.getRestAuthenticationMode() == RestAuthenticationMode.SSL_BASIC) {
+
+ headers.putIfAbsent(HEADER_AUTHORIZATION, new ArrayList<String>());
+ headers.get(HEADER_AUTHORIZATION).add(getBasicAuthenticationCredentials());
+
+ }
+
+ return headers;
+ }
+
+ protected String getBasicAuthenticationCredentials() {
+ String usernameAndPassword = String.join(":", endpointConfig.getBasicAuthUserName(),
+ endpointConfig.getBasicAuthPassword());
+ return "Basic " + java.util.Base64.getEncoder().encodeToString(usernameAndPassword.getBytes());
+ }
+
+ public OxmEntityLookup getOxmEntityLookup() {
+ return oxmEntityLookup;
+ }
+
+ public void setOxmEntityLookup(OxmEntityLookup oxmEntityLookup) {
+ this.oxmEntityLookup = oxmEntityLookup;
+ }
+
+ protected String getResourceBasePath() {
+
+ String versionStr = null;
+ if (oxmModelLoader != null) {
+ versionStr = String.valueOf(oxmModelLoader.getLatestVersionNum());
+ }
+
+ return "/aai/v" + versionStr;
+
+ }
+
+ public static String extractResourcePath(String selflink) {
+ try {
+ return new URI(selflink).getRawPath();
+ } catch (URISyntaxException uriSyntaxException) {
+ LOG.error(AaiUiMsgs.ERROR_EXTRACTING_RESOURCE_PATH_FROM_LINK,
+ uriSyntaxException.getMessage());
+ return selflink;
+ }
+ }
+
+
+ /**
+ * Gets the full url.
+ *
+ * @param resourceUrl the resource url
+ * @return the full url
+ * @throws Exception the exception
+ */
+ private String getFullUrl(String resourceUrl) throws Exception {
+ final String basePath = getResourceBasePath();
+ return String.format("https://%s:%s%s%s", endpointConfig.getEndpointIpAddress(),
+ endpointConfig.getEndpointServerPort(), basePath, resourceUrl);
+ }
+
+ public String getGenericQueryForSelfLink(String startNodeType, List<String> queryParams)
+ throws Exception {
+
+ URIBuilder urlBuilder = new URIBuilder(getFullUrl("/search/generic-query"));
+
+ for (String queryParam : queryParams) {
+ urlBuilder.addParameter("key", queryParam);
+ }
+
+ urlBuilder.addParameter("start-node-type", startNodeType);
+ urlBuilder.addParameter("include", startNodeType);
+
+ final String constructedLink = urlBuilder.toString();
+
+ return constructedLink;
+
+ }
+
+
+ public OperationResult getSelfLinksByEntityType(String entityType) throws Exception {
+
+ /*
+ * For this one, I want to dynamically construct the nodes-query for self-link discovery as a
+ * utility method that will use the OXM model entity data to drive the query as well.
+ */
+
+ if (entityType == null) {
+ throw new NullPointerException(
+ "Failed to getSelfLinksByEntityType() because entityType is null");
+ }
+
+ OxmEntityDescriptor entityDescriptor = oxmEntityLookup.getEntityDescriptors().get(entityType);
+
+ if (entityDescriptor == null) {
+ throw new NoSuchElementException("Failed to getSelfLinksByEntityType() because could"
+ + " not find entity descriptor from OXM with type = " + entityType);
+ }
+
+ String link = null;
+ final String primaryKeyStr =
+ NodeUtils.concatArray(entityDescriptor.getPrimaryKeyAttributeNames(), "/");
+
+ link = getFullUrl("/search/nodes-query?search-node-type=" + entityType + "&filter="
+ + primaryKeyStr + ":EXISTS");
+
+
+ return restClient.get(link, getMessageHeaders(), MediaType.APPLICATION_JSON_TYPE);
+
+ }
+
+ public OperationResult getSelfLinkForEntity(String entityType, String primaryKeyName,
+ String primaryKeyValue) throws Exception {
+
+ if (entityType == null) {
+ throw new NullPointerException("Failed to getSelfLinkForEntity() because entityType is null");
+ }
+
+ if (primaryKeyName == null) {
+ throw new NullPointerException(
+ "Failed to getSelfLinkForEntity() because primaryKeyName is null");
+ }
+
+ if (primaryKeyValue == null) {
+ throw new NullPointerException(
+ "Failed to getSelfLinkForEntity() because primaryKeyValue is null");
+ }
+
+ /*
+ * Try to protect ourselves from illegal URI formatting exceptions caused by characters that
+ * aren't natively supported in a URI, but can be escaped to make them legal.
+ */
+
+ String encodedEntityType = URLEncoder.encode(entityType, "UTF-8");
+ String encodedPrimaryKeyName = URLEncoder.encode(primaryKeyName, "UTF-8");
+ String encodedPrimaryKeyValue = URLEncoder.encode(primaryKeyValue, "UTF-8");
+
+ String link = null;
+
+ if ("service-instance".equals(entityType)) {
+
+ link = getFullUrl("/search/generic-query?key=" + encodedEntityType + "."
+ + encodedPrimaryKeyName + ":" + encodedPrimaryKeyValue + "&start-node-type="
+ + encodedEntityType + "&include=customer&depth=2");
+
+ } else {
+
+ link =
+ getFullUrl("/search/generic-query?key=" + encodedEntityType + "." + encodedPrimaryKeyName
+ + ":" + encodedPrimaryKeyValue + "&start-node-type=" + encodedEntityType);
+
+ }
+
+ return queryActiveInventoryWithRetries(link, "application/json",
+ endpointConfig.getNumRequestRetries());
+
+ }
+
+
+ /**
+ * Our retry conditions should be very specific.
+ *
+ * @param r the r
+ * @return true, if successful
+ */
+ private boolean shouldRetryRequest(OperationResult r) {
+
+ if (r == null) {
+ return true;
+ }
+
+ int rc = r.getResultCode();
+
+ if (rc == 200) {
+ return false;
+ }
+
+ if (rc == 404) {
+ return false;
+ }
+
+ return true;
+
+ }
+
+ /**
+ * Query active inventory.
+ *
+ * @param url the url
+ * @param acceptContentType the accept content type
+ * @return the operation result
+ */
+ // package protected for test classes instead of private
+ OperationResult queryActiveInventory(String url, String acceptContentType) {
+
+ return restClient.get(url, getMessageHeaders(), MediaType.APPLICATION_JSON_TYPE);
+
+ }
+
+ public RestEndpointConfig getEndpointConfig() {
+ return endpointConfig;
+ }
+
+ public void setEndpointConfig(RestEndpointConfig endpointConfig) {
+ this.endpointConfig = endpointConfig;
+ }
+
+ public OperationResult queryActiveInventoryWithRetries(String url, String responseType,
+ int numRetries) {
+
+ OperationResult result = null;
+
+ for (int retryCount = 0; retryCount < numRetries; retryCount++) {
+
+ LOG.debug(AaiUiMsgs.QUERY_AAI_RETRY_SEQ, url, String.valueOf(retryCount + 1));
+
+ result = queryActiveInventory(url, responseType);
+
+ /**
+ * Record number of times we have attempted the request to later summarize how many times we
+ * are generally retrying over thousands of messages in a sync.
+ *
+ * If the number of retries is surprisingly high, then we need to understand why that is as
+ * the number of retries is also causing a heavier load on AAI beyond the throttling controls
+ * we already have in place in term of the transaction rate controller and number of
+ * parallelized threads per task processor.
+ */
+
+ result.setNumRetries(retryCount);
+
+ if (!shouldRetryRequest(result)) {
+
+ result.setFromCache(false);
+ LOG.debug(AaiUiMsgs.QUERY_AAI_RETRY_DONE_SEQ, url, String.valueOf(retryCount + 1));
+
+ return result;
+ }
+
+ try {
+ /*
+ * Sleep between re-tries to be nice to the target system.
+ */
+ Thread.sleep(50);
+ } catch (InterruptedException exc) {
+ LOG.error(AaiUiMsgs.QUERY_AAI_WAIT_INTERRUPTION, exc.getLocalizedMessage());
+ break;
+ }
+ LOG.error(AaiUiMsgs.QUERY_AAI_RETRY_FAILURE_WITH_SEQ, url, String.valueOf(retryCount + 1));
+
+ }
+
+ LOG.info(AaiUiMsgs.QUERY_AAI_RETRY_MAXED_OUT, url);
+
+ return result;
+
+ }
+
+ public String repairSelfLink(String selfLink) {
+ return repairSelfLink(selfLink, null);
+ }
+
+ /**
+ * This method adds a scheme, host and port (if missing) to the passed-in URI.
+ * If these parts of the URI are already present, they will not be duplicated.
+ *
+ * @param selflink The URI to repair
+ * @param queryParams The query parameters as a single string
+ * @return The corrected URI (i.e. includes a scheme/host/port)
+ */
+ public String repairSelfLink(String selflink, String queryParams) {
+ if (selflink == null) {
+ return selflink;
+ }
+
+ UriBuilder builder = UriBuilder.fromPath(selflink).host(endpointConfig.getEndpointIpAddress())
+ .port(Integer.parseInt(endpointConfig.getEndpointServerPort()));
+
+ switch (endpointConfig.getRestAuthenticationMode()) {
+
+ case SSL_BASIC:
+ case SSL_CERT: {
+ builder.scheme(HTTPS_SCHEME);
+ break;
+ }
+
+ default: {
+ builder.scheme(HTTP_SCHEME);
+ }
+ }
+
+ boolean includeQueryParams = ( (null != queryParams) && (!"".equals(queryParams)) );
+
+ /* builder.build().toString() will encode special characters to hexadecimal pairs prefixed with a '%'
+ so we're adding the query parameters separately, in their UTF-8 representations, so that
+ characters such as '?', '&', etc. remain intact as needed by the synchronizer */
+ return (builder.build().toString() + (includeQueryParams ? queryParams : ""));
+ }
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/dal/ElasticSearchAdapter.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/dal/ElasticSearchAdapter.java
new file mode 100644
index 0000000..3f5a273
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/dal/ElasticSearchAdapter.java
@@ -0,0 +1,157 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.dal;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.ws.rs.core.MediaType;
+
+import org.onap.aai.restclient.client.OperationResult;
+import org.onap.aai.restclient.client.RestClient;
+import org.onap.aai.sparky.dal.rest.RestClientConstructionException;
+import org.onap.aai.sparky.dal.rest.RestClientFactory;
+import org.onap.aai.sparky.dal.rest.config.RestEndpointConfig;
+
+/**
+ * The Class ElasticSearchAdapter.
+
+ */
+public class ElasticSearchAdapter {
+
+ private static final String BULK_IMPORT_INDEX_TEMPLATE =
+ "{\"index\":{\"_index\":\"%s\",\"_type\":\"%s\",\"_id\":\"%s\", \"_version\":\"%s\"}}\n";
+
+ private static final String BULK_API = "_bulk";
+
+ private static final String DEFAULT_TYPE = "default";
+
+ private RestClient restClient;
+ private RestEndpointConfig endpointConfig;
+
+ /**
+ * Instantiates a new elastic search adapter.
+ * @throws RestClientConstructionException
+ */
+ public ElasticSearchAdapter(RestEndpointConfig endpointConfig) throws RestClientConstructionException {
+
+ this.restClient = RestClientFactory.buildClient(endpointConfig);
+ this.endpointConfig = endpointConfig;
+
+ }
+
+ protected Map<String, List<String>> getMessageHeaders() {
+ Map<String, List<String>> headers = new HashMap<String, List<String>>();
+ // insert mandatory headers if there are any
+ return headers;
+ }
+
+ public OperationResult doGet(String url, MediaType acceptContentType) {
+ return restClient.get(url, getMessageHeaders(), acceptContentType);
+ }
+
+ public OperationResult doDelete(String url, MediaType acceptContentType) {
+ return restClient.delete(url, getMessageHeaders(), acceptContentType);
+ }
+
+ public OperationResult doPost(String url, String jsonPayload, MediaType acceptContentType) {
+ return restClient.post(url, jsonPayload, getMessageHeaders(), MediaType.APPLICATION_JSON_TYPE,
+ acceptContentType);
+ }
+
+ public OperationResult doPut(String url, String jsonPayload, MediaType acceptContentType) {
+ return restClient.put(url, jsonPayload, getMessageHeaders(), MediaType.APPLICATION_JSON_TYPE,
+ acceptContentType);
+ }
+
+ public OperationResult doPatch(String url, String jsonPayload, MediaType acceptContentType) {
+
+ Map<String,List<String>> headers = getMessageHeaders();
+ headers.putIfAbsent("X-HTTP-Method-Override", new ArrayList<String>());
+ headers.get("X-HTTP-Method-Override").add("PATCH");
+
+ return restClient.post(url, jsonPayload, headers, MediaType.APPLICATION_JSON_TYPE, acceptContentType);
+ }
+
+ public OperationResult doHead(String url, MediaType acceptContentType) {
+ return restClient.head(url, getMessageHeaders(), acceptContentType);
+ }
+
+ public OperationResult doBulkOperation(String url, String payload) {
+ return restClient.put(url, payload, getMessageHeaders(),
+ MediaType.APPLICATION_FORM_URLENCODED_TYPE, MediaType.APPLICATION_JSON_TYPE);
+ }
+
+ public String buildBulkImportOperationRequest(String index, String type, String id,
+ String version, String payload) {
+
+ StringBuilder requestPayload = new StringBuilder(128);
+
+ requestPayload.append(String.format(BULK_IMPORT_INDEX_TEMPLATE, index, type, id, version));
+ requestPayload.append(payload).append("\n");
+
+ return requestPayload.toString();
+
+ }
+
+ public OperationResult retrieveEntityById(String host, String port, String indexName,
+ String docType, String resourceUrl) {
+ String esUrl =
+ String.format("http://%s:%s/%s/%s/%s", host, port, indexName, docType, resourceUrl);
+ return doGet(esUrl, MediaType.APPLICATION_JSON_TYPE);
+ }
+
+ public String buildElasticSearchUrlForApi(String indexName, String api) {
+ return String.format("http://%s:%s/%s/%s", endpointConfig.getEndpointIpAddress(),
+ endpointConfig.getEndpointServerPort(), indexName, api);
+ }
+
+ public String buildElasticSearchUrl(String indexName, String docType) {
+ return String.format("http://%s:%s/%s/%s", endpointConfig.getEndpointIpAddress(),
+ endpointConfig.getEndpointServerPort(), indexName, docType);
+ }
+
+ public String buildElasticSearchGetDocUrl(String indexName, String docType, String docId) {
+ return String.format("http://%s:%s/%s/%s/%s", endpointConfig.getEndpointIpAddress(),
+ endpointConfig.getEndpointServerPort(), indexName, docType, docId);
+ }
+
+ public String buildElasticSearchGetDocUrl(String indexName, String docId) {
+ return buildElasticSearchGetDocUrl(indexName, DEFAULT_TYPE, docId);
+ }
+
+ public String buildElasticSearchPostUrl(String indexName) {
+ return String.format("http://%s:%s/%s/%s", endpointConfig.getEndpointIpAddress(),
+ endpointConfig.getEndpointServerPort(), indexName, DEFAULT_TYPE);
+ }
+
+ public String getBulkUrl() {
+ return String.format("http://%s:%s/%s", endpointConfig.getEndpointIpAddress(),
+ endpointConfig.getEndpointServerPort(), BULK_API);
+ }
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/dal/GizmoAdapter.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/dal/GizmoAdapter.java
new file mode 100644
index 0000000..4ceb0d6
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/dal/GizmoAdapter.java
@@ -0,0 +1,336 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.dal;
+
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.UriBuilder;
+
+import org.onap.aai.cl.api.Logger;
+import org.onap.aai.cl.eelf.LoggerFactory;
+import org.onap.aai.restclient.client.OperationResult;
+import org.onap.aai.restclient.client.RestClient;
+import org.onap.aai.restclient.enums.RestAuthenticationMode;
+import org.onap.aai.sparky.config.oxm.OxmModelLoader;
+import org.onap.aai.sparky.dal.exception.ElasticSearchOperationException;
+import org.onap.aai.sparky.dal.rest.RestClientConstructionException;
+import org.onap.aai.sparky.dal.rest.RestClientFactory;
+import org.onap.aai.sparky.dal.rest.config.RestEndpointConfig;
+import org.onap.aai.sparky.logging.AaiUiMsgs;
+import org.onap.aai.sparky.util.NodeUtils;
+
+/**
+ * The Class GizmoAdapter.
+ */
+
+public class GizmoAdapter {
+
+ private static final Logger LOG = LoggerFactory.getInstance().getLogger(GizmoAdapter.class);
+
+ private static final String HEADER_TRANS_ID = "X-TransactionId";
+ private static final String HEADER_FROM_APP_ID = "X-FromAppId";
+ private static final String HEADER_AUTHORIZATION = "Authorization";
+
+ private static final String HTTP_SCHEME = "http";
+ private static final String HTTPS_SCHEME = "https";
+
+ private static final String TRANSACTION_ID_PREFIX = "txnId-";
+ private static final String UI_APP_NAME = "AAI-UI";
+
+ private OxmModelLoader oxmModelLoader;
+
+ private RestEndpointConfig endpointConfig;
+
+ private RestClient restClient;
+
+ private String inventoryBasePath;
+ private String relationshipsBasePath;
+
+ /**
+ * Instantiates a new active inventory adapter.
+ *
+ * @throws RestClientConstructionException
+ *
+ */
+
+ public GizmoAdapter(OxmModelLoader oxmModelLoader, RestEndpointConfig endpointConfig)
+ throws ElasticSearchOperationException, IOException, RestClientConstructionException {
+
+ this.oxmModelLoader = oxmModelLoader;
+ this.endpointConfig = endpointConfig;
+ this.restClient = RestClientFactory.buildClient(endpointConfig);
+
+ }
+
+ public String getRelationshipsBasePath() {
+ return relationshipsBasePath;
+ }
+
+ public void setRelationshipsBasePath(String relationshipsBasePath) {
+ this.relationshipsBasePath = relationshipsBasePath;
+ }
+
+ public String getInventoryBasePath() {
+ return inventoryBasePath;
+ }
+
+ public void setInventoryBasePath(String inventoryBasePath) {
+ this.inventoryBasePath = inventoryBasePath;
+ }
+
+ public String getFullInventoryUrl(String resourceUrl) throws Exception {
+ final String host = endpointConfig.getEndpointIpAddress();
+ final String port = endpointConfig.getEndpointServerPort();
+ final String basePath = getInventoryBasePath();
+ return String.format("https://%s:%s%s%s", host, port, basePath, resourceUrl);
+ }
+
+ public String addServerDetailsToUrl(String resourceUrl) throws Exception {
+ final String host = endpointConfig.getEndpointIpAddress();
+ final String port = endpointConfig.getEndpointServerPort();
+ return String.format("https://%s:%s/%s", host, port, resourceUrl);
+ }
+
+ public String getFullRelationshipUrl(String resourceUrl) throws Exception {
+ final String host = endpointConfig.getEndpointIpAddress();
+ final String port = endpointConfig.getEndpointServerPort();
+ final String basePath = getRelationshipsBasePath();
+ return String.format("https://%s:%s%s%s", host, port, basePath, resourceUrl);
+ }
+
+ protected Map<String, List<String>> getMessageHeaders() {
+
+ Map<String, List<String>> headers = new HashMap<String, List<String>>();
+
+ headers.putIfAbsent(HEADER_FROM_APP_ID, new ArrayList<String>());
+ headers.get(HEADER_FROM_APP_ID).add(UI_APP_NAME);
+
+ headers.putIfAbsent(HEADER_TRANS_ID, new ArrayList<String>());
+ headers.get(HEADER_TRANS_ID).add(TRANSACTION_ID_PREFIX + NodeUtils.getRandomTxnId());
+
+ if (endpointConfig.getRestAuthenticationMode() == RestAuthenticationMode.SSL_BASIC) {
+
+ headers.putIfAbsent(HEADER_AUTHORIZATION, new ArrayList<String>());
+ headers.get(HEADER_AUTHORIZATION).add(getBasicAuthenticationCredentials());
+
+ }
+
+ return headers;
+ }
+
+ protected String getBasicAuthenticationCredentials() {
+ String usernameAndPassword = String.join(":", endpointConfig.getBasicAuthUserName(),
+ endpointConfig.getBasicAuthPassword());
+ return "Basic " + java.util.Base64.getEncoder().encodeToString(usernameAndPassword.getBytes());
+ }
+
+ /**
+ * Our retry conditions should be very specific.
+ *
+ * @param r
+ * the r
+ * @return true, if successful
+ */
+ private boolean shouldRetryRequest(OperationResult r) {
+
+ if (r == null) {
+ return true;
+ }
+
+ int rc = r.getResultCode();
+
+ if (rc == 200) {
+ return false;
+ }
+
+ if (rc == 404) {
+ return false;
+ }
+
+ return true;
+
+ }
+
+ /**
+ * Query active inventory.
+ *
+ * @param url
+ * the url
+ * @param acceptContentType
+ * the accept content type
+ * @return the operation result
+ */
+ OperationResult queryGizmo(String url, String acceptContentType) {
+
+ return restClient.get(url, getMessageHeaders(), MediaType.APPLICATION_JSON_TYPE);
+
+ }
+
+ public RestEndpointConfig getEndpointConfig() {
+ return endpointConfig;
+ }
+
+ public void setEndpointConfig(RestEndpointConfig endpointConfig) {
+ this.endpointConfig = endpointConfig;
+ }
+
+ public OperationResult queryGizmoWithRetries(String url, String responseType, int numRetries) {
+
+ OperationResult result = null;
+
+ for (int retryCount = 0; retryCount < numRetries; retryCount++) {
+
+ LOG.debug(AaiUiMsgs.QUERY_AAI_RETRY_SEQ, url, String.valueOf(retryCount + 1));
+
+ result = queryGizmo(url, responseType);
+
+ /**
+ * Record number of times we have attempted the request to later
+ * summarize how many times we are generally retrying over thousands
+ * of messages in a sync.
+ *
+ * If the number of retries is surprisingly high, then we need to
+ * understand why that is as the number of retries is also causing a
+ * heavier load on AAI beyond the throttling controls we already
+ * have in place in term of the transaction rate controller and
+ * number of parallelized threads per task processor.
+ */
+
+ result.setNumRetries(retryCount);
+
+ if (!shouldRetryRequest(result)) {
+
+ result.setFromCache(false);
+ LOG.debug(AaiUiMsgs.QUERY_AAI_RETRY_DONE_SEQ, url, String.valueOf(retryCount + 1));
+
+ return result;
+ }
+
+ try {
+ /*
+ * Sleep between re-tries to be nice to the target system.
+ */
+ Thread.sleep(50);
+ } catch (InterruptedException exc) {
+ LOG.error(AaiUiMsgs.QUERY_AAI_WAIT_INTERRUPTION, exc.getLocalizedMessage());
+ break;
+ }
+ LOG.error(AaiUiMsgs.QUERY_AAI_RETRY_FAILURE_WITH_SEQ, url, String.valueOf(retryCount + 1));
+
+ }
+
+ LOG.info(AaiUiMsgs.QUERY_AAI_RETRY_MAXED_OUT, url);
+
+ return result;
+
+ }
+
+ /**
+ * This method adds a scheme, host and port (if missing) to the passed-in
+ * URI. If these parts of the URI are already present, they will not be
+ * duplicated.
+ *
+ * @param selflink
+ * The URI to repair
+ * @param queryParams
+ * The query parameters as a single string
+ * @return The corrected URI (i.e. includes a scheme/host/port)
+ */
+
+ private String repairGizmoSelfLink(String baseUrlPath, String selfLink, String queryParams) {
+
+ if (selfLink == null) {
+ return selfLink;
+ }
+
+ if (selfLink.startsWith("http") || selfLink.startsWith("https")) {
+ return selfLink;
+ }
+
+ UriBuilder builder = UriBuilder.fromPath(baseUrlPath + "/" + selfLink)
+ .host(endpointConfig.getEndpointIpAddress())
+ .port(Integer.parseInt(endpointConfig.getEndpointServerPort()));
+
+ switch (endpointConfig.getRestAuthenticationMode()) {
+
+ case SSL_BASIC:
+ case SSL_CERT: {
+ builder.scheme(HTTPS_SCHEME);
+ break;
+ }
+
+ default: {
+ builder.scheme(HTTP_SCHEME);
+ }
+ }
+
+ boolean includeQueryParams = ((null != queryParams) && (!"".equals(queryParams)));
+
+ /*
+ * builder.build().toString() will encode special characters to hexadecimal pairs prefixed with
+ * a '%' so we're adding the query parameters separately, in their UTF-8 representations, so
+ * that characters such as '?', '&', etc. remain intact as needed by the synchronizer
+ */
+ return (builder.build().toString() + (includeQueryParams ? queryParams : ""));
+
+ }
+
+ public String repairRelationshipSelfLink(String selflink, String queryParams) {
+ return repairGizmoSelfLink(relationshipsBasePath, selflink, queryParams);
+ }
+
+ public String repairInventorySelfLink(String selflink, String queryParams) {
+ return repairGizmoSelfLink(inventoryBasePath, selflink, queryParams);
+ }
+
+ public OperationResult getSelfLinksByEntityType(String entityType) throws Exception {
+
+ if (entityType == null) {
+ throw new NullPointerException("Failed to getSelfLinksByEntityType() because entityType is null");
+ }
+
+ String link = getFullInventoryUrl(entityType);
+
+ return queryGizmoWithRetries(link, "application/json", endpointConfig.getNumRequestRetries());
+
+ }
+
+ public static String extractResourcePath(String selflink) {
+ try {
+ return new URI(selflink).getRawPath();
+ } catch (URISyntaxException uriSyntaxException) {
+ LOG.error(AaiUiMsgs.ERROR_EXTRACTING_RESOURCE_PATH_FROM_LINK, uriSyntaxException.getMessage());
+ return selflink;
+ }
+ }
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/dal/NetworkTransaction.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/dal/NetworkTransaction.java
new file mode 100644
index 0000000..0fc4a4e
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/dal/NetworkTransaction.java
@@ -0,0 +1,159 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.dal;
+
+import org.onap.aai.restclient.client.OperationResult;
+import org.onap.aai.sparky.config.oxm.OxmEntityDescriptor;
+import org.onap.aai.sparky.dal.rest.HttpMethod;
+
+
+/**
+ * The Class NetworkTransaction.
+ */
+public class NetworkTransaction {
+
+ private OperationResult operationResult;
+
+ private String entityType;
+
+ private String link;
+
+ private String queryParameters;
+
+ private HttpMethod operationType;
+
+ private OxmEntityDescriptor descriptor;
+
+ private long createdTimeStampInMs;
+
+ private long opTimeInMs;
+
+ private long taskAgeInMs;
+
+ /**
+ * Instantiates a new network transaction.
+ */
+ public NetworkTransaction() {
+ this.createdTimeStampInMs = System.currentTimeMillis();
+ this.opTimeInMs = 0L;
+ }
+
+ /**
+ * Instantiates a new network transaction.
+ *
+ * @param method the method
+ * @param entityType the entity type
+ * @param or the or
+ */
+ public NetworkTransaction(HttpMethod method, String entityType, OperationResult or) {
+ this();
+ this.operationType = method;
+ this.entityType = entityType;
+ this.operationResult = or;
+ this.opTimeInMs = 0L;
+ }
+
+ public HttpMethod getOperationType() {
+ return operationType;
+ }
+
+ public long getTaskAgeInMs() {
+ return taskAgeInMs;
+ }
+
+ /**
+ * Sets the task age in ms.
+ */
+ public void setTaskAgeInMs() {
+ this.taskAgeInMs = (System.currentTimeMillis() - createdTimeStampInMs);
+ }
+
+ public void setOperationType(HttpMethod operationType) {
+ this.operationType = operationType;
+ }
+
+ public OperationResult getOperationResult() {
+ return operationResult;
+ }
+
+ public void setOperationResult(OperationResult operationResult) {
+ this.operationResult = operationResult;
+ }
+
+ public String getEntityType() {
+ return entityType;
+ }
+
+ public void setEntityType(String entityType) {
+ this.entityType = entityType;
+ }
+
+ public String getLink() {
+ return link;
+ }
+
+ public void setLink(String link) {
+ this.link = link;
+ }
+
+ public String getQueryParameters() {
+ return queryParameters;
+ }
+
+ public void setQueryParameters(String queryParameters) {
+ this.queryParameters = queryParameters;
+ }
+
+ public long getOpTimeInMs() {
+ return opTimeInMs;
+ }
+
+ public void setOpTimeInMs(long opTimeInMs) {
+ this.opTimeInMs = opTimeInMs;
+ }
+
+ public OxmEntityDescriptor getDescriptor() {
+ return descriptor;
+ }
+
+ public void setDescriptor(OxmEntityDescriptor descriptor) {
+ this.descriptor = descriptor;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ return "NetworkTransaction [operationResult=" + operationResult.toString() + ", entityType="
+ + entityType + ", link=" + link + ", operationType=" + operationType + ", descriptor="
+ + descriptor.toString() + ", createdTimeStampInMs=" + createdTimeStampInMs
+ + ", taskAgeInMs=" + taskAgeInMs + "]";
+ }
+
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/dal/aai/ActiveInventoryEntityStatistics.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/dal/aai/ActiveInventoryEntityStatistics.java
new file mode 100644
index 0000000..5ec7318
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/dal/aai/ActiveInventoryEntityStatistics.java
@@ -0,0 +1,285 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.dal.aai;
+
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.onap.aai.restclient.client.OperationResult;
+import org.onap.aai.sparky.dal.NetworkTransaction;
+
+
+/**
+ * The Class ActiveInventoryEntityStatistics.
+ */
+public class ActiveInventoryEntityStatistics {
+
+ private static final String TOTAL = "Total";
+
+ private static final String FOUND = "Found";
+
+ private static final String NO_PAYLOAD = "NoPayload";
+
+ private static final String NOT_FOUND = "NotFound";
+
+ private static final String NUM_RETRIES = "NumRetries";
+
+ private static final String ERROR = "Error";
+
+ private Map<String, HashMap<String, AtomicInteger>> activeInventoryEntityStatistics;
+
+ /**
+ * Creates the entity op stats.
+ *
+ * @return the hash map
+ */
+ private HashMap<String, AtomicInteger> createEntityOpStats() {
+
+ HashMap<String, AtomicInteger> opStats = new HashMap<String, AtomicInteger>();
+
+ opStats.put(TOTAL, new AtomicInteger());
+ opStats.put(FOUND, new AtomicInteger());
+ opStats.put(NO_PAYLOAD, new AtomicInteger());
+ opStats.put(NOT_FOUND, new AtomicInteger());
+ opStats.put(NUM_RETRIES, new AtomicInteger());
+ opStats.put(ERROR, new AtomicInteger());
+
+ return opStats;
+
+ }
+
+ /**
+ * Initializecreate active inventory entity statistics.
+ */
+ private void initializecreateActiveInventoryEntityStatistics() {
+ Set<String> keys = activeInventoryEntityStatistics.keySet();
+
+ Set<String> opStatKeySet = null;
+ Map<String, AtomicInteger> opStats = null;
+
+ for (String k : keys) {
+
+ opStats = activeInventoryEntityStatistics.get(k);
+
+ opStatKeySet = opStats.keySet();
+
+ for (String opStatKey : opStatKeySet) {
+ opStats.get(opStatKey).set(0);
+ }
+ }
+ }
+
+ /**
+ * Instantiates a new active inventory entity statistics.
+ *
+ * @param loader the loader
+ */
+ public ActiveInventoryEntityStatistics() {
+ activeInventoryEntityStatistics = new HashMap<String, HashMap<String, AtomicInteger>>();
+ reset();
+ }
+
+ /**
+ * Initialize counters from oxm entity descriptors.
+ *
+ * @param descriptors the descriptors
+ */
+ public void intializeEntityCounters(
+ String... entityTypes) {
+
+ if (entityTypes != null && entityTypes.length > 0) {
+ for (String entityType : entityTypes) {
+ activeInventoryEntityStatistics.put(entityType, createEntityOpStats());
+ }
+
+ }
+
+ }
+
+ public void intializeEntityCounters(
+ Set<String> entityTypes) {
+
+ if (entityTypes != null && entityTypes.size() > 0) {
+ for (String entityType : entityTypes) {
+ activeInventoryEntityStatistics.put(entityType, createEntityOpStats());
+ }
+ }
+
+ }
+
+
+
+ /**
+ * Reset.
+ */
+ public void reset() {
+ initializecreateActiveInventoryEntityStatistics();
+ }
+
+ /**
+ * Gets the result code.
+ *
+ * @param txn the txn
+ * @return the result code
+ */
+ private int getResultCode(NetworkTransaction txn) {
+
+
+ if (txn == null) {
+ return -1;
+ }
+
+ OperationResult or = txn.getOperationResult();
+
+ if (or == null) {
+ return -1;
+ }
+
+ return or.getResultCode();
+
+ }
+
+ /**
+ * Update active inventory entity counters.
+ *
+ * @param txn the txn
+ */
+ private void updateActiveInventoryEntityCounters(NetworkTransaction txn) {
+
+ if (txn == null) {
+ return;
+ }
+
+ Map<String, AtomicInteger> opStats = activeInventoryEntityStatistics.get(txn.getEntityType());
+
+ int rc = getResultCode(txn);
+
+ switch (txn.getOperationType()) {
+
+ case GET: {
+
+ opStats.get(TOTAL).incrementAndGet();
+
+ if (200 <= rc && rc <= 299) {
+ opStats.get(FOUND).incrementAndGet();
+ } else if (rc == 404) {
+ opStats.get(NOT_FOUND).incrementAndGet();
+ } else {
+ opStats.get(ERROR).incrementAndGet();
+ }
+
+ break;
+ }
+
+ default: {
+ // nothing else for now
+ }
+
+ }
+
+ OperationResult or = txn.getOperationResult();
+
+ if (or != null && or.wasSuccessful()) {
+
+ if (or.getResult() == null || or.getResult().length() == 0) {
+ opStats.get(NO_PAYLOAD).incrementAndGet();
+ }
+
+ if (or.getNumRetries() > 0) {
+ opStats.get(NUM_RETRIES).addAndGet(or.getNumRetries());
+ }
+
+ }
+
+
+ }
+
+ /**
+ * Update counters.
+ *
+ * @param txn the txn
+ */
+ public void updateCounters(NetworkTransaction txn) {
+
+ updateActiveInventoryEntityCounters(txn);
+
+ }
+
+ public String getStatisticsReport() {
+
+ StringBuilder sb = new StringBuilder(128);
+
+ /*
+ * sort entities, then sort nested op codes
+ */
+
+ TreeMap<String, HashMap<String, AtomicInteger>> activeInventoryEntitySortedTreeMap =
+ new TreeMap<String, HashMap<String, AtomicInteger>>(new Comparator<String>() {
+
+ @Override
+ public int compare(String o1, String o2) {
+ return o1.toLowerCase().compareTo(o2.toLowerCase());
+ }
+ });
+
+ activeInventoryEntitySortedTreeMap.putAll(activeInventoryEntityStatistics);
+
+ for (String counterEntityKey : activeInventoryEntitySortedTreeMap.keySet()) {
+
+ HashMap<String, AtomicInteger> entityCounters =
+ activeInventoryEntitySortedTreeMap.get(counterEntityKey);
+
+ AtomicInteger total = entityCounters.get(TOTAL);
+ AtomicInteger found = entityCounters.get(FOUND);
+ AtomicInteger noPayload = entityCounters.get(NO_PAYLOAD);
+ AtomicInteger notFound = entityCounters.get(NOT_FOUND);
+ AtomicInteger numRetries = entityCounters.get(NUM_RETRIES);
+ AtomicInteger error = entityCounters.get(ERROR);
+
+ int totalValue = (total == null) ? 0 : total.get();
+ int foundValue = (found == null) ? 0 : found.get();
+ int noPayloadValue = (noPayload == null) ? 0 : noPayload.get();
+ int notFoundValue = (notFound == null) ? 0 : notFound.get();
+ int numRetriesValue = (numRetries == null) ? 0 : numRetries.get();
+ int errorValue = (error == null) ? 0 : error.get();
+
+ sb.append("\n ")
+ .append(String.format(
+ "%-30s TOTAL: %-12d FOUND: %-12d NO_PAYLOAD:"
+ + " %-12d NOT_FOUND: %-12d NUM_RETRIES: %-12d ERROR: %-12d",
+ counterEntityKey, totalValue, foundValue, noPayloadValue, notFoundValue,
+ numRetriesValue, errorValue));
+ }
+
+ return sb.toString();
+ }
+
+
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/dal/aai/ActiveInventoryProcessingExceptionStatistics.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/dal/aai/ActiveInventoryProcessingExceptionStatistics.java
new file mode 100644
index 0000000..b05b12c
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/dal/aai/ActiveInventoryProcessingExceptionStatistics.java
@@ -0,0 +1,139 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.dal.aai;
+
+import org.onap.aai.cl.api.Logger;
+import org.onap.aai.cl.eelf.LoggerFactory;
+import org.onap.aai.restclient.client.OperationResult;
+import org.onap.aai.sparky.analytics.AbstractStatistics;
+import org.onap.aai.sparky.dal.ActiveInventoryAdapter;
+import org.onap.aai.sparky.dal.NetworkTransaction;
+import org.onap.aai.sparky.logging.AaiUiMsgs;
+
+/**
+ * The Class ActiveInventoryProcessingExceptionStatistics.
+ */
+public class ActiveInventoryProcessingExceptionStatistics extends AbstractStatistics {
+
+ private static final Logger LOG =
+ LoggerFactory.getInstance().getLogger(ActiveInventoryAdapter.class);
+
+ private static final String NATIVE_SOCKET_CONNECT_EXCEPTION = "NativeSocketConnectException";
+ private static final String NATIVE_SOCKET_CONNECTION_RESET = "NativeSocketConnectionReset";
+ private static final String NATIVE_SOCKET_CONNECTION_REFUSED = "NativeSocketConnectionRefused";
+ private static final String CLIENT_TIMEOUT_EXCEPTION = "JerseyClientTimoutException";
+ private static final String UNKNOWN_EXCEPTION = "UnknownException";
+
+ /**
+ * Creates the counters.
+ */
+ private void createCounters() {
+ addCounter(NATIVE_SOCKET_CONNECT_EXCEPTION);
+ addCounter(NATIVE_SOCKET_CONNECTION_RESET);
+ addCounter(NATIVE_SOCKET_CONNECTION_REFUSED);
+ addCounter(CLIENT_TIMEOUT_EXCEPTION);
+ addCounter(UNKNOWN_EXCEPTION);
+ }
+
+ /**
+ * Instantiates a new active inventory processing exception statistics.
+ */
+ public ActiveInventoryProcessingExceptionStatistics() {
+ createCounters();
+ reset();
+ }
+
+ /**
+ * Update counters.
+ *
+ * @param txn the txn
+ */
+ public void updateCounters(NetworkTransaction txn) {
+
+ if (txn == null) {
+ return;
+ }
+
+ OperationResult or = txn.getOperationResult();
+
+ if (or != null && !or.wasSuccessful()) {
+
+ if (or.getResultCode() != 404) {
+
+ String result = or.getResult();
+
+ if (result != null) {
+
+ /*
+ * Try to classify exceptions and peg counters
+ */
+
+ if (result.contains("java.net.SocketTimeoutException: connect timed out")) {
+ pegCounter(CLIENT_TIMEOUT_EXCEPTION);
+ } else if (result.contains("java.net.ConnectException: Connection timed out: connect")) {
+ pegCounter(NATIVE_SOCKET_CONNECT_EXCEPTION);
+ } else if (result.contains("java.net.ConnectException: Connection refused: connect")) {
+ pegCounter(NATIVE_SOCKET_CONNECTION_REFUSED);
+ } else if (result.contains("java.net.SocketException: Connection reset")) {
+ pegCounter(NATIVE_SOCKET_CONNECTION_RESET);
+ } else {
+ pegCounter(UNKNOWN_EXCEPTION);
+ LOG.error(AaiUiMsgs.PEGGING_ERROR, result.toString());
+ }
+
+ }
+ }
+
+ }
+
+ }
+
+ public String getStatisticsReport() {
+
+ StringBuilder sb = new StringBuilder(128);
+
+ int nativeConnect = getCounterValue(NATIVE_SOCKET_CONNECT_EXCEPTION);
+ int nativeCxnReset = getCounterValue(NATIVE_SOCKET_CONNECTION_RESET);
+ int nativeCxnRefused = getCounterValue(NATIVE_SOCKET_CONNECTION_REFUSED);
+ int clientTimeout = getCounterValue(CLIENT_TIMEOUT_EXCEPTION);
+ int unknown = getCounterValue(UNKNOWN_EXCEPTION);
+
+ sb.append("\n ")
+ .append(String.format("%-40s: %-12d", NATIVE_SOCKET_CONNECT_EXCEPTION, nativeConnect));
+ sb.append("\n ")
+ .append(String.format("%-40s: %-12d", NATIVE_SOCKET_CONNECTION_RESET, nativeCxnReset));
+ sb.append("\n ")
+ .append(String.format("%-40s: %-12d", NATIVE_SOCKET_CONNECTION_REFUSED, nativeCxnRefused));
+ sb.append("\n ")
+ .append(String.format("%-40s: %-12d", CLIENT_TIMEOUT_EXCEPTION, clientTimeout));
+ sb.append("\n ").append(String.format("%-40s: %-12d", UNKNOWN_EXCEPTION, unknown));
+
+ return sb.toString();
+
+ }
+
+
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/dal/elasticsearch/ElasticSearchEntityStatistics.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/dal/elasticsearch/ElasticSearchEntityStatistics.java
new file mode 100644
index 0000000..0d46c2a
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/dal/elasticsearch/ElasticSearchEntityStatistics.java
@@ -0,0 +1,265 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.dal.elasticsearch;
+
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.onap.aai.restclient.client.OperationResult;
+import org.onap.aai.sparky.dal.NetworkTransaction;
+import org.onap.aai.sparky.dal.rest.HttpMethod;
+
+
+/**
+ * The Class ElasticSearchEntityStatistics.
+ */
+public class ElasticSearchEntityStatistics {
+
+ private static final String TOTAL = "Total";
+ private static final String CREATED = "Created";
+ private static final String MODIFIED = "Modified";
+ private static final String OTHERSUCCESS = "OTHERSUCCESS";
+ private static final String DELETED = "DELETED";
+ private static final String ERROR = "ERROR";
+
+ private Map<String, HashMap<String, AtomicInteger>> entityStatistics;
+
+ /**
+ * Creates the entity op stats.
+ *
+ * @return the hash map
+ */
+ private HashMap<String, AtomicInteger> createEntityOpStats() {
+
+ HashMap<String, AtomicInteger> opStats = new HashMap<String, AtomicInteger>();
+
+ opStats.put(TOTAL, new AtomicInteger());
+ opStats.put(CREATED, new AtomicInteger());
+ opStats.put(MODIFIED, new AtomicInteger());
+ opStats.put(OTHERSUCCESS, new AtomicInteger());
+ opStats.put(DELETED, new AtomicInteger());
+ opStats.put(ERROR, new AtomicInteger());
+
+ return opStats;
+
+ }
+
+ /**
+ * Initializecreate active inventory entity statistics.
+ */
+ private void initializecreateActiveInventoryEntityStatistics() {
+ Set<String> keys = entityStatistics.keySet();
+
+ Set<String> opStatKeySet = null;
+ Map<String, AtomicInteger> opStats = null;
+
+ for (String k : keys) {
+
+ opStats = entityStatistics.get(k);
+
+ opStatKeySet = opStats.keySet();
+
+ for (String opStatKey : opStatKeySet) {
+ opStats.get(opStatKey).set(0);
+ }
+ }
+ }
+
+ /**
+ * Instantiates a new elastic search entity statistics.
+ *
+ * @param loader the loader
+ */
+ public ElasticSearchEntityStatistics() {
+ entityStatistics = new HashMap<String, HashMap<String, AtomicInteger>>();
+ reset();
+ }
+
+ /**
+ * Initialize counters from oxm entity descriptors.
+ *
+ * @param descriptors the descriptors
+ */
+ public void intializeEntityCounters(
+ String... entityTypes) {
+
+ if (entityTypes != null && entityTypes.length > 0) {
+ for (String entityType : entityTypes) {
+ entityStatistics.put(entityType, createEntityOpStats());
+ }
+
+ }
+
+ }
+
+ public void intializeEntityCounters(
+ Set<String> entityTypes) {
+
+ if (entityTypes != null && entityTypes.size() > 0) {
+ for (String entityType : entityTypes) {
+ entityStatistics.put(entityType, createEntityOpStats());
+ }
+ }
+
+ }
+
+ /**
+ * Reset.
+ */
+ public void reset() {
+ initializecreateActiveInventoryEntityStatistics();
+ }
+
+ /**
+ * Gets the result code.
+ *
+ * @param txn the txn
+ * @return the result code
+ */
+ private int getResultCode(NetworkTransaction txn) {
+
+
+ if (txn == null) {
+ return -1;
+ }
+
+ OperationResult or = txn.getOperationResult();
+
+ if (or == null) {
+ return -1;
+ }
+
+ return or.getResultCode();
+
+ }
+
+ /**
+ * Update elastic search entity counters.
+ *
+ * @param txn the txn
+ */
+ private void updateElasticSearchEntityCounters(NetworkTransaction txn) {
+
+ if (txn == null) {
+ return;
+ }
+
+ Map<String, AtomicInteger> entityOpStats = entityStatistics.get(txn.getEntityType());
+
+ int resultCode = getResultCode(txn);
+
+ if (txn.getOperationType() == HttpMethod.PUT) {
+
+ entityOpStats.get(TOTAL).incrementAndGet();
+
+ if (resultCode == 201) {
+ entityOpStats.get(CREATED).incrementAndGet();
+ } else if (resultCode == 200) {
+ entityOpStats.get(MODIFIED).incrementAndGet();
+ } else if (202 <= resultCode && resultCode <= 299) {
+ entityOpStats.get(OTHERSUCCESS).incrementAndGet();
+ } else {
+ entityOpStats.get(ERROR).incrementAndGet();
+ }
+
+ } else if (txn.getOperationType() == HttpMethod.DELETE) {
+
+ entityOpStats.get(TOTAL).incrementAndGet();
+
+ if (200 <= resultCode && resultCode <= 299) {
+ entityOpStats.get(DELETED).incrementAndGet();
+ } else {
+ entityOpStats.get(ERROR).incrementAndGet();
+ }
+ }
+
+ }
+
+ /**
+ * Update counters.
+ *
+ * @param txn the txn
+ */
+ public void updateCounters(NetworkTransaction txn) {
+
+ updateElasticSearchEntityCounters(txn);
+
+ }
+
+ public String getStatisticsReport() {
+
+ StringBuilder sb = new StringBuilder(128);
+
+ /*
+ * sort entities, then sort nested op codes
+ */
+
+ TreeMap<String, HashMap<String, AtomicInteger>> elasticEntitySortedTreeMap =
+ new TreeMap<String, HashMap<String, AtomicInteger>>(new Comparator<String>() {
+
+ @Override
+ public int compare(String o1, String o2) {
+ return o1.toLowerCase().compareTo(o2.toLowerCase());
+ }
+ });
+
+ elasticEntitySortedTreeMap.putAll(entityStatistics);
+
+ for (String counterEntityKey : elasticEntitySortedTreeMap.keySet()) {
+
+ HashMap<String, AtomicInteger> entityCounters =
+ elasticEntitySortedTreeMap.get(counterEntityKey);
+
+ AtomicInteger total = entityCounters.get(TOTAL);
+ AtomicInteger created = entityCounters.get(CREATED);
+ AtomicInteger modified = entityCounters.get(MODIFIED);
+ AtomicInteger otherSuccess = entityCounters.get(OTHERSUCCESS);
+ AtomicInteger deleted = entityCounters.get(DELETED);
+ AtomicInteger error = entityCounters.get(ERROR);
+
+ int totalValue = (total == null) ? 0 : total.get();
+ int createdValue = (created == null) ? 0 : created.get();
+ int modifiedValue = (modified == null) ? 0 : modified.get();
+ int otherSuccessValue = (otherSuccess == null) ? 0 : otherSuccess.get();
+ int deletedValue = (deleted == null) ? 0 : deleted.get();
+ int errorValue = (error == null) ? 0 : error.get();
+
+ sb.append("\n ")
+ .append(String.format(
+ "%-30s TOTAL: %-12d CREATED: %-12d MODIFIED:"
+ + " %-12d OTHER_2XX: %-12d DELETED: %-12d ERROR: %-12d",
+ counterEntityKey, totalValue, createdValue, modifiedValue, otherSuccessValue,
+ deletedValue, errorValue));
+ }
+ return sb.toString();
+ }
+
+
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/dal/exception/ElasticSearchOperationException.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/dal/exception/ElasticSearchOperationException.java
new file mode 100644
index 0000000..5ad7fd0
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/dal/exception/ElasticSearchOperationException.java
@@ -0,0 +1,53 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.dal.exception;
+
+/**
+ * The Class ElasticSearchOperationException.
+ */
+public class ElasticSearchOperationException extends Exception {
+
+ private static final long serialVersionUID = -7689309913743200670L;
+
+ /**
+ * Instantiates a new elastic search operation exception.
+ *
+ * @param message the message
+ * @param exc the exc
+ */
+ public ElasticSearchOperationException(String message, Exception exc) {
+ super(message, exc);
+ }
+
+ /**
+ * Instantiates a new elastic search operation exception.
+ *
+ * @param message the message
+ */
+ public ElasticSearchOperationException(String message) {
+ super(message);
+ }
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/dal/proxy/processor/AaiUiProxyProcessor.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/dal/proxy/processor/AaiUiProxyProcessor.java
new file mode 100644
index 0000000..bae0784
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/dal/proxy/processor/AaiUiProxyProcessor.java
@@ -0,0 +1,207 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.dal.proxy.processor;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.json.Json;
+import javax.json.JsonObjectBuilder;
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.camel.Exchange;
+import org.onap.aai.cl.api.Logger;
+import org.onap.aai.cl.eelf.LoggerFactory;
+import org.onap.aai.cl.mdc.MdcContext;
+import org.onap.aai.restclient.client.OperationResult;
+import org.onap.aai.restclient.client.RestClient;
+import org.onap.aai.restclient.rest.HttpUtil;
+import org.onap.aai.sparky.dal.rest.RestClientConstructionException;
+import org.onap.aai.sparky.dal.rest.RestClientFactory;
+import org.onap.aai.sparky.dal.rest.config.RestEndpointConfig;
+import org.onap.aai.sparky.logging.AaiUiMsgs;
+import org.onap.aai.sparky.util.NodeUtils;
+import org.onap.aai.sparky.viewandinspect.config.SparkyConstants;
+import org.slf4j.MDC;
+
+/**
+ * The Class AaiUiProxyProcessor.
+ */
+public class AaiUiProxyProcessor {
+ private static final Logger LOG =
+ LoggerFactory.getInstance().getLogger(AaiUiProxyProcessor.class);
+ private static Logger auditLogger =
+ LoggerFactory.getInstance().getAuditLogger(AaiUiProxyProcessor.class.getName());
+
+ private RestClient client;
+ private String synapseBaseUrl;
+
+ private OperationResult operationResult = null;
+
+ private String xTransactionId;
+ private String xFromAppId;
+
+ private static final String ROUTER_SERVICE = "routerService";
+
+
+ /**
+ * Instantiates a new AaiUiProxyProcessor.
+ *
+ * @throws RestClientConstructionException
+ */
+
+ public AaiUiProxyProcessor(RestEndpointConfig endpointConfig, String apiGatewayEndpoint)
+ throws RestClientConstructionException {
+ client = RestClientFactory.buildClient(endpointConfig);
+ synapseBaseUrl = "https://" + endpointConfig.getEndpointIpAddress() + ":"
+ + endpointConfig.getEndpointServerPort() + "/" + apiGatewayEndpoint;
+ }
+
+
+ void setUpMdcContext(final Exchange exchange, final HttpServletRequest request) {
+
+ Object xTransactionId = exchange.getIn().getHeader("X-TransactionId");
+ if (xTransactionId == null) {
+ this.xTransactionId = NodeUtils.getRandomTxnId();
+ } else {
+ this.xTransactionId = (String) xTransactionId;
+ }
+
+ Object partnerName = exchange.getIn().getHeader("X-FromAppId");
+ if (partnerName == null) {
+ xFromAppId = "Browser";
+ } else {
+ xFromAppId = (String) partnerName;
+ }
+
+ MdcContext.initialize((String) xTransactionId, "AAI-UI", "", xFromAppId,
+ request.getRequestURI() + ":" + request.getLocalPort());
+ }
+
+ private Map<String, List<String>> getHeaders() {
+ Map<String, List<String>> headers = new HashMap<>();
+ headers.put("X-FromAppId", Arrays.asList(SparkyConstants.APP_NAME));
+ headers.put("X-TransactionId", Arrays.asList(MDC.get(MdcContext.MDC_REQUEST_ID)));
+ headers.put("X-FromAppId", Arrays.asList(MDC.get(MdcContext.MDC_PARTNER_NAME)));
+ return headers;
+ }
+
+ private String getProxyPayloadAsString(final Exchange exchange) {
+ JsonObjectBuilder jsonBuilder = Json.createObjectBuilder();
+ String srcUri = "";
+ try {
+ srcUri = (String) exchange.getIn().getHeader(Exchange.HTTP_URI);
+ jsonBuilder.add("origin-uri", srcUri);
+
+ String body = exchange.getIn().getBody(String.class);
+
+ if (body != null && body.length() != 0) {
+ jsonBuilder.add("origin-payload", body);
+ }
+
+ } catch (Exception e) {
+ LOG.error(AaiUiMsgs.ERROR_GENERIC,
+ "Failed to extract payload for proxying.\n" + "Requestor URL: " + srcUri);
+ }
+
+ return jsonBuilder.build().toString();
+ }
+
+ private String getSynapseUrl(String requestUri) {
+ String url = "";
+ int pos = requestUri.indexOf(ROUTER_SERVICE);
+ if (pos != -1) {
+ url = synapseBaseUrl + requestUri.substring(pos + ROUTER_SERVICE.length());
+ } else {
+ LOG.error(AaiUiMsgs.DR_REQUEST_URI_FOR_PROXY_UNKNOWN, requestUri);
+ }
+ return url;
+ }
+
+ public void proxyMessage(Exchange exchange) {
+ HttpServletRequest request = exchange.getIn().getBody(HttpServletRequest.class);
+
+ setUpMdcContext(exchange, request);
+
+ try {
+ Map<String, List<String>> headers = getHeaders();
+ String proxyPayload = getProxyPayloadAsString(exchange);
+ String fromUrl = (String) exchange.getIn().getHeader(Exchange.HTTP_URI);
+ String toUrl = getSynapseUrl(fromUrl);
+ auditLogger.info(AaiUiMsgs.DR_PROXY_FROM_TO, fromUrl, toUrl);
+ LOG.debug(AaiUiMsgs.DEBUG_GENERIC,
+ "Proxying request:\n" + proxyPayload + "\n" + "Target URL:\n" + toUrl);
+
+ long startTimeInMs = System.currentTimeMillis();
+
+ operationResult = client.post(toUrl, proxyPayload, headers,
+ javax.ws.rs.core.MediaType.APPLICATION_JSON_TYPE,
+ javax.ws.rs.core.MediaType.APPLICATION_JSON_TYPE);
+
+ long drOpTime = (System.currentTimeMillis() - startTimeInMs);
+ int rc = operationResult.getResultCode();
+ String result = "";
+
+ if (HttpUtil.isHttpResponseClassSuccess(rc)) {
+ result = operationResult.getResult();
+ } else {
+ result = operationResult.getFailureCause();
+ LOG.info(AaiUiMsgs.DR_PROCESSING_FAILURE, String.valueOf(rc), proxyPayload);
+ }
+
+ auditLogger.info(AaiUiMsgs.DR_PROCESSING_TIME, String.valueOf(drOpTime));
+
+ exchange.getOut().setHeader("X-TransactionId", xTransactionId);
+ exchange.getOut().setHeader("X-FromAppId", xFromAppId);
+ exchange.getOut().setHeader("RequestUrl", request.getRequestURI());
+ exchange.getOut().setHeader("RequestPort", request.getLocalPort());
+ exchange.getOut().setBody(result);
+ } catch (Exception exc) {
+ LOG.error(AaiUiMsgs.ERROR_PROCESSING_REQUEST, exc);
+ }
+ }
+
+ public String getSynapseBaseUrl() {
+ return synapseBaseUrl;
+ }
+
+ public void setSynapseBaseUrl(String synapseBaseUrl) {
+ this.synapseBaseUrl = synapseBaseUrl;
+ }
+
+ public RestClient getClient() {
+ return client;
+ }
+
+ public void setClient(RestClient client) {
+ this.client = client;
+ }
+
+ protected OperationResult getOperationResult() {
+ return operationResult;
+ }
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/dal/rest/HttpMethod.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/dal/rest/HttpMethod.java
new file mode 100644
index 0000000..a891d20
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/dal/rest/HttpMethod.java
@@ -0,0 +1,33 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.dal.rest;
+
+
+/**
+ * The Enum HttpMethod.
+ */
+public enum HttpMethod {
+ GET, PUT, POST, DELETE, PATCH, HEAD
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/dal/rest/RestClientConstructionException.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/dal/rest/RestClientConstructionException.java
new file mode 100644
index 0000000..830e624
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/dal/rest/RestClientConstructionException.java
@@ -0,0 +1,38 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.dal.rest;
+
+public class RestClientConstructionException extends Exception {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+ public RestClientConstructionException(String message) {
+ super(message);
+ }
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/dal/rest/RestClientFactory.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/dal/rest/RestClientFactory.java
new file mode 100644
index 0000000..30e48b7
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/dal/rest/RestClientFactory.java
@@ -0,0 +1,97 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.dal.rest;
+
+import org.onap.aai.restclient.client.RestClient;
+import org.onap.aai.sparky.config.SparkyResourceLoader;
+import org.onap.aai.sparky.dal.rest.config.RestEndpointConfig;
+import org.onap.aai.sparky.util.Encryptor;
+
+public class RestClientFactory {
+
+ public static RestClient buildClient(RestEndpointConfig restEndpointConfig)
+ throws RestClientConstructionException {
+
+ if (restEndpointConfig == null) {
+ throw new RestClientConstructionException(
+ "Failed to build RestClient because RestEndpointConfig is null.");
+ }
+
+ if (restEndpointConfig.getRestAuthenticationMode() == null) {
+ throw new RestClientConstructionException(
+ "Failed to build RestClient because RestAuthenticationMode is null.");
+ }
+
+ SparkyResourceLoader resourceLoader = restEndpointConfig.getResourceLoader();
+
+ switch (restEndpointConfig.getRestAuthenticationMode()) {
+
+ case SSL_CERT: {
+
+ Encryptor enc = new Encryptor();
+ String certFileNameFullPath = resourceLoader.getAbsolutePath(restEndpointConfig.getCertFileName());
+ String decryptedCertPassword = enc.decryptValue(restEndpointConfig.getCertPassword());
+ String truststoreFileNameFullPath =
+ resourceLoader.getAbsolutePath(restEndpointConfig.getTruststoreFileName());
+
+ return new RestClient() //
+ .authenticationMode(restEndpointConfig.getRestAuthenticationMode()) //
+ .validateServerCertChain(restEndpointConfig.isValidateServerCertChain()) //
+ .validateServerHostname(restEndpointConfig.isValidateServerHostname()) //
+ .clientCertFile(certFileNameFullPath) //
+ .clientCertPassword(decryptedCertPassword) //
+ .trustStore(truststoreFileNameFullPath) //
+ .connectTimeoutMs(restEndpointConfig.getConnectTimeoutInMs()) //
+ .readTimeoutMs(restEndpointConfig.getReadTimeoutInMs());
+ }
+
+ case SSL_BASIC: {
+
+ return new RestClient() //
+ .authenticationMode(restEndpointConfig.getRestAuthenticationMode()) //
+ .basicAuthUsername(restEndpointConfig.getBasicAuthUserName()) //
+ .basicAuthPassword(restEndpointConfig.getBasicAuthPassword()) //
+ .connectTimeoutMs(restEndpointConfig.getConnectTimeoutInMs()) //
+ .readTimeoutMs(restEndpointConfig.getReadTimeoutInMs());
+
+ }
+
+ case HTTP_NOAUTH:
+ case UNKNOWN_MODE:
+ default: {
+
+ return new RestClient() //
+ .authenticationMode(restEndpointConfig.getRestAuthenticationMode()) //
+ .connectTimeoutMs(restEndpointConfig.getConnectTimeoutInMs()) //
+ .readTimeoutMs(restEndpointConfig.getReadTimeoutInMs());
+
+ }
+
+
+ }
+
+ }
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/dal/rest/RestOperationalStatistics.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/dal/rest/RestOperationalStatistics.java
new file mode 100644
index 0000000..dde68b8
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/dal/rest/RestOperationalStatistics.java
@@ -0,0 +1,255 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.dal.rest;
+
+import org.onap.aai.sparky.analytics.AbstractStatistics;
+import org.onap.aai.sparky.dal.NetworkTransaction;
+
+/**
+ * The Class RestOperationalStatistics.
+ */
+public class RestOperationalStatistics extends AbstractStatistics {
+
+ private static final String GET_1XX = "GET_1XX";
+ private static final String GET_2XX = "GET_2XX";
+ private static final String GET_3XX = "GET_3XX";
+ private static final String GET_4XX = "GET_4XX";
+ private static final String GET_5XX = "GET_5XX";
+ private static final String GET_6XX = "GET_6XX";
+
+ private static final String PUT_1XX = "PUT_1XX";
+ private static final String PUT_2XX = "PUT_2XX";
+ private static final String PUT_3XX = "PUT_3XX";
+ private static final String PUT_4XX = "PUT_4XX";
+ private static final String PUT_5XX = "PUT_5XX";
+ private static final String PUT_6XX = "PUT_6XX";
+
+ private static final String POST_1XX = "POST_1XX";
+ private static final String POST_2XX = "POST_2XX";
+ private static final String POST_3XX = "POST_3XX";
+ private static final String POST_4XX = "POST_4XX";
+ private static final String POST_5XX = "POST_5XX";
+ private static final String POST_6XX = "POST_6XX";
+
+ private static final String DELETE_1XX = "DELETE_1XX";
+ private static final String DELETE_2XX = "DELETE_2XX";
+ private static final String DELETE_3XX = "DELETE_3XX";
+ private static final String DELETE_4XX = "DELETE_4XX";
+ private static final String DELETE_5XX = "DELETE_5XX";
+ private static final String DELETE_6XX = "DELETE_6XX";
+
+ /**
+ * Creates the counters.
+ */
+ private void createCounters() {
+
+ addCounter(GET_1XX);
+ addCounter(GET_2XX);
+ addCounter(GET_3XX);
+ addCounter(GET_4XX);
+ addCounter(GET_5XX);
+ addCounter(GET_6XX);
+
+ addCounter(PUT_1XX);
+ addCounter(PUT_2XX);
+ addCounter(PUT_3XX);
+ addCounter(PUT_4XX);
+ addCounter(PUT_5XX);
+ addCounter(PUT_6XX);
+
+ addCounter(POST_1XX);
+ addCounter(POST_2XX);
+ addCounter(POST_3XX);
+ addCounter(POST_4XX);
+ addCounter(POST_5XX);
+ addCounter(POST_6XX);
+
+ addCounter(DELETE_1XX);
+ addCounter(DELETE_2XX);
+ addCounter(DELETE_3XX);
+ addCounter(DELETE_4XX);
+ addCounter(DELETE_5XX);
+ addCounter(DELETE_6XX);
+
+
+ }
+
+ /**
+ * Gets the result code.
+ *
+ * @param txn the txn
+ * @return the result code
+ */
+ private int getResultCode(NetworkTransaction txn) {
+
+ if (txn == null) {
+ return -1;
+ }
+
+ if (txn.getOperationResult() == null) {
+ return -1;
+ }
+
+ return txn.getOperationResult().getResultCode();
+
+ }
+
+ /**
+ * Update counters.
+ *
+ * @param txn the txn
+ */
+ public void updateCounters(NetworkTransaction txn) {
+
+ if (txn == null) {
+ return;
+ }
+
+ int rc = getResultCode(txn);
+
+ switch (txn.getOperationType()) {
+
+ case GET: {
+
+ if (100 <= rc && rc <= 199) {
+ pegCounter(GET_1XX);
+ } else if (200 <= rc && rc <= 299) {
+ pegCounter(GET_2XX);
+ } else if (300 <= rc && rc <= 399) {
+ pegCounter(GET_3XX);
+ } else if (400 <= rc && rc <= 499) {
+ pegCounter(GET_4XX);
+ } else if (500 <= rc && rc <= 599) {
+ pegCounter(GET_5XX);
+ } else if (600 <= rc && rc <= 699) {
+ pegCounter(GET_6XX);
+ }
+
+ break;
+ }
+
+ case PUT: {
+
+ if (100 <= rc && rc <= 199) {
+ pegCounter(PUT_1XX);
+ } else if (200 <= rc && rc <= 299) {
+ pegCounter(PUT_2XX);
+ } else if (300 <= rc && rc <= 399) {
+ pegCounter(PUT_3XX);
+ } else if (400 <= rc && rc <= 499) {
+ pegCounter(PUT_4XX);
+ } else if (500 <= rc && rc <= 599) {
+ pegCounter(PUT_5XX);
+ } else if (600 <= rc && rc <= 699) {
+ pegCounter(PUT_6XX);
+ }
+
+ break;
+ }
+
+ case POST: {
+
+ if (100 <= rc && rc <= 199) {
+ pegCounter(POST_1XX);
+ } else if (200 <= rc && rc <= 299) {
+ pegCounter(POST_2XX);
+ } else if (300 <= rc && rc <= 399) {
+ pegCounter(POST_3XX);
+ } else if (400 <= rc && rc <= 499) {
+ pegCounter(POST_4XX);
+ } else if (500 <= rc && rc <= 599) {
+ pegCounter(POST_5XX);
+ } else if (600 <= rc && rc <= 699) {
+ pegCounter(POST_6XX);
+ }
+
+ break;
+ }
+
+ case DELETE: {
+
+ if (100 <= rc && rc <= 199) {
+ pegCounter(DELETE_1XX);
+ } else if (200 <= rc && rc <= 299) {
+ pegCounter(DELETE_2XX);
+ } else if (300 <= rc && rc <= 399) {
+ pegCounter(DELETE_3XX);
+ } else if (400 <= rc && rc <= 499) {
+ pegCounter(DELETE_4XX);
+ } else if (500 <= rc && rc <= 599) {
+ pegCounter(DELETE_5XX);
+ } else if (600 <= rc && rc <= 699) {
+ pegCounter(DELETE_6XX);
+ }
+
+ break;
+ }
+
+ default: {
+ // not expecting anything else yet
+ }
+
+ }
+
+ }
+
+ /**
+ * Instantiates a new rest operational statistics.
+ */
+ public RestOperationalStatistics() {
+ createCounters();
+ }
+
+ public String getStatisticsReport() {
+
+ StringBuilder sb = new StringBuilder(128);
+
+ sb.append("\n ")
+ .append(String.format(
+ "%-12s 1XX: %-12d 2XX: %-12d 3XX: %-12d 4XX: %-12d 5XX: %-12d 6XX: %-12d ",
+ HttpMethod.DELETE, getCounterValue(DELETE_1XX), getCounterValue(DELETE_2XX),
+ getCounterValue(DELETE_3XX), getCounterValue(DELETE_4XX), getCounterValue(DELETE_5XX),
+ getCounterValue(DELETE_6XX)));
+
+ sb.append("\n ").append(String.format(
+ "%-12s 1XX: %-12d 2XX: %-12d 3XX: %-12d 4XX: %-12d 5XX: %-12d 6XX: %-12d ", HttpMethod.PUT,
+ getCounterValue(PUT_1XX), getCounterValue(PUT_2XX), getCounterValue(PUT_3XX),
+ getCounterValue(PUT_4XX), getCounterValue(PUT_5XX), getCounterValue(PUT_6XX)));
+
+ sb.append("\n ").append(String.format(
+ "%-12s 1XX: %-12d 2XX: %-12d 3XX: %-12d 4XX: %-12d 5XX: %-12d 6XX: %-12d ", HttpMethod.POST,
+ getCounterValue(POST_1XX), getCounterValue(POST_2XX), getCounterValue(POST_3XX),
+ getCounterValue(POST_4XX), getCounterValue(POST_5XX), getCounterValue(POST_6XX)));
+
+ sb.append("\n ").append(String.format(
+ "%-12s 1XX: %-12d 2XX: %-12d 3XX: %-12d 4XX: %-12d 5XX: %-12d 6XX: %-12d ", HttpMethod.GET,
+ getCounterValue(GET_1XX), getCounterValue(GET_2XX), getCounterValue(GET_3XX),
+ getCounterValue(GET_4XX), getCounterValue(GET_5XX), getCounterValue(GET_6XX)));
+
+ return sb.toString();
+ }
+
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/dal/rest/config/RestEndpointConfig.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/dal/rest/config/RestEndpointConfig.java
new file mode 100644
index 0000000..8859f02
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/dal/rest/config/RestEndpointConfig.java
@@ -0,0 +1,179 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.dal.rest.config;
+
+import org.onap.aai.restclient.enums.RestAuthenticationMode;
+import org.onap.aai.sparky.config.SparkyResourceLoader;
+
+public class RestEndpointConfig {
+
+ private String endpointIpAddress;
+ private String endpointServerPort;
+ private int numRequestRetries;
+ private String basicAuthUserName;
+ private String basicAuthPassword;
+ private RestAuthenticationMode restAuthenticationMode;
+ private int connectTimeoutInMs;
+ private int readTimeoutInMs;
+ private String certFileName;
+ private String certPassword;
+ private String truststoreFileName;
+ private boolean validateServerCertChain;
+ private boolean validateServerHostname;
+ private SparkyResourceLoader resourceLoader;
+
+ public boolean isValidateServerCertChain() {
+ return validateServerCertChain;
+ }
+
+ public void setValidateServerCertChain(boolean validateServerCertChain) {
+ this.validateServerCertChain = validateServerCertChain;
+ }
+
+ public boolean isValidateServerHostname() {
+ return validateServerHostname;
+ }
+
+ public void setValidateServerHostname(boolean validateServerHostname) {
+ this.validateServerHostname = validateServerHostname;
+ }
+
+ public String getEndpointIpAddress() {
+ return endpointIpAddress;
+ }
+
+ public void setEndpointIpAddress(String endpointIpAddress) {
+ this.endpointIpAddress = endpointIpAddress;
+ }
+
+ public String getEndpointServerPort() {
+ return endpointServerPort;
+ }
+
+ public void setEndpointServerPort(String endpointServerPort) {
+ this.endpointServerPort = endpointServerPort;
+ }
+
+ public int getNumRequestRetries() {
+ return numRequestRetries;
+ }
+
+ public void setNumRequestRetries(int numRequestRetries) {
+ this.numRequestRetries = numRequestRetries;
+ }
+
+ public String getBasicAuthUserName() {
+ return basicAuthUserName;
+ }
+
+ public void setBasicAuthUserName(String basicAuthUserName) {
+ this.basicAuthUserName = basicAuthUserName;
+ }
+
+ public String getBasicAuthPassword() {
+ return basicAuthPassword;
+ }
+
+ public void setBasicAuthPassword(String basicAuthPassword) {
+ this.basicAuthPassword = basicAuthPassword;
+ }
+
+ public RestAuthenticationMode getRestAuthenticationMode() {
+ return restAuthenticationMode;
+ }
+
+ public void setRestAuthenticationMode(RestAuthenticationMode restAuthenticationMode) {
+ this.restAuthenticationMode = restAuthenticationMode;
+ }
+
+ public int getConnectTimeoutInMs() {
+ return connectTimeoutInMs;
+ }
+
+ public void setConnectTimeoutInMs(int connectTimeoutInMs) {
+ this.connectTimeoutInMs = connectTimeoutInMs;
+ }
+
+ public int getReadTimeoutInMs() {
+ return readTimeoutInMs;
+ }
+
+ public void setReadTimeoutInMs(int readTimeoutInMs) {
+ this.readTimeoutInMs = readTimeoutInMs;
+ }
+
+ public String getCertFileName() {
+ return certFileName;
+ }
+
+ public void setCertFileName(String certFileName) {
+ this.certFileName = certFileName;
+ }
+
+ public String getCertPassword() {
+ return certPassword;
+ }
+
+ public void setCertPassword(String certPassword) {
+ this.certPassword = certPassword;
+ }
+
+ public String getTruststoreFileName() {
+ return truststoreFileName;
+ }
+
+ public void setTruststoreFileName(String truststoreFileName) {
+ this.truststoreFileName = truststoreFileName;
+ }
+
+ public SparkyResourceLoader getResourceLoader() {
+ return resourceLoader;
+ }
+
+ public void setResourceLoader(SparkyResourceLoader resourceLoader) {
+ this.resourceLoader = resourceLoader;
+ }
+
+ @Override
+ public String toString() {
+ return "RestEndpointConfig ["
+ + (endpointIpAddress != null ? "endpointIpAddress=" + endpointIpAddress + ", " : "")
+ + (endpointServerPort != null ? "endpointServerPort=" + endpointServerPort + ", " : "")
+ + "numRequestRetries=" + numRequestRetries + ", "
+ + (basicAuthUserName != null ? "basicAuthUserName=" + basicAuthUserName + ", " : "")
+ + (basicAuthPassword != null ? "basicAuthPassword=" + basicAuthPassword + ", " : "")
+ + (restAuthenticationMode != null
+ ? "restAuthenticationMode=" + restAuthenticationMode + ", " : "")
+ + "connectTimeoutInMs=" + connectTimeoutInMs + ", readTimeoutInMs=" + readTimeoutInMs + ", "
+ + (certFileName != null ? "certFileName=" + certFileName + ", " : "")
+ + (certPassword != null ? "certPassword=" + certPassword + ", " : "")
+ + (truststoreFileName != null ? "truststoreFileName=" + truststoreFileName + ", " : "")
+ + "validateServerCertChain=" + validateServerCertChain + ", validateServerHostname="
+ + validateServerHostname + "]";
+ }
+
+
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/editattributes/AttributeEditProcessor.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/editattributes/AttributeEditProcessor.java
new file mode 100644
index 0000000..8b35d7c
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/editattributes/AttributeEditProcessor.java
@@ -0,0 +1,182 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.editattributes;
+
+import java.io.UnsupportedEncodingException;
+import java.util.Map;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.component.restlet.RestletConstants;
+import org.onap.aai.cl.api.Logger;
+import org.onap.aai.cl.eelf.LoggerFactory;
+import org.onap.aai.cl.mdc.MdcContext;
+import org.onap.aai.restclient.client.OperationResult;
+import org.onap.aai.sparky.editattributes.entity.EditRequest;
+import org.onap.aai.sparky.logging.AaiUiMsgs;
+import org.onap.aai.sparky.util.NodeUtils;
+import org.restlet.Request;
+import org.restlet.Response;
+import org.restlet.data.ClientInfo;
+import org.restlet.data.Cookie;
+import org.restlet.data.MediaType;
+import org.restlet.data.Status;
+import org.restlet.util.Series;
+
+import com.fasterxml.jackson.annotation.JsonInclude.Include;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+/**
+ * The Class AttributeEditProcessor.
+ */
+public class AttributeEditProcessor {
+
+ private static final Logger LOG =
+ LoggerFactory.getInstance().getLogger(AttributeEditProcessor.class);
+
+ private ObjectMapper mapper;
+ private AttributeUpdater attrUpdater;
+
+ public AttributeEditProcessor(AttributeUpdater attributeUpdater) {
+ this.attrUpdater = attributeUpdater;
+
+ this.mapper = new ObjectMapper();
+ mapper.setSerializationInclusion(Include.NON_EMPTY);
+ }
+
+ public void editAttribute(Exchange exchange) {
+
+ Object xTransactionId = exchange.getIn().getHeader("X-TransactionId");
+
+ if (xTransactionId == null) {
+ xTransactionId = NodeUtils.getRandomTxnId();
+ }
+
+ Object partnerName = exchange.getIn().getHeader("X-FromAppId");
+ if (partnerName == null) {
+ partnerName = "Browser";
+ }
+
+ Request request = exchange.getIn().getHeader(RestletConstants.RESTLET_REQUEST, Request.class);
+
+ /*
+ * Disables automatic Apache Camel Restlet component logging which prints out an undesirable log
+ * entry which includes client (e.g. browser) information
+ */
+ request.setLoggable(false);
+
+ ClientInfo clientInfo = request.getClientInfo();
+ MdcContext.initialize((String) xTransactionId, "AAI-UI", "", (String) partnerName,
+ clientInfo.getAddress() + ":" + clientInfo.getPort());
+
+ String payload = exchange.getIn().getBody(String.class);
+ EditRequest editRequest = null;
+ OperationResult operationResult = new OperationResult();
+
+ Response response = exchange.getIn().getHeader(RestletConstants.RESTLET_RESPONSE, Response.class);
+ response.setStatus(Status.SUCCESS_OK); // 200 is assumed unless an actual exception occurs (a failure is still a valid response)
+
+ boolean wasErrorDuringProcessing = false;
+ String errorMessage = null;
+
+
+ try {
+
+ if (payload != null && !payload.isEmpty()) {
+ editRequest = mapper.readValue(payload, EditRequest.class);
+
+ if (editRequest != null) {
+
+ String attUid = getAttUid(request.getCookies());
+ String objectUri = editRequest.getEntityUri();
+ Map<String, Object> attributeValues = editRequest.getAttributes();
+
+ if (attUid != null && !attUid.isEmpty() && objectUri != null && !objectUri.isEmpty()
+ && attributeValues != null && !attributeValues.isEmpty()) {
+
+ LOG.info(AaiUiMsgs.ATTRIBUTES_HANDLING_EDIT, objectUri, editRequest.toString());
+
+ operationResult = attrUpdater.updateObjectAttribute(objectUri, attributeValues, attUid);
+
+ boolean wasSuccess = (operationResult.getResultCode() == 200);
+ String message = String.format("Edit Attributes completed with Result Code : %s (%s).",
+ operationResult.getResultCode(), wasSuccess ? "success" : "failed");
+
+ LOG.info(AaiUiMsgs.INFO_GENERIC, message);
+ }
+ }
+ } else {
+ wasErrorDuringProcessing = true;
+ errorMessage = "Empty payload provided, need details to complete request";
+ }
+ } catch (Exception exc) {
+ LOG.error(AaiUiMsgs.ATTRIBUTES_NOT_UPDATED_EXCEPTION, exc.getLocalizedMessage());
+ operationResult.setResult(500, "Error encountered while trying to update attributes.");
+ response.setStatus(Status.SERVER_ERROR_INTERNAL);
+ }
+
+ if(wasErrorDuringProcessing) {
+ LOG.error(AaiUiMsgs.ATTRIBUTES_NOT_UPDATED_MESSAGE, errorMessage);
+ }
+
+ response.setEntity(operationResult.getResult(), MediaType.APPLICATION_JSON);
+ exchange.getOut().setBody(response);
+ }
+
+ /**
+ * Gets the att uid.
+ *
+ * @param request the request
+ * @return the att uid
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ */
+ public String getAttUid(Series<Cookie> cookies) throws UnsupportedEncodingException {
+ String attId = "";
+ if (cookies == null) {
+ LOG.error(AaiUiMsgs.COOKIE_NOT_FOUND);
+ return attId;
+ }
+ for (Cookie cookie : cookies) {
+ if (cookie.getName().equals("attESHr")) {
+ // This cookie is of the form :
+ // "FIRSTNAME|LASTNAME|emailname@domain.com|||ab1234||fl6789,RBFMSKQ,"
+ // + "Z9V2298,9762186|YNNNNNNNNNNNNNYNNYYNNNNN|FIRSTNAME|EY6SC9000|"
+ // we are to extract fl6789 from this which would be the attuid for the user.
+ String value = cookie.getValue();
+ value = java.net.URLDecoder.decode(value, "UTF-8");
+ LOG.info(AaiUiMsgs.COOKIE_FOUND, value);
+ String[] values = value.split("\\|");
+ if (values.length > 7) {
+ attId = (values[7].split(","))[0];
+
+ String initials = (values[0].substring(0, 1) + values[1].substring(0, 1)).toLowerCase();
+ if (attId.startsWith(initials)) {
+ return attId;
+ }
+ }
+ }
+ }
+ return attId;
+ }
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/editattributes/AttributeUpdater.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/editattributes/AttributeUpdater.java
new file mode 100644
index 0000000..5d71135
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/editattributes/AttributeUpdater.java
@@ -0,0 +1,362 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.editattributes;
+
+import java.net.URI;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.ws.rs.core.UriBuilder;
+
+import org.eclipse.persistence.dynamic.DynamicType;
+import org.onap.aai.cl.api.Logger;
+import org.onap.aai.cl.eelf.LoggerFactory;
+import org.onap.aai.restclient.client.OperationResult;
+import org.onap.aai.sparky.config.oxm.OxmEntityLookup;
+import org.onap.aai.sparky.config.oxm.OxmModelLoader;
+import org.onap.aai.sparky.dal.ActiveInventoryAdapter;
+import org.onap.aai.sparky.editattributes.exception.AttributeUpdateException;
+import org.onap.aai.sparky.logging.AaiUiMsgs;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.ObjectWriter;
+import com.fasterxml.jackson.databind.PropertyNamingStrategy;
+
+/**
+ * Class to process attribute updates on AAI objects.
+ *
+ *
+ */
+public class AttributeUpdater {
+
+ /**
+ * The Class AaiEditObject.
+ */
+ public class AaiEditObject {
+ String objectType;
+ String rootElement;
+ String keyName;
+ String keyValue;
+ String schemaVersion;
+
+ /**
+ * Instantiates a new aai edit object.
+ */
+ public AaiEditObject() {
+
+ }
+
+ /**
+ * Instantiates a new aai edit object.
+ *
+ * @param objectType the object type
+ * @param idName the id name
+ * @param schemaVersion the schema version
+ */
+ public AaiEditObject(String objectType, String idName, String schemaVersion) {
+ super();
+ this.objectType = objectType;
+ this.keyName = idName;
+ this.schemaVersion = schemaVersion;
+ }
+
+ public String getObjectType() {
+ return objectType;
+ }
+
+ public void setObjectType(String objectType) {
+ this.objectType = objectType;
+ }
+
+ public String getKeyName() {
+ return keyName;
+ }
+
+ public void setKeyName(String idName) {
+ this.keyName = idName;
+ }
+
+ public String getSchemaVersion() {
+ return schemaVersion;
+ }
+
+ public void setSchemaVersion(String schemaVersion) {
+ this.schemaVersion = schemaVersion;
+ }
+
+ public void setKeyValue(String keyValue) {
+ this.keyValue = keyValue;
+ }
+
+ public String getKeyValue() {
+ return keyValue;
+ }
+
+ public String getRootElement() {
+ return rootElement;
+ }
+
+ public void setRootElement(String rootElement) {
+ this.rootElement = rootElement;
+ }
+
+ }
+
+ private static final Logger LOG = LoggerFactory.getInstance().getLogger(AttributeUpdater.class);
+ private static final String MESSAGE_VERSION_EXTRACTION_REGEX = "\\/(v[0-9]+)";
+ private static final String ATTRIBUTES_UPDATED_SUCCESSFULLY = "Attributes updated successfully";
+ private static final String ATTRIBUTES_NOT_UPDATED = "Attributes not updated. ";
+
+ private ActiveInventoryAdapter aaiAdapter;
+ private UserValidator validator;
+ private OxmModelLoader oxmModelLoader;
+ private OxmEntityLookup oxmEntityLookup;
+
+ /**
+ * Instantiates a new attribute updater.
+ * @throws AttributeUpdateException
+ */
+ public AttributeUpdater(OxmModelLoader oxmModelLoader, OxmEntityLookup oxmEntityLookup, ActiveInventoryAdapter activeInventoryAdapter) throws AttributeUpdateException {
+ super();
+ this.oxmModelLoader = oxmModelLoader;
+ this.oxmEntityLookup = oxmEntityLookup;
+ this.aaiAdapter = activeInventoryAdapter;
+
+ try {
+ this.validator = new UserValidator();
+ } catch (Exception exc) {
+ LOG.error(AaiUiMsgs.ATTRIBUTES_ERROR_GETTING_AAI_CONFIG_OR_ADAPTER, exc.getLocalizedMessage());
+ throw new AttributeUpdateException(exc);
+ }
+ }
+
+ protected String getResourceBasePath() {
+
+ String versionStr = null;
+ if (oxmModelLoader != null) {
+ versionStr = String.valueOf(oxmModelLoader.getLatestVersionNum());
+ }
+
+ return "/aai/v" + versionStr;
+
+ }
+
+ protected URI getBaseUri() {
+ return UriBuilder
+ .fromUri("https://" + aaiAdapter.getEndpointConfig().getEndpointIpAddress() + ":"
+ + aaiAdapter.getEndpointConfig().getEndpointServerPort() + getResourceBasePath())
+ .build();
+ }
+
+ /**
+ * Update object attribute.
+ *
+ * @param objectUri - Valid URI of the object as per OXM model.
+ * @param attributeValues - Map of (attribute-name & attribute-value) for
+ * any attributes to be updated to the value.
+ * @param attUid - ATTUID of the user requesting the update.
+ * @return - OperationResult with success or failure reason.
+ */
+ public OperationResult updateObjectAttribute(String objectUri, Map<String, Object> attributeValues, String attUid) {
+ OperationResult result = new OperationResult();
+ LOG.info(AaiUiMsgs.ATTRIBUTES_UPDATE_METHOD_CALLED, objectUri, attUid, String.valueOf(attributeValues));
+ if (!validator.isAuthorizedUser(attUid)) {
+ result.setResultCode(403);
+ result.setResult(String.format("User %s is not authorized for Attributes update ", attUid));
+ LOG.error(AaiUiMsgs.ATTRIBUTES_USER_NOT_AUTHORIZED_TO_UPDATE, attUid);
+ return result;
+ }
+
+ AaiEditObject object = null;
+
+ try {
+ object = getEditObjectFromUri(objectUri);
+ } catch (AttributeUpdateException exc) {
+ result.setResultCode(400);
+ result.setResult(ATTRIBUTES_NOT_UPDATED);
+ LOG.error(AaiUiMsgs.ATTRIBUTES_NOT_UPDATED_EXCEPTION, exc.getLocalizedMessage());
+ return result;
+ }
+ try {
+ String jsonPayload = convertEditRequestToJson(object, attributeValues);
+ String patchUri = getBaseUri().toString() + getRelativeUri(objectUri);
+
+
+ /*
+ * FIX ME: Dave Adams, 8-Nov-2017
+ */
+
+ //result = aaiAdapter.doPatch(patchUri, jsonPayload, MediaType.APPLICATION_JSON);
+
+ result = new OperationResult();
+ result.setResultCode(404);
+
+ if (result.getResultCode() == 200) {
+ result.setResult(ATTRIBUTES_UPDATED_SUCCESSFULLY);
+ String message = result.getResult() + " for " + objectUri;
+ LOG.info(AaiUiMsgs.INFO_GENERIC, message);
+ } else {
+ String message = ATTRIBUTES_NOT_UPDATED + " For: " + objectUri + ". AAI PATCH Status Code : "
+ + result.getResultCode() + ". Error : " + result.getResult();
+ LOG.error(AaiUiMsgs.ATTRIBUTES_NOT_UPDATED_MESSAGE, message);
+ }
+ } catch (AttributeUpdateException exc) {
+ result.setResultCode(500);
+ result.setResult(ATTRIBUTES_NOT_UPDATED + exc.getLocalizedMessage());
+ LOG.error(AaiUiMsgs.ATTRIBUTES_NOT_UPDATED_EXCEPTION, exc.getLocalizedMessage());
+ }
+ return result;
+
+ }
+
+ /**
+ * Gets the relative uri.
+ *
+ * @param objectUri the object uri
+ * @return the relative uri
+ */
+ public String getRelativeUri(String objectUri) {
+ String tempUri = objectUri;
+ final Pattern pattern = Pattern.compile(MESSAGE_VERSION_EXTRACTION_REGEX, Pattern.DOTALL);
+ Matcher matcher = pattern.matcher(objectUri);
+ while (matcher.find()) {
+ tempUri = objectUri.substring(matcher.end());
+ }
+ if (!tempUri.startsWith("/")) {
+ tempUri = "/" + tempUri;
+ }
+ return tempUri;
+ }
+
+ /**
+ * Gets the edits the object from uri.
+ *
+ * @param objectUri the object uri
+ * @return the edits the object from uri
+ * @throws AttributeUpdateException the attribute update exception
+ */
+ public AaiEditObject getEditObjectFromUri(String objectUri) throws AttributeUpdateException {
+
+ AaiEditObject object = new AaiEditObject();
+ String version = getVersionFromUri(objectUri);
+
+ if ( null == version ) {
+ version = "v" + String.valueOf(oxmModelLoader.getLatestVersionNum());
+ }
+ object.setSchemaVersion(version);
+
+ String[] values = objectUri.split("/");
+ if (values.length < 2) {
+ throw new AttributeUpdateException("Invalid or malformed object URI : " + objectUri);
+ }
+ String keyValue = values[values.length - 1];
+ String rootElement = values[values.length - 2];
+
+ object.setKeyValue(keyValue);
+ object.setRootElement(rootElement);
+
+ String objectJavaType = null;
+ Map<String, DynamicType> entityTypeLookup = oxmEntityLookup.getEntityTypeLookup();
+ DynamicType entity = entityTypeLookup.get(rootElement);
+ if ( null != entity ) {
+ objectJavaType = entity.getName();
+ String message = "Descriptor: Alias: " + objectJavaType + " : DefaultRootElement: "
+ + rootElement;
+ LOG.debug(AaiUiMsgs.DEBUG_GENERIC, message);
+ }
+
+
+ if (objectJavaType == null) {
+ throw new AttributeUpdateException(
+ "Object type could not be determined from the URI : " + objectUri);
+ }
+ object.setObjectType(objectJavaType);
+
+ // Set key attribute name
+ final List<String> primaryKeys = entity.getDescriptor().getPrimaryKeyFieldNames();
+
+ if (primaryKeys.isEmpty()) {
+ throw new AttributeUpdateException("Object primary key not found in OXM version " + version);
+ }
+
+ for (int i = 0; i < primaryKeys.size(); i++) {
+ final String primaryKey = primaryKeys.get(i);
+ if (primaryKey.indexOf("/text()") != -1) {
+ primaryKeys.set(i, primaryKey.replace("/text()", ""));
+ }
+ }
+ object.setKeyName(primaryKeys.iterator().next());
+
+ return object;
+ }
+
+ /**
+ * Gets the version from uri.
+ *
+ * @param objectUri the object uri
+ * @return the version from uri
+ * @throws AttributeUpdateException the attribute update exception
+ */
+ private String getVersionFromUri(String objectUri) throws AttributeUpdateException {
+ final Pattern pattern = Pattern.compile(MESSAGE_VERSION_EXTRACTION_REGEX, Pattern.DOTALL);
+ Matcher matcher = pattern.matcher(objectUri);
+ String messageSchemaVersion = null;
+ while (matcher.find()) {
+ messageSchemaVersion = matcher.group(1);
+ break;
+ }
+ return messageSchemaVersion;
+ }
+
+ /**
+ * Convert edit request to json.
+ *
+ * @param object the object
+ * @param attributeValues the attribute values
+ * @return the string
+ * @throws AttributeUpdateException the attribute update exception
+ */
+ private static String convertEditRequestToJson(AaiEditObject object,
+ Map<String, Object> attributeValues) throws AttributeUpdateException {
+
+ ObjectMapper mapper = new ObjectMapper();
+ mapper.setPropertyNamingStrategy(new PropertyNamingStrategy.KebabCaseStrategy());
+ ObjectWriter ow = mapper.writer();
+
+ Map<String, Object> patchAttributes = new HashMap<>();
+ patchAttributes.put(object.getKeyName(), object.getKeyValue());
+ patchAttributes.putAll(attributeValues);
+
+ try {
+ return ow.writeValueAsString(patchAttributes);
+ } catch (JsonProcessingException exc) {
+ throw new AttributeUpdateException("Caught a JPE while creating PATCH request body = ", exc);
+ }
+ }
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/editattributes/UserAuthorizationReader.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/editattributes/UserAuthorizationReader.java
new file mode 100644
index 0000000..a5c251e
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/editattributes/UserAuthorizationReader.java
@@ -0,0 +1,79 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.editattributes;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+/**
+ * Reads user IDs from a file. Each line in the user authorization file should contain a single user
+ * ID. For example,
+ *
+ * <pre>
+ * user1
+ * user2
+ * </pre>
+ */
+public class UserAuthorizationReader {
+
+ private File userAuthorizationFile;
+
+ /**
+ * Set the user authorization file.
+ *
+ * @param file a user authorization file
+ */
+ public UserAuthorizationReader(File file) {
+ this.userAuthorizationFile = file;
+ }
+
+ /**
+ * Gets user IDs from a file.
+ *
+ * @return a list of user IDs
+ * @throws IOException if there is a problem reading the user configuration file
+ */
+ public List<String> getUsers() throws IOException {
+ List<String> userList = new ArrayList<>();
+ try (Stream<String> stream = Files.lines(getUserAuthorizationFile().toPath())) {
+ userList.addAll(stream.map(String::trim).collect(Collectors.toList()));
+ }
+ return userList;
+ }
+
+ // Getters and setters
+ public File getUserAuthorizationFile() {
+ return userAuthorizationFile;
+ }
+
+ public void setUserAuthorizationFile(File file) {
+ this.userAuthorizationFile = file;
+ }
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/editattributes/UserValidator.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/editattributes/UserValidator.java
new file mode 100644
index 0000000..8999105
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/editattributes/UserValidator.java
@@ -0,0 +1,67 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.editattributes;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+
+import org.onap.aai.cl.api.Logger;
+import org.onap.aai.cl.eelf.LoggerFactory;
+import org.onap.aai.sparky.logging.AaiUiMsgs;
+import org.onap.aai.sparky.viewandinspect.config.SparkyConstants;
+
+/**
+ * Validates users against a user authorization file.
+ */
+public class UserValidator {
+
+ private static final Logger LOG = LoggerFactory.getInstance().getLogger(UserValidator.class);
+ private static final String USER_AUTH_FILE =
+ SparkyConstants.AUTHORIZED_USERS_FILE_LOCATION;
+
+ private UserAuthorizationReader userAuthorizationReader =
+ new UserAuthorizationReader(new File(USER_AUTH_FILE));
+
+ /**
+ * Returns true if the user is authorized.
+ *
+ * @param userId a user identifier
+ * @return true if the user ID is present in the user authorization file
+ */
+ public boolean isAuthorizedUser(String userId) {
+ if (userId != null && !userId.isEmpty()) {
+ try {
+ List<String> users = userAuthorizationReader.getUsers();
+ return users.contains(userId);
+ } catch (IOException exc) {
+ LOG.error(AaiUiMsgs.USER_AUTHORIZATION_FILE_UNAVAILABLE, userId);
+ return false;
+ }
+ } else {
+ return false;
+ }
+ }
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/editattributes/entity/EditRequest.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/editattributes/entity/EditRequest.java
new file mode 100644
index 0000000..0e8ce17
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/editattributes/entity/EditRequest.java
@@ -0,0 +1,69 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.editattributes.entity;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+/**
+ * The Class EditRequest.
+ */
+public class EditRequest {
+
+ @JsonProperty("entity-uri")
+ private String entityUri;
+
+ @JsonProperty("entity-type")
+ private String entityType;
+
+ @JsonProperty("attributes")
+ private Map<String, Object> attributes = new HashMap<>();
+
+ public String getEntityUri() {
+ return entityUri;
+ }
+
+ public void setEntityUri(String entityUri) {
+ this.entityUri = entityUri;
+ }
+
+ public String getEntityType() {
+ return entityType;
+ }
+
+ public void setEntityType(String entityType) {
+ this.entityType = entityType;
+ }
+
+ public Map<String, Object> getAttributes() {
+ return attributes;
+ }
+
+ public void setAttributes(Map<String, Object> attributes) {
+ this.attributes = attributes;
+ }
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/editattributes/exception/AttributeUpdateException.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/editattributes/exception/AttributeUpdateException.java
new file mode 100644
index 0000000..119d680
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/editattributes/exception/AttributeUpdateException.java
@@ -0,0 +1,62 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.editattributes.exception;
+
+/**
+ * The Class AttributeUpdateException.
+ */
+public class AttributeUpdateException extends Exception {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Attribute Edit specific Exception Class.
+ *
+ * @param exc the exc
+ */
+
+ public AttributeUpdateException(Exception exc) {
+ super(exc);
+ }
+
+ /**
+ * Instantiates a new attribute update exception.
+ *
+ * @param message the message
+ */
+ public AttributeUpdateException(String message) {
+ super(message);
+ }
+
+ /**
+ * Instantiates a new attribute update exception.
+ *
+ * @param message the message
+ * @param exc the exc
+ */
+ public AttributeUpdateException(String message, Exception exc) {
+ super(message, exc);
+ }
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/inventory/EntityHistoryQueryBuilder.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/inventory/EntityHistoryQueryBuilder.java
new file mode 100644
index 0000000..a2039b4
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/inventory/EntityHistoryQueryBuilder.java
@@ -0,0 +1,143 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.inventory;
+
+import javax.json.Json;
+import javax.json.JsonArray;
+import javax.json.JsonArrayBuilder;
+import javax.json.JsonObject;
+import javax.json.JsonObjectBuilder;
+
+/**
+ * The Class EntityHistoryQueryBuilder.
+ */
+public class EntityHistoryQueryBuilder {
+
+ private static final String TABLE = "table";
+ private static final String GRAPH = "graph";
+
+ /**
+ * Gets the query.
+ *
+ * @param type the type
+ * @return the query
+ */
+ public static JsonObject getQuery(String type) {
+ if (type.equalsIgnoreCase(TABLE)) {
+ return createTableQuery();
+ } else if (type.equalsIgnoreCase(GRAPH)) {
+ return createGraphQuery();
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Creates the graph query.
+ *
+ * @return the json object
+ */
+ public static JsonObject createGraphQuery() {
+ JsonObjectBuilder jsonBuilder = Json.createObjectBuilder();
+
+ jsonBuilder.add("aggs",
+ Json.createObjectBuilder().add("group_by_entityType",
+ Json.createObjectBuilder()
+ .add("terms", Json.createObjectBuilder().add("field", "entityType").add("size", 0))
+ .add("aggs", Json.createObjectBuilder().add("group_by_date",
+ Json.createObjectBuilder().add("date_histogram", createDateHistogram())
+ .add("aggs", Json.createObjectBuilder().add("sort_by_date",
+ Json.createObjectBuilder().add("top_hits", createTopHitsBlob())))))));
+ jsonBuilder.add("size", 0);
+
+ return jsonBuilder.build();
+ }
+
+ /**
+ * Creates the table query.
+ *
+ * @return the json object
+ */
+ public static JsonObject createTableQuery() {
+ JsonObjectBuilder jsonBuilder = Json.createObjectBuilder();
+
+ jsonBuilder.add("aggs",
+ Json.createObjectBuilder().add("group_by_entityType",
+ Json.createObjectBuilder()
+ .add("terms", Json.createObjectBuilder().add("field", "entityType").add("size", 0))
+ .add("aggs", Json.createObjectBuilder().add("sort_by_date",
+ Json.createObjectBuilder().add("top_hits", createTopHitsBlob())))));
+ jsonBuilder.add("size", 0);
+
+ return jsonBuilder.build();
+ }
+
+ /**
+ * Creates the date histogram.
+ *
+ * @return the json object
+ */
+ private static JsonObject createDateHistogram() {
+ JsonObjectBuilder jsonBuilder = Json.createObjectBuilder();
+
+ jsonBuilder.add("field", "timestamp");
+ jsonBuilder.add("min_doc_count", 1);
+ jsonBuilder.add("interval", "day");
+ jsonBuilder.add("format", "epoch_millis");
+
+ return jsonBuilder.build();
+ }
+
+ /**
+ * Creates the top hits blob.
+ *
+ * @return the json object
+ */
+ private static JsonObject createTopHitsBlob() {
+ JsonObjectBuilder builder = Json.createObjectBuilder();
+ builder.add("size", 1);
+ builder.add("sort", getSortCriteria());
+ return builder.build();
+ }
+
+ public static JsonArray getSortCriteria() {
+ JsonArrayBuilder jsonBuilder = Json.createArrayBuilder();
+ jsonBuilder.add(Json.createObjectBuilder().add("timestamp",
+ Json.createObjectBuilder().add("order", "desc")));
+
+ return jsonBuilder.build();
+ }
+
+ /**
+ * The main method.
+ *
+ * @param args the arguments
+ */
+ public static void main(String[] args) {
+ System.out.println("TABLE-QUERY: " + createTableQuery().toString());
+ System.out.println("GRAPH_QUERY: " + createGraphQuery().toString());
+ }
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/inventory/GeoVisualizationProcessor.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/inventory/GeoVisualizationProcessor.java
new file mode 100644
index 0000000..a0e0630
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/inventory/GeoVisualizationProcessor.java
@@ -0,0 +1,180 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.inventory;
+
+import java.io.IOException;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.component.restlet.RestletConstants;
+import org.json.JSONArray;
+import org.json.JSONObject;
+import org.onap.aai.cl.api.Logger;
+import org.onap.aai.cl.eelf.LoggerFactory;
+import org.onap.aai.cl.mdc.MdcContext;
+import org.onap.aai.restclient.client.OperationResult;
+import org.onap.aai.sparky.dal.ElasticSearchAdapter;
+import org.onap.aai.sparky.logging.AaiUiMsgs;
+import org.onap.aai.sparky.util.NodeUtils;
+import org.restlet.Request;
+import org.restlet.Response;
+import org.restlet.data.ClientInfo;
+import org.restlet.data.Form;
+import org.restlet.data.MediaType;
+import org.restlet.data.Parameter;
+import org.restlet.data.Status;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+/**
+ * The Class GeoVisualizationServlet.
+ */
+public class GeoVisualizationProcessor {
+
+ private static final Logger LOG =
+ LoggerFactory.getInstance().getLogger(GeoVisualizationProcessor.class);
+
+ private ObjectMapper mapper;
+ private ElasticSearchAdapter elasticSearchAdapter = null;
+ private String topographicalSearchIndexName;
+
+ private static final String SEARCH_STRING = "_search";
+ private static final String SEARCH_PARAMETER = "?filter_path=hits.hits._source&_source=location&size=5000&q=entityType:";
+ private static final String PARAMETER_KEY = "entity";
+
+ /**
+ * Instantiates a new geo visualization processor
+ */
+ public GeoVisualizationProcessor(ElasticSearchAdapter elasticSearchAdapter, String topographicalSearchIndexName) {
+ this.mapper = new ObjectMapper();
+ this.elasticSearchAdapter = elasticSearchAdapter;
+ this.topographicalSearchIndexName = topographicalSearchIndexName;
+ }
+
+ /**
+ * Gets the geo visualization results.
+ *
+ * @param response the response
+ * @param entityType the entity type
+ * @return the geo visualization results
+ * @throws Exception the exception
+ */
+ protected OperationResult getGeoVisualizationResults(Exchange exchange) throws Exception {
+ OperationResult operationResult = new OperationResult();
+
+
+ Object xTransactionId = exchange.getIn().getHeader("X-TransactionId");
+ if (xTransactionId == null) {
+ xTransactionId = NodeUtils.getRandomTxnId();
+ }
+
+ Object partnerName = exchange.getIn().getHeader("X-FromAppId");
+ if (partnerName == null) {
+ partnerName = "Browser";
+ }
+
+ Request request = exchange.getIn().getHeader(RestletConstants.RESTLET_REQUEST, Request.class);
+
+ /* Disables automatic Apache Camel Restlet component logging which prints out an undesirable log entry
+ which includes client (e.g. browser) information */
+ request.setLoggable(false);
+
+ ClientInfo clientInfo = request.getClientInfo();
+ MdcContext.initialize((String) xTransactionId, "AAI-UI", "", (String) partnerName, clientInfo.getAddress() + ":" + clientInfo.getPort());
+
+ String entityType = "";
+
+ Form form = request.getResourceRef().getQueryAsForm();
+ for (Parameter parameter : form) {
+ if(PARAMETER_KEY.equals(parameter.getName())) {
+ entityType = parameter.getName();
+ }
+ }
+
+ String api = SEARCH_STRING + SEARCH_PARAMETER + entityType;
+
+ final String requestUrl = elasticSearchAdapter.buildElasticSearchUrlForApi(topographicalSearchIndexName, api);
+
+ try {
+
+ OperationResult opResult =
+ elasticSearchAdapter.doGet(requestUrl, javax.ws.rs.core.MediaType.APPLICATION_JSON_TYPE);
+
+ JSONObject finalOutputJson = formatOutput(opResult.getResult());
+
+ Response response = exchange.getIn().getHeader(RestletConstants.RESTLET_RESPONSE, Response.class);
+ response.setStatus(Status.SUCCESS_OK);
+ response.setEntity(String.valueOf(finalOutputJson), MediaType.APPLICATION_JSON);
+ exchange.getOut().setBody(response);
+
+ } catch (Exception exc) {
+ LOG.error(AaiUiMsgs.ERROR_GENERIC, "Error processing Geo Visualization request");
+ }
+
+ return operationResult;
+ }
+
+ /**
+ * Format output.
+ *
+ * @param results the results
+ * @return the JSON object
+ */
+ private JSONObject formatOutput(String results) {
+ JsonNode resultNode = null;
+ JSONObject finalResult = new JSONObject();
+ JSONArray entitiesArr = new JSONArray();
+
+ try {
+ resultNode = mapper.readTree(results);
+
+ final JsonNode hitsNode = resultNode.get("hits").get("hits");
+ if (hitsNode.isArray()) {
+
+ for (final JsonNode arrayNode : hitsNode) {
+ JsonNode sourceNode = arrayNode.get("_source");
+ if (sourceNode.get("location") != null) {
+ JsonNode locationNode = sourceNode.get("location");
+ if (NodeUtils.isNumeric(locationNode.get("lon").asText())
+ && NodeUtils.isNumeric(locationNode.get("lat").asText())) {
+ JSONObject location = new JSONObject();
+ location.put("longitude", locationNode.get("lon").asText());
+ location.put("latitude", locationNode.get("lat").asText());
+
+ entitiesArr.put(location);
+ }
+
+ }
+ }
+ }
+ finalResult.put("plotPoints", entitiesArr);
+
+ } catch (IOException exc) {
+ LOG.warn(AaiUiMsgs.ERROR_BUILDING_SEARCH_RESPONSE, exc.getLocalizedMessage());
+ }
+
+ return finalResult;
+ }
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/inventory/entity/GeoIndexDocument.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/inventory/entity/GeoIndexDocument.java
new file mode 100644
index 0000000..86918ad
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/inventory/entity/GeoIndexDocument.java
@@ -0,0 +1,289 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.inventory.entity;
+
+import java.io.Serializable;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.List;
+
+import org.onap.aai.sparky.config.oxm.OxmEntityDescriptor;
+import org.onap.aai.sparky.config.oxm.OxmEntityLookup;
+import org.onap.aai.sparky.sync.entity.IndexDocument;
+import org.onap.aai.sparky.util.NodeUtils;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+/**
+ * The Class GeoIndexDocument.
+ */
+public class GeoIndexDocument implements Serializable, IndexDocument {
+
+ @JsonIgnore
+ private static final long serialVersionUID = -5188479658230319058L;
+
+ protected String entityType;
+ protected String entityPrimaryKeyValue;
+ protected String entityPrimaryKeyName;
+ protected String latitude;
+ protected String longitude;
+ protected String selfLink;
+
+ @JsonIgnore
+ protected OxmEntityLookup oxmEntityLookup;
+
+ @JsonIgnore
+ protected ObjectMapper mapper = new ObjectMapper();
+ // generated, SHA-256 digest
+ @JsonIgnore
+ protected String id;
+
+ /**
+ * Convert bytes to hex string.
+ *
+ * @param bytesToConvert the bytes to convert
+ * @return the string
+ */
+ private static String convertBytesToHexString(byte[] bytesToConvert) {
+ StringBuffer hexString = new StringBuffer();
+ for (int i = 0; i < bytesToConvert.length; i++) {
+ hexString.append(Integer.toHexString(0xFF & bytesToConvert[i]));
+ }
+ return hexString.toString();
+ }
+
+
+ @JsonIgnore
+ public boolean isValidGeoDocument() {
+
+ boolean isValid = true;
+
+ isValid &= (this.getEntityType() != null);
+ isValid &= (this.getLatitude() != null);
+ isValid &= (this.getLongitude() != null);
+ isValid &= (this.getId() != null);
+ isValid &= (this.getSelfLink() != null);
+
+ isValid &= NodeUtils.isNumeric(this.getLatitude());
+ isValid &= NodeUtils.isNumeric(this.getLongitude());
+
+ return isValid;
+ }
+
+ /**
+ * Concat array.
+ *
+ * @param list the list
+ * @param delimiter the delimiter
+ * @return the string
+ */
+ private static String concatArray(List<String> list, char delimiter) {
+
+ if (list == null || list.size() == 0) {
+ return "";
+ }
+
+ StringBuilder result = new StringBuilder(64);
+
+ int listSize = list.size();
+ boolean firstValue = true;
+
+ for (String item : list) {
+
+ if (firstValue) {
+ result.append(item);
+ firstValue = false;
+ } else {
+ result.append(delimiter).append(item);
+ }
+
+ }
+
+ return result.toString();
+
+ }
+
+ /*
+ * We'll try and create a unique identity key that we can use for differencing the previously
+ * imported record sets as we won't have granular control of what is created/removed and when. The
+ * best we can hope for is identification of resources by generated Id until the Identity-Service
+ * UUID is tagged against all resources, then we can use that instead.
+ */
+
+ /**
+ * Generate unique sha digest.
+ *
+ * @param entityType the entity type
+ * @param fieldName the field name
+ * @param fieldValue the field value
+ * @return the string
+ * @throws NoSuchAlgorithmException the no such algorithm exception
+ */
+ public static String generateUniqueShaDigest(String entityType, String fieldName,
+ String fieldValue) throws NoSuchAlgorithmException {
+
+ /*
+ * Basically SHA-256 will result in an identity with a guaranteed uniqueness compared to just a
+ * java hashcode value.
+ */
+ MessageDigest digest = MessageDigest.getInstance("SHA-256");
+ digest.update(String.format("%s.%s.%s", entityType, fieldName, fieldValue).getBytes());
+ return convertBytesToHexString(digest.digest());
+ }
+
+ /**
+ * Instantiates a new geo index document.
+ */
+ public GeoIndexDocument() {}
+
+ /*
+ * (non-Javadoc)
+ *
+ */
+
+ @Override
+ @JsonIgnore
+ public String getAsJson() throws JsonProcessingException {
+
+ if (latitude != null && longitude != null) {
+
+ /**
+ * A valid entry from this class is one that has both lat and long. If one or both is missing
+ * we shouldn't be indexing anything.
+ */
+
+ return NodeUtils.convertObjectToJson(this, true);
+
+ }
+
+ return null;
+
+ }
+
+ /* (non-Javadoc)
+ * @see org.openecomp.sparky.synchronizer.entity.IndexDocument#deriveFields()
+ */
+ @Override
+ public void deriveFields() {
+
+ /*
+ * We'll try and create a unique identity key that we can use for differencing the previously
+ * imported record sets as we won't have granular control of what is created/removed and when.
+ * The best we can hope for is identification of resources by generated Id until the
+ * Identity-Service UUID is tagged against all resources, then we can use that instead.
+ */
+
+ OxmEntityDescriptor descriptor = oxmEntityLookup.getEntityDescriptors().get(entityType);
+ String entityPrimaryKeyName = NodeUtils.concatArray(
+ descriptor.getPrimaryKeyAttributeNames(), "/");
+
+ this.id =
+ NodeUtils.generateUniqueShaDigest(entityType, entityPrimaryKeyName, entityPrimaryKeyValue);
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ return "TopographicalEntity [" + ("entityType=" + entityType + ", ")
+ + ("entityPrimaryKeyValue=" + entityPrimaryKeyValue + ", ")
+ + ("latitude=" + latitude + ", ") + ("longitude=" + longitude + ", ") + ("ID=" + id + ", ")
+ + ("selfLink=" + selfLink) + "]";
+ }
+
+ @Override
+ @JsonIgnore
+ public String getId() {
+ return this.id;
+ }
+
+ @JsonProperty("entityType")
+ public String getEntityType() {
+ return entityType;
+ }
+
+ public void setEntityType(String entityType) {
+ this.entityType = entityType;
+ }
+
+ @JsonProperty("entityPrimaryKeyValue")
+ public String getEntityPrimaryKeyValue() {
+ return entityPrimaryKeyValue;
+ }
+
+ public void setEntityPrimaryKeyValue(String entityPrimaryKeyValue) {
+ this.entityPrimaryKeyValue = entityPrimaryKeyValue;
+ }
+
+ @JsonProperty("entityPrimaryKeyName")
+ public String getEntityPrimaryKeyName() {
+ return entityPrimaryKeyName;
+ }
+
+ public void setEntityPrimaryKeyName(String entityPrimaryKeyName) {
+ this.entityPrimaryKeyName = entityPrimaryKeyName;
+ }
+
+ @JsonProperty("lat")
+ public String getLatitude() {
+ return latitude;
+ }
+
+ public void setLatitude(String latitude) {
+ this.latitude = latitude;
+ }
+
+ @JsonProperty("long")
+ public String getLongitude() {
+ return longitude;
+ }
+
+ public void setLongitude(String longitude) {
+ this.longitude = longitude;
+ }
+
+ @JsonProperty("link")
+ public String getSelfLink() {
+ return selfLink;
+ }
+
+ public void setSelfLink(String selfLink) {
+ this.selfLink = selfLink;
+ }
+
+ @JsonIgnore
+ public static long getSerialversionuid() {
+ return serialVersionUID;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/inventory/entity/TopographicalEntity.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/inventory/entity/TopographicalEntity.java
new file mode 100644
index 0000000..ac89c6b
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/inventory/entity/TopographicalEntity.java
@@ -0,0 +1,219 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.inventory.entity;
+
+import java.io.IOException;
+import java.io.Serializable;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.List;
+
+import javax.json.Json;
+import javax.json.JsonObject;
+
+/**
+ * The Class TopographicalEntity.
+ */
+public class TopographicalEntity implements Serializable {
+
+ private static final long serialVersionUID = -5188479658230319058L;
+
+ protected String entityType;
+ protected String entityPrimaryKeyValue;
+ protected String entityPrimaryKeyName;
+ protected String latitude;
+ protected String longitude;
+ protected String selfLink;
+
+ // generated, SHA-256 digest
+ protected String id;
+
+ /**
+ * Convert bytes to hex string.
+ *
+ * @param bytesToConvert the bytes to convert
+ * @return the string
+ */
+ private static String convertBytesToHexString(byte[] bytesToConvert) {
+ StringBuffer hexString = new StringBuffer();
+ for (int i = 0; i < bytesToConvert.length; i++) {
+ hexString.append(Integer.toHexString(0xFF & bytesToConvert[i]));
+ }
+ return hexString.toString();
+ }
+
+ /**
+ * Concat array.
+ *
+ * @param list the list
+ * @param delimiter the delimiter
+ * @return the string
+ */
+ private static String concatArray(List<String> list, char delimiter) {
+
+ if (list == null || list.size() == 0) {
+ return "";
+ }
+
+ StringBuilder result = new StringBuilder(64);
+
+ int listSize = list.size();
+ boolean firstValue = true;
+
+ for (String item : list) {
+
+ if (firstValue) {
+ result.append(item);
+ firstValue = false;
+ } else {
+ result.append(delimiter).append(item);
+ }
+
+ }
+
+ return result.toString();
+
+ }
+
+ /*
+ * We'll try and create a unique identity key that we can use for differencing the previously
+ * imported record sets as we won't have granular control of what is created/removed and when. The
+ * best we can hope for is identification of resources by generated Id until the Identity-Service
+ * UUID is tagged against all resources, then we can use that instead.
+ */
+
+ /**
+ * Generate unique sha digest.
+ *
+ * @param entityType the entity type
+ * @param fieldName the field name
+ * @param fieldValue the field value
+ * @return the string
+ * @throws NoSuchAlgorithmException the no such algorithm exception
+ */
+ public static String generateUniqueShaDigest(String entityType, String fieldName,
+ String fieldValue) throws NoSuchAlgorithmException {
+
+ /*
+ * Basically SHA-256 will result in an identity with a guaranteed uniqueness compared to just a
+ * java hashcode value.
+ */
+ MessageDigest digest = MessageDigest.getInstance("SHA-256");
+ digest.update(String.format("%s.%s.%s", entityType, fieldName, fieldValue).getBytes());
+ return convertBytesToHexString(digest.digest());
+ }
+
+ /**
+ * Instantiates a new topographical entity.
+ */
+ public TopographicalEntity() {}
+
+ /*
+ * (non-Javadoc)
+ *
+ */
+ public String getAsJson() throws IOException {
+
+ JsonObject obj =
+ Json.createObjectBuilder().add("entityType", entityType).add("pkey", entityPrimaryKeyValue)
+ .add("location", Json.createObjectBuilder().add("lat", latitude).add("lon", longitude))
+ .add("selfLink", selfLink).build();
+
+ return obj.toString();
+ }
+
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ return "TopographicalEntity [" + ("entityType=" + entityType + ", ")
+ + ("entityPrimaryKeyValue=" + entityPrimaryKeyValue + ", ")
+ + ("latitude=" + latitude + ", ") + ("longitude=" + longitude + ", ") + ("ID=" + id + ", ")
+ + ("selfLink=" + selfLink) + "]";
+ }
+
+ public String getId() {
+ return this.id;
+ }
+
+ public String getEntityType() {
+ return entityType;
+ }
+
+ public void setEntityType(String entityType) {
+ this.entityType = entityType;
+ }
+
+ public String getEntityPrimaryKeyValue() {
+ return entityPrimaryKeyValue;
+ }
+
+ public void setEntityPrimaryKeyValue(String entityPrimaryKeyValue) {
+ this.entityPrimaryKeyValue = entityPrimaryKeyValue;
+ }
+
+ public String getEntityPrimaryKeyName() {
+ return entityPrimaryKeyName;
+ }
+
+ public void setEntityPrimaryKeyName(String entityPrimaryKeyName) {
+ this.entityPrimaryKeyName = entityPrimaryKeyName;
+ }
+
+ public String getLatitude() {
+ return latitude;
+ }
+
+ public void setLatitude(String latitude) {
+ this.latitude = latitude;
+ }
+
+ public String getLongitude() {
+ return longitude;
+ }
+
+ public void setLongitude(String longitude) {
+ this.longitude = longitude;
+ }
+
+ public String getSelfLink() {
+ return selfLink;
+ }
+
+ public void setSelfLink(String selfLink) {
+ this.selfLink = selfLink;
+ }
+
+ public static long getSerialversionuid() {
+ return serialVersionUID;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/logging/AaiUiMsgs.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/logging/AaiUiMsgs.java
new file mode 100644
index 0000000..7ae73a1
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/logging/AaiUiMsgs.java
@@ -0,0 +1,472 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.logging;
+
+import org.onap.aai.cl.eelf.LogMessageEnum;
+
+import com.att.eelf.i18n.EELFResourceManager;
+
+/**
+ * The Enum AaiUiMsgs.
+ */
+public enum AaiUiMsgs implements LogMessageEnum {
+ /** Arguments: {0} = Exception/error. */
+ FAILURE_TO_PROCESS_REQUEST,
+ /** Arguments: {0} = Message and or error body. */
+ FAILED_TO_DETERMINE,
+ /** Arguments: {0} = Exception/error. */
+ UNKNOWN_SERVER_ERROR,
+ /** Arguments: {0} = Message and or error body. */
+ FAILED_TO_ANALYZE,
+ /** Arguments: {0} = Exception/error. */
+ FAILED_TO_GET_NODES_QUERY_RESULT,
+ /** Arguments: {0} = Expected link count, {1} = Actual link count. */
+ UNEXPECTED_NUMBER_OF_LINKS,
+ /** Arguments: {0} = Reason. */
+ DANGLING_NODE_WARNING,
+ /** Arguments: {0} = Node count, {1} = Link count. */
+ VISUALIZATION_GRAPH_OUTPUT,
+ /** Arguments: {0} = JsonNode. */
+ ITEM_TYPE_NULL,
+ /** Arguments: {0} = Filter property. */
+ UNEXPECTED_TOKEN_COUNT,
+ /** Arguments: {0} = Error/exception message. */
+ ADD_SEARCH_TARGET_ATTRIBUTES_FAILED,
+ /** Arguments: {0} = Error/exception message. */
+ NODE_INTEGRITY_OVERLAY_ERROR,
+ /** Arguments: {0} = Node ID. */
+ NODE_INTEGRITY_ALREADY_PROCESSED,
+ /** Arguments: {0} = Node ID. */
+ SKIPPING_PROCESS_NODE_INTEGRITY,
+ /** Arguments: {0} = Error/exception message. */
+ FAILED_TO_PROCESS_NODE_INTEGRITY,
+ /** No argument */
+ MAX_EVALUATION_ATTEMPTS_EXCEEDED,
+ /** Arguments: {0} = Error/exception message. */
+ VISUALIZATION_OUTPUT_ERROR,
+ /** Arguments: {0} = Total resolve time, {1} = Total links retrieved, {2} = Op time. */
+ ALL_TRANSACTIONS_RESOLVED,
+ /** Arguments: {0} = Error/exception message. */
+ PROCESSING_LOOP_INTERUPTED,
+ /** Arguments: {0} = Node ID. */
+ IGNORING_SKELETON_NODE,
+ /** Arguments: {0} = Node count. */
+ OUTSTANDING_WORK_PENDING_NODES,
+ /** Arguments: {0} = Reason. */
+ FAILED_TO_ADD_SKELETON_NODE,
+ /** Arguments: {0} = Reason. */
+ FAILED_TO_PROCESS_SKELETON_NODE,
+ INVALID_RESOLVE_STATE_DURING_INIT,
+ /** Arguments: {0} = Reason. */
+ FAILED_TO_PROCESS_INITIAL_STATE,
+ /** Arguments: {0} = Relationship. */
+ SKIPPING_RELATIONSHIP,
+ /** Arguments: {0} = Failure reason. */
+ FAILED_TO_DETERMINE_NODE_ID,
+ /** Arguments: {0} = Error/exception message. */
+ EXTRACTION_ERROR,
+ /** Arguments: {0} = Error/exception message. */
+ SELF_LINK_NODE_PARSE_ERROR,
+ /** Arguments: {0} = Node ID. */
+ ROOT_NODE_DISCOVERED,
+ /** Arguments: {0} = Error/exception message. */
+ SELF_LINK_PROCESS_NEIGHBORS_ERROR,
+ /** Arguments: {0} = Error/exception message. */
+ SELF_LINK_JSON_PARSE_ERROR,
+ /** Arguments: {0} = Error/exception message. */
+ SELF_LINK_PROCESSING_ERROR,
+ /** Arguments: {0} = Entity type. */
+ UNHANDLED_OBJ_TYPE_FOR_ENTITY_TYPE,
+ /** Arguments: {0} = Attribute group. */
+ ATTRIBUTE_GROUP_FAILURE,
+ /** Arguments: {0} = Situational description, {1} = Exception message. */
+ EXCEPTION_CAUGHT,
+ /** Arguments: {0} = Operation name, {1} = Operation time. */
+ OPERATION_TIME,
+ /** Arguments: {0} = Error message. */
+ SEARCH_SERVLET_ERROR,
+ /** Arguments: {0} = Exception message. */
+ SEARCH_RESPONSE_BUILDING_EXCEPTION,
+ /** Arguments: {0} = Error message, {1} = Error message. */
+ SEARCH_TAG_ANNOTATION_ERROR,
+ /** Arguments: {0} = App type. */
+ QUERY_FAILED_UNHANDLED_APP_TYPE,
+ /** Arguments: {0} = Entity type. */
+ ENTITY_NOT_FOUND_IN_OXM,
+ /** Arguments: {0} = JSON conversion type, {1} = Error thrown. */
+ JSON_CONVERSION_ERROR,
+ /** Arguments: {0} = Node ID */
+ NO_RELATIONSHIP_DISCOVERED,
+ /** No argument */
+ SELF_LINK_NULL_EMPTY_RESPONSE,
+ /** Arguments: {0} = Error message. */
+ SELF_LINK_RELATIONSHIP_LIST_ERROR,
+ /** Arguments: {0} = AIN id, {1} = old depth, {2} = new depth. */
+ ACTIVE_INV_NODE_CHANGE_DEPTH,
+ /** Arguments: {0} = Node ID, {1} = Current state, {2} = New state {3} = Triggering action */
+ ACTIVE_INV_NODE_CHANGE_STATE,
+ /** Arguments: {0} = Current state, {1} = New state {2} = Triggering action */
+ ACTIVE_INV_NODE_CHANGE_STATE_NO_NODE_ID,
+ /** Arguments: {0} = Count Key {1} = Aggregation Key. */
+ AGGREGATION_KEY_ERROR,
+ /** Arguments: {0} Configuration */
+ CONFIGURATION_ERROR,
+ /** Arguments: {0} = Source. */
+ ERROR_PARSING_JSON_PAYLOAD_NONVERBOSE,
+ /** Arguments: {0} = Payload. */
+ ERROR_PARSING_JSON_PAYLOAD_VERBOSE,
+ /** Arguments: {0} = Key {1} = JSON Blob. */
+ ERROR_FETCHING_JSON_VALUE,
+ /** Arguments: {0} = Error. */
+ ERROR_PARSING_PARAMS,
+ /** No argument */
+ INVALID_REQUEST_PARAMS,
+ /** Arguments: {0} = Key. */
+ ERROR_SORTING_VIOLATION_DATA,
+ /** Arguments: {0} = exception */
+ ERROR_SERVLET_PROCESSSING,
+ /** Arguments: {0} = exception */
+ ERROR_BUILDING_RESPONSE_FOR_TABLE_QUERY,
+ /** Arguments: {0} = exception */
+ ERROR_BUILDING_SEARCH_RESPONSE,
+ /** No argument */
+ ERROR_CSP_CONFIG_FILE,
+ /** Arguments: {0} = exception */
+ ERROR_SHUTDOWN_EXECUTORS,
+ /** No argument */
+ ERROR_LOADING_OXM,
+ /** Arguments: {0} = exception */
+ ERROR_GETTING_DATA_FROM_AAI,
+ /** No argument */
+ WAIT_FOR_ALL_SELFLINKS_TO_BE_COLLECTED,
+ /** Arguments: {0} = Entity Type */
+ MISSING_ENTITY_DESCRIPTOR,
+ /** Arguments: {0} = Error */
+ SELF_LINK_GET,
+ /** Arguments: {0} = Error */
+ ES_FAILED_TO_CONSTRUCT_QUERY,
+ /** Arguments: {0} = Error */
+ ES_RETRIEVAL_FAILED,
+ /** Arguments: {0} = Error */
+ ES_LINK_UPSERT,
+ /** Arguments: {0} = Element */
+ ES_SIMPLE_PUT,
+ /** Arguments: {0} = Value {1} = Element {2} = Error */
+ ES_ABORT_CROSS_ENTITY_REF_SYNC,
+ /** Arguments: {0} Return Code */
+ ES_OPERATION_RETURN_CODE,
+ /** Arguments: {0} = Error */
+ ES_CROSS_ENTITY_REF_PUT,
+ /** No argument */
+ ES_CROSS_REF_SYNC_VERSION_CONFLICT,
+ /** Arguments: {0} Result Code {1} = Error */
+ ES_CROSS_REF_SYNC_FAILURE,
+ /** Arguments: {0} = Error */
+ ES_FAILED_TO_CONSTRUCT_URI,
+ /** No argument */
+ ES_RETRIEVAL_FAILED_RESYNC,
+ /** Arguments: {0} = Entity */
+ ES_CROSS_ENTITY_RESYNC_LIMIT,
+ /** Arguments: {0} Entity Name */
+ ES_PKEYVALUE_NULL,
+ /** Arguments: {0} = Error */
+ ES_STORE_FAILURE,
+ /** Arguments: {0} Index Name {1} = Error */
+ ES_PRE_SYNC_FAILURE,
+ /** Arguments: {0} Index Name */
+ ES_SYNC_CLEAN_UP,
+ /** Arguments: {0} Index Name {1} Size before clean up {2} = Size after clean up */
+ ES_SYNC_CLEAN_UP_SIZE,
+ /** Arguments: {0} Index Name {1} Index Type {2} = Size before delete */
+ ES_SYNC_SELECTIVE_DELETE,
+ /** Arguments: {0} Index Name {1} Number of records */
+ ES_BULK_DELETE,
+ /** Arguments: {0} Index name {1} = Error */
+ ES_BULK_DELETE_ERROR,
+ /** Arguments: {0} Type of retrieval {1} Completion Time */
+ COLLECT_TIME_WITH_ERROR,
+ /** Arguments: {0} Type of retrieval {1} Completion Time */
+ COLLECT_TIME_WITH_SUCCESS,
+ /** Arguments: {0} Type of retrieval {1} Number of records */
+ COLLECT_TOTAL,
+ /** Arguments: {0} Number of required fetches */
+ SYNC_NUMBER_REQ_FETCHES,
+ /** Arguments: {0} Number of total fetches {1} Number of available records*/
+ SYNC_NUMBER_TOTAL_FETCHES,
+ /** Arguments: {0} Completion Time */
+ COLLECT_TOTAL_TIME,
+ /** Arguments: {0} = Error */
+ ES_SCROLL_CONTEXT_ERROR,
+ /** No argument */
+ ES_BULK_DELETE_SKIP,
+ /** Arguments: {0} = Number of docs */
+ ES_BULK_DELETE_START,
+ /** No argument */
+ SELF_LINK_CROSS_REF_SYNC,
+ /** Arguments: {0} = message */
+ ERROR_GENERIC,
+ /** Arguments: {0} = error */
+ JSON_PROCESSING_ERROR,
+ /** Arguments: {0} = exception */
+ ERROR_PROCESSING_REQUEST,
+ /** Arguments: {0} = Self Link */
+ SELF_LINK_GET_NO_RESPONSE,
+ /** Arguments: {0} = error */
+ HISTORICAL_COLLECT_ERROR,
+ /** Arguments: {0} = Time */
+ HISTORICAL_ENTITY_COUNT_SUMMARIZER_STARTING,
+ /** No argument */
+ HISTORICAL_ENTITY_COUNT_SUMMARIZER_NOT_STARTED,
+ /** Arguments: {0} = Controller {1} = Time */
+ HISTORICAL_SYNC_DURATION,
+ /** No argument */
+ HISTORICAL_SYNC_PENDING,
+ /** Arguments: {0} = Time */
+ HISTORICAL_SYNC_TO_BEGIN,
+ /** Arguments: {0} = message */
+ DEBUG_GENERIC,
+ /** Arguments: {0} = message */
+ INFO_GENERIC,
+ /** Arguments: {0} = message */
+ WARN_GENERIC,
+ /** Arguments: {0} = context {1} = Exception*/
+ INTERRUPTED,
+ /** Arguments: {0} = Entity Type {1} Entity */
+ GEO_SYNC_IGNORING_ENTITY,
+ /** Arguments: {0} = reason */
+ OXM_LOADING_ERROR,
+ /** Arguments: {0} = type */
+ OXM_FAILED_RETRIEVAL,
+ OXM_FILE_NOT_FOUND,
+ /** No argument */
+ OXM_READ_ERROR_NONVERBOSE,
+ /** Arguments: {0} = OXM File name */
+ OXM_READ_ERROR_VERBOSE,
+ /** No argument */
+ OXM_PARSE_ERROR_NONVERBOSE,
+ /** Arguments: {0} = OXM File name {1} = Exception*/
+ OXM_PARSE_ERROR_VERBOSE,
+ /** Arguments: {0} = Numerical value for loaded OXM version */
+ OXM_LOAD_SUCCESS,
+ /** Arguments: {0} = Entity {1} = Found property-value*/
+ OXM_PROP_DEF_ERR_CROSS_ENTITY_REF,
+ /** Arguments: {0} = Sequence Number */
+ ETAG_RETRY_SEQ,
+ /** Arguments: {0} = Reason */
+ ETAG_WAIT_INTERRUPTION,
+ /** Arguments: {0} = URL {1} = Sequence Number */
+ QUERY_AAI_RETRY_SEQ,
+ /** Arguments: {0} = URL {1} = Sequence Number */
+ QUERY_AAI_RETRY_DONE_SEQ,
+ /** Arguments: {0} = Reason */
+ QUERY_AAI_WAIT_INTERRUPTION,
+ /** Arguments: {0} = URL {1} = Sequence Number */
+ QUERY_AAI_RETRY_FAILURE_WITH_SEQ,
+ /** Arguments: {0} = URL */
+ QUERY_AAI_RETRY_MAXED_OUT,
+ /** Arguments: {0} = Reason */
+ PEGGING_ERROR,
+ /** Arguments: {0} = Key */
+ DATA_CACHE_SUCCESS,
+ /** Arguments: {0} = URL {1} = Sequence Number */
+ EXECUTOR_SERV_EXCEPTION,
+ /** Arguments: {0} = Exception */
+ DISK_CACHE_READ_IO_ERROR,
+ /** Arguments: {0} = Exception */
+ DISK_CREATE_DIR_IO_ERROR,
+ /** Arguments: {0} = Exception */
+ DISK_DATA_WRITE_IO_ERROR,
+ /** Arguments: {0} = Data Item {1} = Exception */
+ DISK_NAMED_DATA_WRITE_IO_ERROR,
+ /** Arguments: {0} = Data Item {1} = Exception */
+ DISK_NAMED_DATA_READ_IO_ERROR,
+ /** No argument */
+ OFFLINE_STORAGE_PATH_ERROR,
+ /** Arguments: {0} = URL {1} = Error */
+ RESTFULL_OP_ERROR_VERBOSE,
+ /** Arguments: {0} = Method {1} = Time {2} = URL {3} = Result Code */
+ RESTFULL_OP_COMPLETE,
+ /** No argument */
+ INITIALIZE_OXM_MODEL_LOADER,
+ /** Arguments: {0} = Exception */
+ AAI_RETRIEVAL_FAILED_GENERIC,
+ /** Arguments: {0} = Self Link */
+ AAI_RETRIEVAL_FAILED_FOR_SELF_LINK,
+ /** Arguments: {0} = Exception */
+ ATTRIBUTES_NOT_UPDATED_EXCEPTION,
+ /** Arguments: {0} = Message */
+ ATTRIBUTES_NOT_UPDATED_MESSAGE,
+ /** Arguments: {0} = Exception */
+ ATTRIBUTES_ERROR_GETTING_AAI_CONFIG_OR_ADAPTER,
+ /** Arguments: {0} = Schema File URI */
+ ATTRIBUTES_ERROR_LOADING_MODEL_VERSION,
+ /** Arguments: {0} = Request URI {1} = Edit Request Body */
+ ATTRIBUTES_HANDLING_EDIT,
+ /** Arguments: {0} = Object URI {1} = Attribute ID {2} Attribute Values */
+ ATTRIBUTES_UPDATE_METHOD_CALLED,
+ /** Arguments: {0} = Attribute ID */
+ ATTRIBUTES_USER_NOT_AUTHORIZED_TO_UPDATE,
+ /** Arguments: {0} = Cookie */
+ COOKIE_FOUND,
+ /** No argument */
+ COOKIE_NOT_FOUND,
+ /** Arguments: {0} = Message */
+ INVALID_REQUEST,
+ /** Arguments: {0} = User ID */
+ USER_AUTHORIZATION_FILE_UNAVAILABLE,
+ /** Arguments: {0} = URL {1} = Cause */
+ INVALID_URL_VERBOSE,
+ /** Arguments: {0} = Row ID */
+ DI_DATA_NOT_FOUND_NONVERBOSE,
+ /** Arguments: {0} = Row ID {1} Attempt count */
+ DI_DATA_NOT_FOUND_VERBOSE,
+ /** Arguments: {0} = Time in ms {1} Status */
+ DI_MS_TIME_FOR_DATA_FETCH,
+ /** Arguments: {0} = Number of Entity Links */
+ ENTITY_SYNC_FAILED_SELFLINK_AMBIGUITY,
+ /** Arguments: {0} = Message */
+ ERROR_EXTRACTING_FROM_RESPONSE,
+ /** No argument */
+ ERROR_LOADING_OXM_SEARCHABLE_ENTITIES,
+ /** Arguments: {0} = Message */
+ ES_SEARCHABLE_ENTITY_SYNC_ERROR,
+ /** Arguments: {0} = Message */
+ FAILED_TO_REGISTER_DUE_TO_NULL,
+ /** Arguments: {0} = File Path */
+ FAILED_TO_RESTORE_TXN_FILE_MISSING,
+ /** Arguments: {0} = Index Name */
+ INDEX_ALREADY_EXISTS,
+ /** Arguments: {0} = Index Name */
+ INDEX_EXISTS,
+ /** Arguments: {0} = Index Name {1} = Operation Result */
+ INDEX_INTEGRITY_CHECK_FAILED,
+ /** Arguments: {0} = Index Name */
+ INDEX_NOT_EXIST,
+ /** Arguments: {0} = Index Name */
+ INDEX_RECREATED,
+ /** Arguments: {0} = Time */
+ SEARCH_ENGINE_SYNC_STARTED,
+ /** Arguments: {0} = Time */
+ SKIP_PERIODIC_SYNC_AS_SYNC_DIDNT_FINISH,
+ /** Arguments: {0} = Message */
+ SYNC_DURATION,
+ /** Arguments: {0} = Entity Type */
+ ENTITY_SYNC_FAILED_DESCRIPTOR_NOT_FOUND,
+ /** Arguments: {0} = AAI Query Result */
+ ENTITY_SYNC_FAILED_DURING_AAI_RESPONSE_CONVERSION,
+ /** Arguments: {0} = Message */
+ ENTITY_SYNC_FAILED_QUERY_ERROR,
+ /** Arguments: {0} = Self Link Query */
+ SELF_LINK_DETERMINATION_FAILED_GENERIC,
+ /** Arguments: {0} = Number of Entity Links */
+ SELF_LINK_DETERMINATION_FAILED_UNEXPECTED_LINKS,
+ /** Arguments: {1} = Query {2} = Operation Result Code {3} = Operation Result */
+ SELF_LINK_RETRIEVAL_FAILED,
+ /** Arguments: {0} = Controller {1} = Synchronizer Current Internal State {2} = New State {3} = Caused By Action */
+ SYNC_INTERNAL_STATE_CHANGED,
+ /** Arguments: {0} = Message */
+ SYNC_INVALID_CONFIG_PARAM,
+ /** Arguments: {0} = Synchronizer Current Internal State */
+ SYNC_NOT_VALID_STATE_DURING_REQUEST,
+ /** No argument */
+ SYNC_SKIPPED_SYNCCONTROLLER_NOT_INITIALIZED,
+ /** No argument */
+ SYNC_START_TIME,
+ /** Arguments: {0} = Controller {1} = Time */
+ SYNC_TO_BEGIN,
+ /** Arguments: {0} = File Path */
+ WILL_RETRIEVE_TXN,
+ /** Arguments: {0} = Configuration file name {1} = Exception */
+ CONFIG_NOT_FOUND_VERBOSE,
+ /** Arguments: {0} = File name */
+ FILE_NOT_FOUND,
+ /** Arguments: {0} = File name */
+ FILE_READ_IN_PROGRESS,
+ ERROR_LOADING_OXM_SUGGESTIBLE_ENTITIES,
+ /** Arguments: {0} = Error message */
+ ES_SUGGESTION_SEARCH_ENTITY_SYNC_ERROR,
+ /** Arguments: {0} = Error message */
+ ES_AGGREGATION_SUGGESTION_ENTITY_SYNC_ERROR,
+ /** Arguments: {0} = Error message. */
+ ENTITY_SYNC_SEARCH_TAG_ANNOTATION_FAILED,
+ /** Arguments: {0} = Error message */
+ SEARCH_ADAPTER_ERROR,
+ /** Arguments: {0} = Decoding exception message */
+ UNSUPPORTED_URL_ENCODING,
+ /** Arguments: {0} = Invalid URL */
+ INVALID_REDIRECT_URL,
+ /** Arguments: {0} = Valid login URL */
+ VALID_REDIRECT_URL,
+ /** Arguments: {0} = Query Parameter Self-Link Extraction Error */
+ QUERY_PARAM_EXTRACTION_ERROR,
+ /** Arguments: {0} = Info message */
+ LOGIN_FILTER_INFO,
+ /** Arguments: {0} = Debug message */
+ LOGIN_FILTER_DEBUG,
+ /** Arguments: {0} = URL to extract parameter from */
+ ERROR_REMOVING_URL_PARAM,
+ /** Arguments: {0} = Hash value */
+ ERROR_INVALID_HASH,
+ ERROR_HASH_NOT_FOUND,
+ ERROR_FILTERS_NOT_FOUND,
+ ERROR_READING_HTTP_REQ_PARAMS,
+ /** Arguments: {0} = Exception */
+ ERROR_D3_GRAPH_VISUALIZATION,
+ /** Arguments: {0} = Exception */
+ ERROR_AAI_QUERY_WITH_RETRY,
+ /** Arguments: Error extracting resource path from self-link. Error = {0} */
+ ERROR_EXTRACTING_RESOURCE_PATH_FROM_LINK,
+ /** Arguments: {0} = Schema file location */
+ ERROR_READING_JSON_SCHEMA,
+ /** Arguments: {0} = UI view name */
+ VIEW_NAME_NOT_SUPPORTED,
+ /** Arguments: {0} = response code, {1} = filter name */
+ ERROR_FETCHING_FILTER_VALUES,
+ /** Arguments: {0} = query type, {1} = view name */
+ ERROR_PROCESSING_WIDGET_REQUEST,
+ /** Arguments: {0} = Time in ms */
+ DR_PROCESSING_TIME,
+ /** Arguments: {0} = Response code {1} = payload */
+ DR_PROCESSING_FAILURE,
+ /** Arguments: {0} = request uri */
+ DR_REQUEST_URI_FOR_PROXY_UNKNOWN,
+ /** Arguments: {0} = origin-url {1} = dr-url */
+ DR_PROXY_FROM_TO,
+ /** Arguments: {0} = Exception */
+ URI_DECODING_EXCEPTION,
+ /** Arguments: {0} = Value {1} = Error */
+ ENCRYPTION_ERROR,
+ /** Arguments: {0} = Encrypted value {1} = Error */
+ DECRYPTION_ERROR,
+ /** Arguments: {0} = URI */
+ RESOURCE_NOT_FOUND;
+
+ /**
+ * Static initializer to ensure the resource bundles for this class are loaded...
+ */
+ static {
+ EELFResourceManager.loadMessageBundle("logging/AAIUIMsgs");
+ }
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/logging/util/LoggingUtils.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/logging/util/LoggingUtils.java
new file mode 100644
index 0000000..04ad83a
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/logging/util/LoggingUtils.java
@@ -0,0 +1,43 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.logging.util;
+
+/**
+ * The Class LoggingUtils.
+ */
+public class LoggingUtils {
+
+ /**
+ * Sets the duration.
+ *
+ * @param startTime the start time
+ * @param stopTime the stop time
+ * @return the string
+ */
+ public static String setDuration(long startTime, long stopTime) {
+ return String.valueOf(stopTime - startTime);
+ }
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/logging/util/ServletUtils.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/logging/util/ServletUtils.java
new file mode 100644
index 0000000..44068a1
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/logging/util/ServletUtils.java
@@ -0,0 +1,204 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.logging.util;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.camel.Exchange;
+import org.onap.aai.cl.api.Logger;
+import org.onap.aai.cl.mdc.MdcContext;
+import org.onap.aai.restclient.client.OperationResult;
+import org.onap.aai.sparky.logging.AaiUiMsgs;
+import org.onap.aai.sparky.search.SearchServiceAdapter;
+import org.onap.aai.sparky.util.NodeUtils;
+import org.onap.aai.sparky.viewandinspect.config.SparkyConstants;
+import org.slf4j.MDC;
+
+/**
+ * The Class ServletUtils.
+ */
+public class ServletUtils {
+
+ /**
+ * Execute get query.
+ *
+ * @param logger the logger
+ * @param search the search
+ * @param response the response
+ * @param requestUrl the request url
+ * @return the operation result
+ * @throws Exception the exception
+ */
+ public static OperationResult executeGetQuery(Logger logger, SearchServiceAdapter search,
+ HttpServletResponse response, String requestUrl) throws Exception {
+
+ OperationResult opResult = search.doGet(requestUrl, "application/json");
+
+ if (opResult.getResultCode() > 300) {
+ setServletResponse(logger, true, opResult.getResultCode(), response, opResult.getResult());
+ } else {
+ response.setStatus(opResult.getResultCode());
+ }
+
+ return opResult;
+
+ }
+
+ /**
+ * Execute post query.
+ *
+ * @param logger the logger
+ * @param search the search
+ * @param response the response
+ * @param requestUrl the request url
+ * @param requestJsonPayload the request json payload
+ * @return the operation result
+ * @throws Exception the exception
+ */
+ public static OperationResult executePostQuery(Logger logger, SearchServiceAdapter search,
+ HttpServletResponse response, String requestUrl, String requestJsonPayload) throws Exception {
+
+ OperationResult opResult = search.doPost(requestUrl, requestJsonPayload, "application/json");
+
+ if (opResult.getResultCode() > 300) {
+ setServletResponse(logger, true, opResult.getResultCode(), response, opResult.getResult());
+
+ } else {
+ response.setStatus(opResult.getResultCode());
+ }
+
+ return opResult;
+ }
+
+ /**
+ * Handle search servlet errors.
+ *
+ * @param logger the logger
+ * @param errorMsg the error msg
+ * @param exc the exc
+ * @param response the response
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public static void handleSearchServletErrors(Logger logger, String errorMsg, Exception exc,
+ HttpServletResponse response) throws IOException {
+ String errorLogMsg = (exc == null ? errorMsg : errorMsg + ". Error:"
+ + exc.getLocalizedMessage());
+ logger.error(AaiUiMsgs.ERROR_GENERIC, errorLogMsg);
+ response.setContentType("application/json");
+ PrintWriter out = response.getWriter();
+ out.println(generateJsonErrorResponse(errorMsg));
+ out.close();
+ }
+
+ /**
+ * Generate json error response.
+ *
+ * @param message the message
+ * @return the string
+ */
+ public static String generateJsonErrorResponse(String message) {
+ return String.format("{ \"errorMessage\" : %s }", message);
+ }
+
+ /**
+ * Sets the servlet response.
+ *
+ * @param logger the logger
+ * @param isError the is error
+ * @param responseCode the response code
+ * @param response the response
+ * @param postPayload the post payload
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public static void setServletResponse(Logger logger, boolean isError, int responseCode,
+ HttpServletResponse response, String postPayload) throws IOException {
+
+ if (isError) {
+ logger.error(AaiUiMsgs.ERROR_GENERIC, postPayload);
+ }
+
+ response.setStatus(responseCode);
+
+ if (postPayload != null) {
+ response.setContentType("application/json");
+ PrintWriter out = response.getWriter();
+ out.println(postPayload);
+ out.close();
+ }
+ }
+
+ /**
+ * Gets the full url.
+ *
+ * @param elasticConfig the elastic config
+ * @param resourceUrl the resource url
+ * @return the full url
+ */
+ public static String getFullUrl(String eHost,String ePort, String resourceUrl) {
+ final String host = eHost;
+ final String port = ePort;
+ return String.format("http://%s:%s%s", host, port, resourceUrl);
+ }
+
+ public static void setUpMdcContext(final Exchange exchange, final HttpServletRequest request) {
+
+ String txnId;
+
+ Object xTransactionId = exchange.getIn().getHeader("X-TransactionId");
+ if (xTransactionId == null) {
+ txnId = NodeUtils.getRandomTxnId();
+ } else {
+ txnId = (String) xTransactionId;
+ }
+
+ String fromAppId;
+
+ Object partnerName = exchange.getIn().getHeader("X-FromAppId");
+ if (partnerName == null) {
+ fromAppId = SparkyConstants.APP_NAME;
+ } else {
+ fromAppId = (String) partnerName;
+ }
+
+ MdcContext.initialize(txnId, "AAI-UI", "", fromAppId,
+ request.getRequestURI() + ":" + request.getLocalPort());
+ }
+
+ public static Map<String, List<String>> getTxnHeaders() {
+ Map<String, List<String>> headers = new HashMap<String, List<String>>();
+ headers.put("X-TransactionId", Arrays.asList(MDC.get(MdcContext.MDC_REQUEST_ID)));
+ headers.put("X-FromAppId", Arrays.asList(MDC.get(MdcContext.MDC_PARTNER_NAME)));
+ return headers;
+ }
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/EntityCountHistoryProcessor.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/EntityCountHistoryProcessor.java
new file mode 100644
index 0000000..4c393e1
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/EntityCountHistoryProcessor.java
@@ -0,0 +1,407 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.search;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.TreeMap;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.Processor;
+import org.apache.camel.component.restlet.RestletConstants;
+import org.json.JSONArray;
+import org.json.JSONObject;
+import org.onap.aai.cl.api.Logger;
+import org.onap.aai.cl.eelf.LoggerFactory;
+import org.onap.aai.cl.mdc.MdcContext;
+import org.onap.aai.restclient.client.OperationResult;
+import org.onap.aai.sparky.dal.ElasticSearchAdapter;
+import org.onap.aai.sparky.inventory.EntityHistoryQueryBuilder;
+import org.onap.aai.sparky.logging.AaiUiMsgs;
+import org.onap.aai.sparky.util.NodeUtils;
+import org.onap.aai.sparky.util.RestletUtils;
+import org.restlet.Request;
+import org.restlet.Response;
+import org.restlet.data.ClientInfo;
+import org.restlet.data.MediaType;
+import org.restlet.data.Status;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
+
+/**
+ * Receives and processes Entity Count History requests
+ */
+public class EntityCountHistoryProcessor implements Processor {
+
+ private static final Logger LOG =
+ LoggerFactory.getInstance().getLogger(EntityCountHistoryProcessor.class);
+
+ private static final long serialVersionUID = 1L;
+
+ private ElasticSearchAdapter elasticSearchAdapter = null;
+ private ObjectMapper mapper;
+
+ private static final String SEARCH_PRETTY_STRING = "_search?pretty";
+ private static final String TYPE = "type";
+ private static final String TABLE = "table";
+ private static final String GRAPH = "graph";
+
+ private List<String> entityTypesToSummarize;
+ private List<String> vnfEntityTypes;
+
+ private String entityCountHistoryIndexName;
+
+ private boolean summarizeVnfs = false;
+
+ private RestletUtils restletUtils = new RestletUtils();
+
+ /**
+ * Instantiates a new Entity Count History
+ */
+
+ public EntityCountHistoryProcessor(ElasticSearchAdapter elasticSearchAdapter,
+ String entityTypesToSummarizeDelimitedList, String vnfEntityTypesDelimitedList, String entityCountHistoryIndexName) {
+
+ this.elasticSearchAdapter = elasticSearchAdapter;
+ this.entityCountHistoryIndexName = entityCountHistoryIndexName;
+
+ entityTypesToSummarize =
+ Arrays.asList(entityTypesToSummarizeDelimitedList.toLowerCase().split("[\\s,]+"));
+
+ vnfEntityTypes =
+ Arrays.asList(vnfEntityTypesDelimitedList.toLowerCase().split("[\\s,]+"));
+
+ summarizeVnfs = vnfEntityTypesDelimitedList.toLowerCase().contains("vnf");
+
+ this.mapper = new ObjectMapper();
+ this.mapper.configure(SerializationFeature.INDENT_OUTPUT, true);
+ }
+
+ /**
+ * Processes a entity count history search request
+ *
+ * @param exchange The Exchange object generated by Apache Camel for the incoming request
+ */
+
+ @Override
+ public void process(Exchange exchange) throws Exception {
+
+ Request request = exchange.getIn().getHeader(RestletConstants.RESTLET_REQUEST, Request.class);
+ Response restletResponse =
+ exchange.getIn().getHeader(RestletConstants.RESTLET_RESPONSE, Response.class);
+
+ Object xTransactionId = exchange.getIn().getHeader("X-TransactionId");
+ if (xTransactionId == null) {
+ xTransactionId = NodeUtils.getRandomTxnId();
+ }
+
+ Object partnerName = exchange.getIn().getHeader("X-FromAppId");
+ if (partnerName == null) {
+ partnerName = "Browser";
+ }
+
+ /*
+ * Disables automatic Apache Camel Restlet component logging which prints out an undesirable log
+ * entry which includes client (e.g. browser) information
+ */
+ request.setLoggable(false);
+
+ ClientInfo clientInfo = request.getClientInfo();
+ MdcContext.initialize((String) xTransactionId, "AAI-UI", "", (String) partnerName,
+ clientInfo.getAddress() + ":" + clientInfo.getPort());
+
+ String typeParameter = getTypeParameter(exchange);
+
+ if (null != typeParameter && !typeParameter.isEmpty()) {
+ OperationResult operationResult = null;
+
+ try {
+ operationResult = getResults(restletResponse, typeParameter);
+ restletResponse.setEntity(operationResult.getResult(), MediaType.APPLICATION_JSON);
+ } catch (Exception exc) {
+ LOG.error(AaiUiMsgs.CONFIGURATION_ERROR, exc.getLocalizedMessage());
+ }
+ } else {
+ LOG.error(AaiUiMsgs.RESOURCE_NOT_FOUND, request.getOriginalRef().toString());
+ String errorMessage =
+ restletUtils.generateJsonErrorResponse("Unsupported request. Resource not found.");
+ restletResponse.setEntity(errorMessage, MediaType.APPLICATION_JSON);
+ restletResponse.setStatus(Status.CLIENT_ERROR_NOT_FOUND);
+ }
+
+ exchange.getOut().setBody(restletResponse);
+ }
+
+
+ /**
+ * Format line graph output
+ *
+ * @param results The results
+ * @return The JSON object
+ * @throws JsonProcessingException The JSON processing exception
+ */
+ public JSONObject formatLineGraphOutput(String results) throws JsonProcessingException {
+ Map<Long, Long> countByDateMap = new HashMap<Long, Long>();
+
+ JsonNode resultNode = null;
+
+ JSONObject finalResult = new JSONObject();
+ JSONArray finalResultArr = new JSONArray();
+
+ try {
+ resultNode = mapper.readTree(results);
+
+ final JsonNode bucketsNode = getBucketsNode(resultNode);
+
+ if (bucketsNode.isArray()) {
+
+ for (final JsonNode entityNode : bucketsNode) {
+ final JsonNode dateBucketNode = entityNode.get("group_by_date").get("buckets");
+ if (dateBucketNode.isArray()) {
+ for (final JsonNode dateBucket : dateBucketNode) {
+ Long date = dateBucket.get("key").asLong();
+ final JsonNode countBucketNode =
+ dateBucket.get("sort_by_date").get("hits").get("hits");
+
+ if (countBucketNode.isArray()) {
+ final JsonNode latestEntityNode = countBucketNode.get(0);
+
+ long currentCount = latestEntityNode.get("_source").get("count").asLong();
+ if (countByDateMap.containsKey(date)) {
+ // add to the value if map already contains this date
+ currentCount += countByDateMap.get(date);
+ }
+
+ countByDateMap.put(date, currentCount);
+ }
+ }
+
+ }
+ }
+ }
+
+ /*
+ * Sort the map by epoch timestamp
+ */
+ Map<Long, Long> sortedMap = new TreeMap<Long, Long>(countByDateMap);
+ for (Entry<Long, Long> entry : sortedMap.entrySet()) {
+ JSONObject dateEntry = new JSONObject();
+ dateEntry.put("date", entry.getKey());
+ dateEntry.put("count", entry.getValue());
+ finalResultArr.put(dateEntry);
+ }
+
+ } catch (Exception exc) {
+ LOG.warn(AaiUiMsgs.ERROR_BUILDING_SEARCH_RESPONSE, exc.getLocalizedMessage());
+ }
+
+ return finalResult.put("result", finalResultArr);
+ }
+
+ /**
+ * Format table output
+ *
+ * @param results The results
+ * @return The JSON object
+ * @throws JsonProcessingException The JSON processing exception
+ */
+ public JSONObject formatTableOutput(String results) throws JsonProcessingException {
+ JsonNode resultNode = null;
+
+ JSONObject finalResult = new JSONObject();
+ JSONArray entitiesArr = new JSONArray();
+
+ Map<String, Long> entityCountInTable = initializeEntityMap();
+
+ long vnfCount = 0;
+
+ try {
+ resultNode = mapper.readTree(results);
+
+ final JsonNode bucketsNode = getBucketsNode(resultNode);
+ if (bucketsNode.isArray()) {
+
+ for (final JsonNode entityNode : bucketsNode) {
+ String entityType = entityNode.get("key").asText();
+ boolean isAVnf = vnfEntityTypes.contains(entityType);
+ long countValue = 0;
+
+ if (isAVnf || entityCountInTable.get(entityType) != null) {
+ final JsonNode hitsBucketNode = entityNode.get("sort_by_date").get("hits").get("hits");
+ if (hitsBucketNode.isArray()) {
+ // the first bucket will be the latest
+ final JsonNode hitNode = hitsBucketNode.get(0);
+
+ countValue = hitNode.get("_source").get("count").asLong();
+
+ /*
+ * Special case: Add all the VNF types together to get aggregate count
+ */
+ if (summarizeVnfs && isAVnf) {
+ vnfCount += countValue;
+ countValue = vnfCount;
+ entityType = "vnf";
+ }
+
+ entityCountInTable.replace(entityType, countValue);
+ }
+ }
+
+ }
+ }
+ for (Entry<String, Long> entry : entityCountInTable.entrySet()) {
+ JSONObject entityType = new JSONObject();
+ entityType.put("key", entry.getKey());
+ entityType.put("doc_count", entry.getValue());
+ entitiesArr.put(entityType);
+ }
+
+ finalResult.put("result", entitiesArr);
+
+ } catch (Exception exc) {
+ LOG.warn(AaiUiMsgs.ERROR_BUILDING_RESPONSE_FOR_TABLE_QUERY, exc.getLocalizedMessage());
+ }
+
+ return finalResult;
+ }
+
+ /**
+ * Gets the results
+ *
+ * @param response The response
+ * @param type The type
+ * @return The results
+ */
+ public OperationResult getResults(Response response, String type) {
+ OperationResult operationResult = new OperationResult();
+
+ String reqPayload = EntityHistoryQueryBuilder.getQuery(type).toString();
+
+ try {
+ final String fullUrlStr = elasticSearchAdapter
+ .buildElasticSearchUrlForApi(entityCountHistoryIndexName, SEARCH_PRETTY_STRING);
+
+ OperationResult opResult = elasticSearchAdapter.doPost(fullUrlStr, reqPayload,
+ javax.ws.rs.core.MediaType.APPLICATION_JSON_TYPE);
+
+ JSONObject finalOutput = null;
+ if (type.equalsIgnoreCase(TABLE)) {
+ finalOutput = formatTableOutput(opResult.getResult());
+ } else if (type.equalsIgnoreCase(GRAPH)) {
+ finalOutput = formatLineGraphOutput(opResult.getResult());
+ }
+
+ if (finalOutput != null) {
+ response.setEntity(finalOutput.toString(), MediaType.APPLICATION_JSON);
+ operationResult.setResult(finalOutput.toString());
+ }
+ } catch (JsonProcessingException exc) {
+ restletUtils.handleRestletErrors(LOG, "Unable to map JSONpayload", exc, response);
+ }
+
+ return operationResult;
+ }
+
+ /**
+ * Gets the buckets node
+ *
+ * @param node The node
+ * @return The buckets node
+ * @throws Exception The exception
+ */
+ public JsonNode getBucketsNode(JsonNode node) throws Exception {
+ if (node.get("aggregations").get("group_by_entityType").get("buckets") != null) {
+ return node.get("aggregations").get("group_by_entityType").get("buckets");
+ } else {
+ throw new Exception("Failed to map JSON response");
+ }
+ }
+
+ /**
+ * Initialize entity map
+ *
+ * @return the map
+ */
+ private Map<String, Long> initializeEntityMap() {
+ Map<String, Long> entityMap = new HashMap<String, Long>();
+ for (String entity : entityTypesToSummarize) {
+ entityMap.put(entity, (long) 0);
+ }
+
+ return entityMap;
+ }
+
+ /**
+ * Extracts the "type" query parameter from the request URI
+ *
+ * @param exchange
+ * @return String containing the value of the "type" query parameter of the request. Returns null
+ * if no "type" parameter found
+ */
+ public String getTypeParameter(Exchange exchange) {
+ String typeParameter = null;
+
+ String requestUriParameterString = exchange.getIn().getHeader("CamelHttpQuery", String.class);
+
+ if (null != requestUriParameterString) {
+ String[] requestParameterParts = requestUriParameterString.split("&");
+
+ String[] parameter = requestParameterParts[0].split("=");
+ String currentParameterKey = parameter[0];
+
+ if (null != currentParameterKey && !currentParameterKey.isEmpty()) {
+ // Check if we're looking at the "type" parameter key
+ if (currentParameterKey.equals(TYPE)) {
+ boolean uriIncludesTypeParameterValue =
+ (parameter.length >= 2) && !parameter[1].isEmpty();
+
+ if (uriIncludesTypeParameterValue) {
+ String typeParameterValue = parameter[1];
+
+ // Is the parameter value one that we return data for?
+ if (typeParameterValue.equalsIgnoreCase(TABLE)
+ || typeParameterValue.equalsIgnoreCase(GRAPH)) {
+ typeParameter = typeParameterValue;
+ }
+ }
+ }
+ }
+ }
+
+ return typeParameter;
+ }
+
+
+ public void setRestletUtils(RestletUtils restletUtils) {
+ this.restletUtils = restletUtils;
+ }
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/EntityTypeSummary.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/EntityTypeSummary.java
new file mode 100644
index 0000000..b36753e
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/EntityTypeSummary.java
@@ -0,0 +1,53 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.search;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class EntityTypeSummary {
+ private int totalChartHits;
+ private List<EntityTypeSummaryBucket> buckets = new ArrayList<>();
+
+ public int getTotalChartHits() {
+ return totalChartHits;
+ }
+
+ public List<EntityTypeSummaryBucket> getBuckets() {
+ return buckets;
+ }
+
+ public void setTotalChartHits(int totalChartHits) {
+ this.totalChartHits = totalChartHits;
+ }
+
+ public void setBuckets(List<EntityTypeSummaryBucket> buckets) {
+ this.buckets = buckets;
+ }
+
+ public void addBucket(EntityTypeSummaryBucket bucket) {
+ this.buckets.add(bucket);
+ }
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/EntityTypeSummaryBucket.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/EntityTypeSummaryBucket.java
new file mode 100644
index 0000000..9568232
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/EntityTypeSummaryBucket.java
@@ -0,0 +1,46 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.search;
+
+public class EntityTypeSummaryBucket {
+ private int count;
+ private String key;
+
+ public int getCount() {
+ return count;
+ }
+
+ public String getKey() {
+ return key;
+ }
+
+ public void setCount(int count) {
+ this.count = count;
+ }
+
+ public void setKey(String key) {
+ this.key = key;
+ }
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/SearchEntityProperties.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/SearchEntityProperties.java
new file mode 100644
index 0000000..c790bb1
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/SearchEntityProperties.java
@@ -0,0 +1,49 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.search;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class SearchEntityProperties {
+ private String type;
+ private Map<String, String> fields = new HashMap<>();
+
+ public String getType() {
+ return type;
+ }
+
+ public Map<String, String> getFields() {
+ return fields;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ public void setFields(Map<String, String> field) {
+ this.fields = field;
+ }
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/SearchResponse.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/SearchResponse.java
new file mode 100644
index 0000000..201c154
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/SearchResponse.java
@@ -0,0 +1,102 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.search;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.onap.aai.sparky.search.entity.SearchSuggestion;
+
+/**
+ * The Class SearchResponse.
+ */
+public class SearchResponse {
+
+ private long processingTimeInMs;
+ private int totalFound;
+
+ private List<SearchSuggestion> suggestions;
+
+ /**
+ * Instantiates a new search response.
+ */
+ public SearchResponse() {
+ this.suggestions = new ArrayList<SearchSuggestion>();
+ this.processingTimeInMs = 0;
+ this.totalFound = 0;
+ }
+
+ public long getProcessingTimeInMs() {
+ return processingTimeInMs;
+ }
+
+ public void setProcessingTimeInMs(long processingTimeInMs) {
+ this.processingTimeInMs = processingTimeInMs;
+ }
+
+ public int getTotalFound() {
+ return totalFound;
+ }
+
+ public void setTotalFound(int totalFound) {
+ this.totalFound = totalFound;
+ }
+
+ public List<SearchSuggestion> getSuggestions() {
+ return suggestions;
+ }
+
+ public void setSuggestions(List<SearchSuggestion> suggestions) {
+ this.suggestions = suggestions;
+ }
+
+ /**
+ * Adds the entity entry.
+ *
+ * @param suggestionEntry that will be converted to JSON
+ */
+ public void addSuggestion(SearchSuggestion suggestionEntity){
+ suggestions.add(suggestionEntity);
+ }
+
+ /**
+ * Increments the total number of hits for this SearchResponse by
+ * the value passed in.
+ *
+ * @param additionalCount - Count to increment the total found
+ */
+ public void addToTotalFound(int additionalCount) {
+ totalFound += additionalCount;
+ }
+
+ @Override
+ public String toString() {
+ return "SearchResponse [processingTimeInMs=" + processingTimeInMs + ", totalFound=" + totalFound
+ + ", " + (suggestions != null ? "suggestions=" + suggestions : "") + "]";
+ }
+
+
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/SearchServiceAdapter.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/SearchServiceAdapter.java
new file mode 100644
index 0000000..d37997a
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/SearchServiceAdapter.java
@@ -0,0 +1,139 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.search;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.ws.rs.core.MediaType;
+
+import org.onap.aai.cl.mdc.MdcContext;
+import org.onap.aai.restclient.client.Headers;
+import org.onap.aai.restclient.client.OperationResult;
+import org.onap.aai.restclient.client.RestClient;
+import org.onap.aai.sparky.dal.rest.RestClientFactory;
+import org.onap.aai.sparky.dal.rest.config.RestEndpointConfig;
+import org.slf4j.MDC;
+
+
+/**
+ * The Class SearchServiceAdapter.
+ */
+public class SearchServiceAdapter {
+
+ private static final String VALUE_QUERY = "query";
+
+ private RestClient client;
+ private RestEndpointConfig endpointConfig;
+ private String serviceApiVersion;
+
+ private Map<String, List<String>> commonHeaders;
+
+ /**
+ * Instantiates a new search adapter.
+ * @throws Exception
+ */
+ public SearchServiceAdapter(RestEndpointConfig endpointConfig, String serviceApiVersion) throws Exception {
+
+ client = RestClientFactory.buildClient(endpointConfig);
+
+ commonHeaders = new HashMap<String, List<String>>();
+ commonHeaders.put("Accept", Arrays.asList("application/json"));
+ commonHeaders.put(Headers.FROM_APP_ID, Arrays.asList("AAI-UI"));
+
+ this.serviceApiVersion = serviceApiVersion;
+ this.endpointConfig = endpointConfig;
+ }
+
+ public String getServiceApiVersion() {
+ return serviceApiVersion;
+ }
+
+ public void setServiceApiVersion(String serviceApiVersion) {
+ this.serviceApiVersion = serviceApiVersion;
+ }
+
+ public RestEndpointConfig getEndpointConfig() {
+ return endpointConfig;
+ }
+
+ public void setEndpointConfig(RestEndpointConfig endpointConfig) {
+ this.endpointConfig = endpointConfig;
+ }
+
+ public OperationResult doPost(String url, String jsonPayload, String acceptContentType) {
+ OperationResult or = client.post(url, jsonPayload, getTxnHeader(),
+ MediaType.APPLICATION_JSON_TYPE, MediaType.APPLICATION_JSON_TYPE);
+ return new OperationResult(or.getResultCode(), or.getResult());
+ }
+
+ public OperationResult doGet(String url, String acceptContentType) {
+ OperationResult or =
+ client.get(url, getTxnHeader(), MediaType.APPLICATION_JSON_TYPE);
+ return new OperationResult(or.getResultCode(), or.getResult());
+ }
+
+ public OperationResult doPut(String url, String payload, String acceptContentType) {
+ OperationResult or = client.put(url, payload, getTxnHeader(),
+ MediaType.APPLICATION_JSON_TYPE, MediaType.APPLICATION_JSON_TYPE);
+ return new OperationResult(or.getResultCode(), or.getResult());
+ }
+
+ public OperationResult doDelete(String url, String acceptContentType) {
+
+ OperationResult or =
+ client.delete(url, getTxnHeader(), MediaType.APPLICATION_JSON_TYPE);
+ return new OperationResult(or.getResultCode(), or.getResult());
+ }
+
+ public Map<String, List<String>> getTxnHeader() {
+ HashMap<String, List<String>> headers = new HashMap<String, List<String>>();
+ headers.putAll(this.commonHeaders);
+ headers.put("X-TransactionId", Arrays.asList(MDC.get(MdcContext.MDC_REQUEST_ID)));
+ headers.put("X-FromAppId", Arrays.asList(MDC.get(MdcContext.MDC_PARTNER_NAME)));
+ return headers;
+ }
+
+ /**
+ * Get Full URL for search
+ *
+ * @param api the api
+ * @param indexName
+ * @return the full url
+ */
+ public String buildSearchServiceQueryUrl(String indexName) {
+ return buildSearchServiceUrlForApi(indexName, VALUE_QUERY);
+ }
+
+ public String buildSearchServiceUrlForApi(String indexName, String api) {
+ return String.format("https://%s:%s/services/search-data-service/%s/search/indexes/%s/%s",
+ endpointConfig.getEndpointIpAddress(), endpointConfig.getEndpointServerPort(),
+ serviceApiVersion, indexName, api);
+ }
+
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/UnifiedSearchProcessor.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/UnifiedSearchProcessor.java
new file mode 100644
index 0000000..dfe9016
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/UnifiedSearchProcessor.java
@@ -0,0 +1,188 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.search;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.TreeMap;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.camel.Exchange;
+import org.onap.aai.cl.api.Logger;
+import org.onap.aai.cl.eelf.LoggerFactory;
+import org.onap.aai.sparky.logging.AaiUiMsgs;
+import org.onap.aai.sparky.logging.util.ServletUtils;
+import org.onap.aai.sparky.search.api.SearchProvider;
+import org.onap.aai.sparky.search.entity.QuerySearchEntity;
+import org.onap.aai.sparky.search.entity.SearchSuggestion;
+import org.onap.aai.sparky.search.registry.SearchProviderRegistry;
+import org.onap.aai.sparky.util.NodeUtils;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+public class UnifiedSearchProcessor {
+
+ protected static final String HASH_ID_KEY = "hashId";
+
+ private static final Logger LOG =
+ LoggerFactory.getInstance().getLogger(UnifiedSearchProcessor.class);
+
+ protected SearchProviderRegistry searchProviderRegistry;
+ protected ObjectMapper mapper;
+ protected boolean useOrderedSearchProviderKeys;
+
+ public UnifiedSearchProcessor() {
+ mapper = new ObjectMapper();
+ this.useOrderedSearchProviderKeys = false;
+ }
+
+ public boolean isUseOrderedSearchProviderKeys() {
+ return useOrderedSearchProviderKeys;
+ }
+
+ public void setUseOrderedSearchProviderKeys(boolean useOrderedSearchProviderKeys) {
+ this.useOrderedSearchProviderKeys = useOrderedSearchProviderKeys;
+ }
+
+ public void search(Exchange exchange) {
+ HttpServletRequest request = exchange.getIn().getBody(HttpServletRequest.class);
+ ServletUtils.setUpMdcContext(exchange, request);
+
+ SearchResponse searchResponse = new SearchResponse();
+ long processTime = System.currentTimeMillis();
+ int totalAdded = 0;
+
+ try {
+
+ String payload = exchange.getIn().getBody(String.class);
+
+ if (payload == null || payload.isEmpty()) {
+
+ LOG.error(AaiUiMsgs.SEARCH_SERVLET_ERROR, "Request Payload is empty");
+ exchange.getOut().setHeader(Exchange.HTTP_RESPONSE_CODE, 404);
+ return;
+
+ } else {
+
+ QuerySearchEntity searchRequest = mapper.readValue(payload, QuerySearchEntity.class);
+ int maxResultsPerSearch = Integer.valueOf(searchRequest.getMaxResults());
+
+ Map<String, List<SearchSuggestion>> searchProviderSuggestions =
+ new HashMap<String, List<SearchSuggestion>>();
+
+ int totalSuggestionsFromProviders = 0;
+ List<SearchSuggestion> suggestions = null;
+ for (SearchProvider searchProvider : searchProviderRegistry.getSearchProviders()) {
+ suggestions = searchProvider.search(searchRequest);
+ totalSuggestionsFromProviders += suggestions.size();
+ searchProviderSuggestions.put(searchProvider.getClass().getCanonicalName(), suggestions);
+ }
+
+ /*
+ * Using ordered search provider keys allows us to deterministically calculate how many
+ * results from each provider should be returned. At the moment, this behavior is primarily
+ * only beneficial to test classes. As there is a cost to sorted-collections in the call
+ * processing path, this behavior has been made optional.
+ */
+
+ if (useOrderedSearchProviderKeys) {
+ searchProviderSuggestions =
+ new TreeMap<String, List<SearchSuggestion>>(searchProviderSuggestions);
+ }
+
+ if (totalSuggestionsFromProviders > 0) {
+
+ int suggestionIndex = 0;
+
+ Set<Entry<String, List<SearchSuggestion>>> searchProviderResults =
+ searchProviderSuggestions.entrySet();
+
+ while (totalAdded < maxResultsPerSearch && (totalAdded < totalSuggestionsFromProviders)) {
+
+ for (Entry<String, List<SearchSuggestion>> searchProviderResultList : searchProviderResults) {
+
+ if ((suggestionIndex <= (searchProviderResultList.getValue().size() - 1))) {
+
+ if (totalAdded < maxResultsPerSearch) {
+ searchResponse
+ .addSuggestion(searchProviderResultList.getValue().get(suggestionIndex));
+ totalAdded++;
+ }
+ }
+
+ }
+
+ suggestionIndex++;
+
+ }
+
+ }
+
+ }
+
+ searchResponse.addToTotalFound(totalAdded);
+
+ processTime = System.currentTimeMillis() - processTime;
+ searchResponse.setProcessingTimeInMs(processTime);
+ String searchResponseJson = NodeUtils.convertObjectToJson(searchResponse, true);
+ exchange.getOut().setHeader(Exchange.HTTP_RESPONSE_CODE, 200);
+ exchange.getOut().setBody(searchResponseJson);
+
+ } catch (Exception exc) {
+ LOG.error(AaiUiMsgs.ERROR_PROCESSING_REQUEST, exc);
+
+ exchange.getOut().setHeader(Exchange.HTTP_RESPONSE_CODE, 500);
+ exchange.getOut().setBody(
+ ServletUtils.generateJsonErrorResponse("Processing error = " + exc.getMessage()),
+ String.class);
+
+ } finally {
+ /*
+ * Restore the txnId + appId from the current thread local via the MdcContext
+ */
+
+ ServletUtils.getTxnHeaders().forEach((key, value) -> {
+ exchange.getOut().setHeader(key, value);
+ });
+
+ exchange.getOut().setHeader("RequestUrl", request.getRequestURI());
+ exchange.getOut().setHeader("RequestPort", request.getLocalPort());
+
+ }
+ }
+
+ public SearchProviderRegistry getSearchProviderRegistry() {
+ return searchProviderRegistry;
+ }
+
+ public void setSearchProviderRegistry(SearchProviderRegistry searchProviderRegistry) {
+ this.searchProviderRegistry = searchProviderRegistry;
+ }
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/api/SearchProvider.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/api/SearchProvider.java
new file mode 100644
index 0000000..923c4d6
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/api/SearchProvider.java
@@ -0,0 +1,36 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.search.api;
+
+import java.util.List;
+
+import org.onap.aai.sparky.search.entity.QuerySearchEntity;
+import org.onap.aai.sparky.search.entity.SearchSuggestion;
+
+public interface SearchProvider {
+
+ List<SearchSuggestion> search(QuerySearchEntity queryRequest);
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/config/SuggestionConfig.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/config/SuggestionConfig.java
new file mode 100644
index 0000000..070f305
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/config/SuggestionConfig.java
@@ -0,0 +1,76 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.search.config;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+public class SuggestionConfig {
+
+
+ private Map<String, String> pairingList;
+ private Collection<String> stopWords;
+ private String defaultPairingValue;
+ private String ViSuggestionRoute;
+
+
+ public SuggestionConfig() {}
+
+
+ public Collection<String> getStopWords() {
+ return stopWords;
+ }
+
+ public void setStopWords(Collection<String> stopWords) {
+ this.stopWords = stopWords;
+ }
+
+ public Map<String, String> getPairingList() {
+ return pairingList;
+ }
+
+ public void setPairingList(HashMap<String, String> pairingList) {
+ this.pairingList = pairingList;
+ }
+
+ public String getDefaultPairingValue() {
+ return defaultPairingValue;
+ }
+
+ public void setDefaultPairingValue(String defaultPairingValue) {
+ this.defaultPairingValue = defaultPairingValue;
+ }
+
+ public String getViSuggestionRoute() {
+ return ViSuggestionRoute;
+ }
+
+ public void setViSuggestionRoute(String ViSuggestionRoute) {
+ this.ViSuggestionRoute = ViSuggestionRoute;
+ }
+
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/entity/QuerySearchEntity.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/entity/QuerySearchEntity.java
new file mode 100644
index 0000000..37059fb
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/entity/QuerySearchEntity.java
@@ -0,0 +1,73 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.search.entity;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+
+/**
+ * The Class ViewAndInspectSearchRequest.
+ */
+public class QuerySearchEntity {
+
+ private static final String DEFAULT_MAX_RESULTS = "10";
+ public String maxResults;
+ public String queryStr;
+
+ /**
+ * Instantiates a new view and inspect search request.
+ */
+ public QuerySearchEntity() {
+ maxResults = DEFAULT_MAX_RESULTS;
+ queryStr = null;
+ }
+
+ public String getMaxResults() {
+ return maxResults;
+ }
+
+ public void setMaxResults(String maxResults) {
+ this.maxResults = maxResults;
+ }
+
+ public String getQueryStr() {
+ return queryStr;
+ }
+
+ public void setQueryStr(String queryStr) {
+ this.queryStr = queryStr;
+ }
+
+ @JsonIgnore
+ public String[] getSearchTerms() {
+
+ if (queryStr == null) {
+ return null;
+ }
+
+ return queryStr.split(" ");
+
+ }
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/entity/SearchSuggestion.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/entity/SearchSuggestion.java
new file mode 100644
index 0000000..4529af5
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/entity/SearchSuggestion.java
@@ -0,0 +1,39 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.search.entity;
+
+public interface SearchSuggestion {
+ public String getHashId();
+
+ public void setHashId(String hashId);
+
+ public String getRoute();
+
+ public void setRoute(String route);
+
+ public String getText();
+
+ public void setText(String searchText);
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/FilterElasticSearchAdapter.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/FilterElasticSearchAdapter.java
new file mode 100644
index 0000000..3a01e2b
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/FilterElasticSearchAdapter.java
@@ -0,0 +1,119 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.search.filters;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.json.JsonObject;
+import javax.ws.rs.core.MediaType;
+
+import org.json.JSONArray;
+import org.json.JSONObject;
+import org.onap.aai.cl.api.Logger;
+import org.onap.aai.cl.eelf.LoggerFactory;
+import org.onap.aai.restclient.client.OperationResult;
+import org.onap.aai.sparky.dal.ElasticSearchAdapter;
+import org.onap.aai.sparky.logging.AaiUiMsgs;
+import org.onap.aai.sparky.search.filters.config.UiFilterDataSourceConfig;
+import org.onap.aai.sparky.search.filters.entity.UiFilterEntity;
+import org.onap.aai.sparky.viewandinspect.config.SparkyConstants;
+
+
+/**
+ * Performs all Elasticsearch related queries for filters related to
+ * the Sparky-FE.
+ *
+ * @author RICHARV
+ */
+public class FilterElasticSearchAdapter {
+
+ private static final Logger LOG = LoggerFactory.getInstance().getLogger(FilterElasticSearchAdapter.class);
+ private static final String AGGS = "aggregations";
+ private static final String CONTAINER = "default";
+ private static final String BUCKETS = "buckets";
+ private static final String FILTER_VALUE_KEY = "key";
+ private ElasticSearchAdapter elasticSearchAdapter;
+
+ public FilterElasticSearchAdapter(ElasticSearchAdapter elasticSearchAdapter) {
+ this.elasticSearchAdapter = elasticSearchAdapter;
+ }
+
+ /**
+ * For a given UiFilterEntity, will attempt to contact an Elasticsearch instance
+ * and fetch all possible values for filter's field name.
+ *
+ * @param filter - Filter object against which the search will take place.
+ * @param sourceData - If present, contains the index name and field value to search against.
+ * @return - A List of strings if results were found, else empty list.
+ */
+ public List<String> fetchValuesForFilter(UiFilterEntity filter, UiFilterDataSourceConfig dataSourceConfig) {
+ ArrayList<String> filterValues = new ArrayList<String>();
+
+ if(dataSourceConfig != null) {
+ JsonObject filterValueQuery = null;
+ if(dataSourceConfig.getPathToField() != null) {
+ filterValueQuery = FilterQueryBuilder.createNestedFilterValueQueryObject(dataSourceConfig.getFieldName(), dataSourceConfig.getPathToField());
+ } else {
+ filterValueQuery = FilterQueryBuilder.createFilterValueQueryObject(dataSourceConfig.getFieldName());
+ }
+
+ OperationResult opResult = elasticSearchAdapter.doPost(
+ elasticSearchAdapter.buildElasticSearchUrlForApi(dataSourceConfig.getIndexName(),
+ SparkyConstants.ES_SEARCH_API),
+ filterValueQuery.toString(), MediaType.APPLICATION_JSON_TYPE);
+
+ String result = opResult.getResult();
+ if(opResult.wasSuccessful() && result != null) {
+ JSONObject responseJson = new JSONObject(result);
+ JSONObject aggJson = responseJson.getJSONObject(AGGS);
+
+ JSONObject containerJson = null;
+ if(dataSourceConfig.getPathToField() != null) {
+ JSONObject nestedContainer = aggJson.getJSONObject(dataSourceConfig.getPathToField());
+ containerJson = nestedContainer.getJSONObject(dataSourceConfig.getFieldName());
+ } else {
+ containerJson = aggJson.getJSONObject(CONTAINER);
+ }
+
+ JSONArray buckets = containerJson.getJSONArray(BUCKETS);
+
+ int bucketLength = buckets.length();
+ for(int i = 0; i < bucketLength; i++) {
+ JSONObject filterBucket = buckets.getJSONObject(i);
+
+ String filterValue = filterBucket.getString(FILTER_VALUE_KEY);
+ if(filterValue != null && !filterValue.isEmpty()) {
+ filterValues.add(filterValue);
+ }
+ }
+ } else {
+ LOG.error(AaiUiMsgs.ERROR_FETCHING_FILTER_VALUES, String.valueOf(opResult.getResultCode()), filter.getFilterName());
+ }
+ }
+ filterValues.sort(String::compareToIgnoreCase);
+ return filterValues;
+ }
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/FilterProcessor.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/FilterProcessor.java
new file mode 100644
index 0000000..9d404a9
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/FilterProcessor.java
@@ -0,0 +1,144 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.search.filters;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.json.JsonObject;
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.camel.Exchange;
+import org.onap.aai.cl.api.Logger;
+import org.onap.aai.cl.eelf.LoggerFactory;
+import org.onap.aai.sparky.logging.AaiUiMsgs;
+import org.onap.aai.sparky.logging.util.ServletUtils;
+import org.onap.aai.sparky.search.filters.entity.UiFilterEntity;
+import org.onap.aai.sparky.search.filters.entity.UiFiltersEntity;
+import org.onap.aai.sparky.viewandinspect.config.SparkyConstants;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+public class FilterProcessor {
+
+ private static final Logger LOG = LoggerFactory.getInstance().getLogger(FilterProcessor.class);
+
+ private ObjectMapper mapper;
+ private FilteredSearchHelper filteredSearchHelper;
+
+ public FilterProcessor() {
+ this.mapper = new ObjectMapper();
+ }
+
+ public ObjectMapper getMapper() {
+ return mapper;
+ }
+
+ public FilteredSearchHelper getFilteredSearchHelper() {
+ return filteredSearchHelper;
+ }
+
+ public void setFilteredSearchHelper(FilteredSearchHelper filteredSearchHelper) {
+ this.filteredSearchHelper = filteredSearchHelper;
+ }
+
+ public void getFiltersWithValues(Exchange exchange) {
+
+ HttpServletRequest request = exchange.getIn().getBody(HttpServletRequest.class);
+ ServletUtils.setUpMdcContext(exchange, request);
+
+ UiFiltersEntity viewFiltersList = null;
+ boolean wasErrorDuringFilterDiscovery = false;
+
+ try {
+ String payload = exchange.getIn().getBody(String.class);
+
+ if (payload == null || payload.isEmpty()) {
+ /* Don't throw back an error, just return an empty set */
+ LOG.error(AaiUiMsgs.SEARCH_SERVLET_ERROR, "Request Payload is empty");
+ wasErrorDuringFilterDiscovery = true;
+ } else {
+ String viewName = mapper.readValue(payload, JsonNode.class).get(SparkyConstants.UI_FILTER_VIEW_NAME_PARAMETER).asText();
+
+ if (viewName == null || viewName.isEmpty()) {
+ wasErrorDuringFilterDiscovery = true;
+ } else {
+ viewFiltersList = filteredSearchHelper.doFilterDiscovery(viewName);
+ }
+ }
+ } catch(Exception exc) {
+ LOG.error(AaiUiMsgs.ERROR_GENERIC, "FilterProcessor failed to get filter list due to error = " + exc.getMessage());
+
+ exchange.getOut().setHeader(Exchange.HTTP_RESPONSE_CODE, 500);
+
+ exchange.getOut().setBody(
+ ServletUtils.generateJsonErrorResponse("FilterProcessor failed to get filter list due to error = " + exc.getMessage()),
+ String.class);
+
+ return;
+ }
+
+ boolean wasErrorDuringValueSearch = false;
+ if(!wasErrorDuringFilterDiscovery) {
+ try {
+ if(!viewFiltersList.getFilters().isEmpty()) {
+ List<String> filterIds = new ArrayList<String>();
+
+ for(UiFilterEntity filterEntity : viewFiltersList.getFilters()) {
+ filterIds.add(filterEntity.getFilterId());
+ }
+
+ UiFiltersEntity responseFiltersList = filteredSearchHelper.doFilterEnumeration(filterIds);
+
+ JsonObject finalResponse = UiFiltersEntityConverter.convertUiFiltersEntityToUnifiedFilterResponse(responseFiltersList);
+ exchange.getOut().setHeader(Exchange.HTTP_RESPONSE_CODE, 200);
+ exchange.getOut().setBody(finalResponse.toString());
+ } else {
+ wasErrorDuringValueSearch = true;
+ }
+ } catch(Exception exc) {
+ LOG.error(AaiUiMsgs.ERROR_GENERIC, "FilterProcessor failed to generate valid unifiedFilterRequest response due to error, " + exc.getMessage());
+
+ exchange.getOut().setHeader(Exchange.HTTP_RESPONSE_CODE, 500);
+
+ exchange.getOut().setBody(
+ ServletUtils.generateJsonErrorResponse("FilterProcessor failed to generate valid unifiedFilterRequest response due to error = " + exc.getMessage()),
+ String.class);
+
+ return;
+ }
+ }
+
+ // In the case of an error we want to respond with a valid empty response
+ if(wasErrorDuringFilterDiscovery || wasErrorDuringValueSearch) {
+ //response.setStatus(Status.SUCCESS_OK);
+ //response.setEntity(UiFiltersEntityConverter.generateEmptyResponse().toString(), MediaType.APPLICATION_JSON);
+ exchange.getOut().setHeader(Exchange.HTTP_RESPONSE_CODE, 404);
+ exchange.getOut().setBody(UiFiltersEntityConverter.generateEmptyResponse().toString());
+ }
+ }
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/FilterQueryBuilder.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/FilterQueryBuilder.java
new file mode 100644
index 0000000..41a7b91
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/FilterQueryBuilder.java
@@ -0,0 +1,218 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.search.filters;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.json.Json;
+import javax.json.JsonArrayBuilder;
+import javax.json.JsonObject;
+import javax.json.JsonObjectBuilder;
+
+import org.onap.aai.sparky.search.filters.config.FiltersConfig;
+import org.onap.aai.sparky.search.filters.config.UiFilterConfig;
+import org.onap.aai.sparky.search.filters.entity.AggregationEntity;
+import org.onap.aai.sparky.search.filters.entity.BoolQueryBuilder;
+import org.onap.aai.sparky.search.filters.entity.FilteredAggregationQueryBuilder;
+import org.onap.aai.sparky.search.filters.entity.MatchFilterCriteriaEntity;
+import org.onap.aai.sparky.search.filters.entity.SearchFilter;
+
+/**
+ * Used to generate queries against Elasticsearch for filter related queries.
+ */
+public class FilterQueryBuilder {
+
+ private static final int EXISTING_FILTERS_LIMIT = 0;
+ private static final int SHOULD_BRANCH_LIMIT = 2;
+
+ public static JsonObject createFilteredBoolQueryObject(FiltersConfig filtersConfig, List<SearchFilter> searchFilters, int minShouldMatch, List<String> fields) {
+
+ if (searchFilters == null || searchFilters.size() == 0) {
+ return null;
+ }
+
+ int searchFilterValueSize = 0;
+
+ BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
+
+ for (SearchFilter searchFilter : searchFilters) {
+
+ searchFilterValueSize = searchFilter.getValues().size();
+
+ /*
+ * translate the filter-id into the filter-name from the oxm data model/config file
+ */
+ UiFilterConfig filter = filtersConfig.getFilterById(searchFilter.getFilterId());
+
+ if (filter == null || filter.getFilterName() == null) {
+ // log error and continue
+ } else {
+
+ String fieldName = filter.getDataSource().getFieldName();
+ if(!fields.contains(fieldName)) {
+ fields.add(fieldName);
+ }
+
+ if (searchFilterValueSize >= SHOULD_BRANCH_LIMIT) {
+ // Add should branches
+ for (String filterValue : searchFilter.getValues()) {
+ boolQueryBuilder.addShouldFilter(new MatchFilterCriteriaEntity(fieldName, filterValue));
+ }
+
+ } else if (searchFilterValueSize > EXISTING_FILTERS_LIMIT) {
+ // Add must branch
+ for (String filterValue : searchFilter.getValues()) {
+ boolQueryBuilder.addMustFilter(new MatchFilterCriteriaEntity(fieldName, filterValue));
+ }
+ }
+ }
+ }
+
+ boolQueryBuilder.setMinShouldMatch(minShouldMatch);
+
+ return boolQueryBuilder.getJsonObject();
+ }
+
+ public static JsonObject createAggregationQueryArray(FiltersConfig filtersConfig, List<SearchFilter> searchFilters) {
+
+ if (searchFilters == null || searchFilters.size() == 0) {
+ // log error
+ return null;
+ }
+
+ FilteredAggregationQueryBuilder aggQueryBuilder = new FilteredAggregationQueryBuilder();
+
+ for (SearchFilter searchFilter : searchFilters) {
+
+ /*
+ * translate the filter-id into the filter-name from the oxm data model/config file
+ */
+ UiFilterConfig filter = filtersConfig.getFilterById(searchFilter.getFilterId());
+
+ if (filter == null || filter.getFilterName() == null) {
+ // log error and continue
+ } else {
+ String fieldName = filter.getDataSource().getFieldName();
+ aggQueryBuilder.addAggregationEntity(new AggregationEntity(fieldName, fieldName, 0));
+ }
+
+ }
+
+ return aggQueryBuilder.getJsonObject();
+ }
+
+ public static JsonObject createCombinedBoolAndAggQuery(FiltersConfig filtersConfig, List<SearchFilter> searchFilters, int minShouldMatch) {
+ JsonObjectBuilder wrappedQueryBuilder = Json.createObjectBuilder();
+ if(searchFilters != null) {
+ List<String> fields = new ArrayList<String>();
+ JsonObject boolQuery = createFilteredBoolQueryObject(filtersConfig,searchFilters, minShouldMatch, fields);
+ JsonObject aggQuery = createAggregationQueryArray(filtersConfig, searchFilters);
+
+ if (boolQuery != null) {
+ wrappedQueryBuilder.add("size", 0);
+
+ JsonArrayBuilder filedsArrayBuilder = Json.createBuilderFactory(null).createArrayBuilder(); // TODO -> Should we use a class instance factory?
+ for(String field : fields) {
+ filedsArrayBuilder.add(field);
+ }
+ wrappedQueryBuilder.add("fields", filedsArrayBuilder.build());
+
+ wrappedQueryBuilder.add("query", boolQuery);
+ }
+
+ if (aggQuery != null) {
+ wrappedQueryBuilder.add("aggs", aggQuery);
+ }
+ }
+ return wrappedQueryBuilder.build();
+ }
+
+ public static JsonObject createFilterValueQueryObject(String fieldValue) {
+ JsonObjectBuilder jsonBuilder = Json.createObjectBuilder();
+ jsonBuilder.add("size", "0"); // avoid source data
+ buildZeroTermSummaryQuery(jsonBuilder, fieldValue);
+
+ return jsonBuilder.build();
+ }
+
+ public static JsonObject createNestedFilterValueQueryObject(String fieldValue,
+ String pathToField) {
+ JsonObjectBuilder jsonBuilder = Json.createObjectBuilder();
+ jsonBuilder.add("size", "0"); // avoid source data
+ generateNestedAggregations(jsonBuilder, fieldValue, pathToField);
+
+ return jsonBuilder.build();
+ }
+
+ public static void buildZeroTermSummaryQuery(JsonObjectBuilder jsonBuilder, String fieldValue) {
+ JsonObjectBuilder aggsBlobBuilder = Json.createObjectBuilder();
+ getSummaryAggsBlob(aggsBlobBuilder, fieldValue, 0);
+ jsonBuilder.add("aggs", aggsBlobBuilder.build());
+ }
+
+ public static void getSummaryAggsBlob(JsonObjectBuilder aggsBlobBuilder, String fieldValue,
+ int resultSize) {
+ JsonObjectBuilder fieldBuilder =
+ Json.createObjectBuilder().add("field", fieldValue).add("size", resultSize);
+ JsonObject aggsFieldBlob = fieldBuilder.build();
+ JsonObjectBuilder defaultBlobBuilder = Json.createObjectBuilder().add("terms", aggsFieldBlob);
+ JsonObject defaultBlob = defaultBlobBuilder.build();
+ aggsBlobBuilder.add("default", defaultBlob);
+ }
+
+ public static void addNestedSummaryAggsBlob(JsonObjectBuilder nestedAggsBuilder,
+ String containerValue, String fieldValue, int resultSize) {
+ JsonObjectBuilder fieldBuilder = Json.createObjectBuilder()
+ .add("field", containerValue + "." + fieldValue).add("size", resultSize);
+ JsonObject aggsFieldObject = fieldBuilder.build();
+
+ JsonObjectBuilder termBuilder = Json.createObjectBuilder().add("terms", aggsFieldObject);
+ JsonObject termObject = termBuilder.build();
+
+ JsonObjectBuilder namedAggsBuilder = Json.createObjectBuilder().add(fieldValue, termObject);
+ JsonObject namedAggsObject = namedAggsBuilder.build();
+
+ nestedAggsBuilder.add("aggs", namedAggsObject);
+ }
+
+ public static void generateNestedAggregations(JsonObjectBuilder jsonBuilder, String fieldValue,
+ String pathToField) {
+ JsonObjectBuilder nestedAggsBuilder = Json.createObjectBuilder();
+
+ JsonObjectBuilder pathObjectBuilder = Json.createObjectBuilder().add("path", pathToField);
+ JsonObject nestedPathObject = pathObjectBuilder.build();
+
+ JsonObjectBuilder nestedObjectBuilder =
+ Json.createObjectBuilder().add("nested", nestedPathObject);
+
+ addNestedSummaryAggsBlob(nestedObjectBuilder, pathToField, fieldValue, 0);
+
+ JsonObject nestedObject = nestedObjectBuilder.build();
+ nestedAggsBuilder.add(pathToField, nestedObject);
+
+ jsonBuilder.add("aggs", nestedAggsBuilder.build());
+ }
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/FilteredSearchHelper.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/FilteredSearchHelper.java
new file mode 100644
index 0000000..0e981b4
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/FilteredSearchHelper.java
@@ -0,0 +1,158 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.search.filters;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.onap.aai.cl.api.Logger;
+import org.onap.aai.cl.eelf.LoggerFactory;
+import org.onap.aai.sparky.logging.AaiUiMsgs;
+import org.onap.aai.sparky.search.filters.config.FiltersConfig;
+import org.onap.aai.sparky.search.filters.config.FiltersDetailsConfig;
+import org.onap.aai.sparky.search.filters.config.UiFilterConfig;
+import org.onap.aai.sparky.search.filters.config.UiFilterDataSourceConfig;
+import org.onap.aai.sparky.search.filters.config.UiFilterListItemConfig;
+import org.onap.aai.sparky.search.filters.config.UiViewListItemConfig;
+import org.onap.aai.sparky.search.filters.entity.UiFilterEntity;
+import org.onap.aai.sparky.search.filters.entity.UiFilterValueEntity;
+import org.onap.aai.sparky.search.filters.entity.UiFiltersEntity;
+
+public class FilteredSearchHelper {
+ private static final Logger LOG = LoggerFactory.getInstance().getLogger(FilteredSearchHelper.class);
+
+ private FiltersConfig filtersConfig;
+ private Map<String, UiFilterConfig> filtersMap = null;
+ private FilterElasticSearchAdapter filterSearchAdapter = null;
+
+ public FilteredSearchHelper(FiltersConfig filterConfig,FilterElasticSearchAdapter filterElasticSearchAdapter) {
+ this.filtersConfig = filterConfig;
+ this.filterSearchAdapter = filterElasticSearchAdapter;
+
+ if (filtersMap == null) {
+ filtersMap = new HashMap<>();
+
+ final FiltersDetailsConfig uiFiltersConfig = filterConfig.getFiltersConfig();
+
+ if (uiFiltersConfig != null) {
+ for (UiFilterConfig filter : uiFiltersConfig.getFilters()) {
+ filtersMap.put(filter.getFilterId(), filter);
+ }
+ }
+ }
+
+ }
+
+ public FiltersConfig getFiltersConfig() {
+ return filtersConfig;
+ }
+
+ public void setFiltersConfig(FiltersConfig filterConfig) {
+ this.filtersConfig = filterConfig;
+ }
+
+ public UiFiltersEntity doFilterDiscovery(String viewName) {
+ List<UiViewListItemConfig> views = filtersConfig.getViewsConfig().getViews();
+ List<UiFilterListItemConfig> filters = null;
+ UiFiltersEntity viewFiltersList = new UiFiltersEntity();
+
+ if(viewName != null) {
+ for (UiViewListItemConfig view: views) {
+ if (viewName.equalsIgnoreCase(view.getViewName())) {
+ filters = view.getFilters();
+ break;
+ }
+ }
+
+ if (filters == null) {
+ LOG.error(AaiUiMsgs.VIEW_NAME_NOT_SUPPORTED, viewName);
+ } else {
+ for (UiFilterListItemConfig filter : filters) {
+ FiltersDetailsConfig filtersDetailsConfig = filtersConfig.getFiltersConfig();
+
+ for (UiFilterConfig filterConfig: filtersDetailsConfig.getFilters()) {
+ if (filterConfig.getFilterId().equals(filter.getFilterId())) {
+ UiFilterEntity filterEntity = new UiFilterEntity(filterConfig);
+ if(filter.getDefaultValue() != null) {
+ filterEntity.setDefaultValue(filter.getDefaultValue());
+ }
+ viewFiltersList.addFilter(filterEntity);
+ }
+ }
+ }
+ }
+ }
+ return viewFiltersList;
+ }
+
+ public UiFiltersEntity doFilterEnumeration(List<String> requestedFilterIds) {
+ UiFiltersEntity viewFiltersList = new UiFiltersEntity();
+
+ for (String requestedFilterId : requestedFilterIds) {
+ if (null == filtersMap.get(requestedFilterId)) {
+ String errorMessage = "Requested filter ID '" + requestedFilterId + "' does not exist.";
+ LOG.error(AaiUiMsgs.SEARCH_SERVLET_ERROR, errorMessage);
+ } else {
+ UiFilterConfig sourceData = filtersMap.get(requestedFilterId);
+ UiFilterEntity filterEntity = new UiFilterEntity(sourceData);
+ this.getFilterEnumeration(filterEntity, sourceData);
+ viewFiltersList.addFilter(filterEntity);
+ }
+ }
+
+ return viewFiltersList;
+ }
+
+ public void getFilterEnumeration(UiFilterEntity filter, UiFilterConfig sourceData) {
+ List<String> filterValues = filterSearchAdapter.fetchValuesForFilter(filter, sourceData.getDataSource());
+
+ for(String value : filterValues) {
+ UiFilterValueEntity valueEntity = new UiFilterValueEntity();
+ valueEntity.setDisplayName(value);
+ valueEntity.setFilterValue(value);
+ filter.addFilterValue(valueEntity);
+ }
+ }
+
+ public Map<String, UiFilterConfig> getFiltersMap() {
+ return filtersMap;
+ }
+
+ public void setFiltersMap(Map<String, UiFilterConfig> filtersMap) {
+ this.filtersMap = filtersMap;
+ }
+
+ public UiFilterDataSourceConfig getFilterDataSource(String filterId) {
+ UiFilterConfig filterConfig = filtersMap.get(filterId);
+ UiFilterDataSourceConfig returnValue = null;
+
+ if(filterConfig != null) {
+ returnValue = filterConfig.getDataSource();
+ }
+
+ return returnValue;
+ }
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/UiFiltersEntityConverter.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/UiFiltersEntityConverter.java
new file mode 100644
index 0000000..46f62ac
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/UiFiltersEntityConverter.java
@@ -0,0 +1,180 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.search.filters;
+
+import java.util.List;
+
+import javax.json.Json;
+import javax.json.JsonArray;
+import javax.json.JsonArrayBuilder;
+import javax.json.JsonObject;
+import javax.json.JsonObjectBuilder;
+
+import org.onap.aai.sparky.search.filters.config.UiFilterOptionsValuesConfig;
+import org.onap.aai.sparky.search.filters.entity.UiFilterEntity;
+import org.onap.aai.sparky.search.filters.entity.UiFilterValueEntity;
+import org.onap.aai.sparky.search.filters.entity.UiFiltersEntity;
+
+public class UiFiltersEntityConverter {
+
+ private static final String KEY_TYPE = "type";
+ private static final String KEY_MULTISELECT = "multiSelect";
+ private static final String KEY_WATERMARK = "watermark";
+ private static final String KEY_CONTROLS = "controls";
+ private static final String KEY_LABEL = "label";
+ private static final String KEY_FILTERS = "filters";
+ private static final String KEY_DECODE = "decode";
+ private static final String KEY_CODE = "code";
+ private static final String KEY_DEFAULT_VALUE = "defaultValue";
+
+ /**
+ * Converts a UiFiltersEntity into a JSON object to satisfy a new (as of 23 Oct 2017)
+ * filter library being used in the FE.
+ *
+ * @param entityToConvert - The UiFiltersEntity to be converted into a JSON response.
+ * @return A JsonObject representing the passed in UiFiltersEntity.
+ */
+ public static JsonObject convertUiFiltersEntityToUnifiedFilterResponse(UiFiltersEntity entityToConvert) {
+ JsonObjectBuilder filterBuilder = Json.createObjectBuilder();
+
+ if(entityToConvert != null) {
+ List<UiFilterEntity> filterEntities = entityToConvert.getFilters();
+ if(filterEntities != null) {
+ for(UiFilterEntity entity : filterEntities) {
+ filterBuilder.add(entity.getFilterId(), generateFilterObject(entity));
+ }
+ }
+ }
+
+ JsonObjectBuilder finalObject = Json.createObjectBuilder();
+ finalObject.add(KEY_FILTERS, filterBuilder.build());
+ return finalObject.build();
+ }
+
+ /**
+ * Generates the core body of the a single filter within the JSON body.
+ *
+ * @param entity - The filter entity (loaded from config and populated from data store).
+ * @return A JsonObject representing the core data of a filter.
+ */
+ private static JsonObject generateFilterObject(UiFilterEntity entity) {
+ JsonObjectBuilder filterBuilder = Json.createObjectBuilder();
+
+ filterBuilder.add(KEY_LABEL, entity.getDisplayName());
+ filterBuilder.add(KEY_CONTROLS, generateControlObject(entity, entity.getFilterValueList()));
+
+ return filterBuilder.build();
+ }
+
+ /**
+ * Generates the "controls" object within the filter JSON.
+ *
+ * @param filterEntity - The filter entity on which this filter will be based.
+ * @param filterValues - The list of values associated with the filter
+ * from data store queries.
+ * @return A JsonObject representing the "controls" object of the filter JSON.
+ */
+ private static JsonObject generateControlObject(UiFilterEntity filterEntity, List<UiFilterValueEntity> filterValues) {
+ JsonObjectBuilder controls = Json.createObjectBuilder();
+ JsonObjectBuilder subControl = Json.createObjectBuilder();
+
+ subControl.add(KEY_TYPE, filterEntity.getDataType());
+ subControl.add(KEY_MULTISELECT, filterEntity.getMultiSelect());
+ subControl.add(KEY_WATERMARK, filterEntity.getWatermark());
+
+ if(filterEntity.getDefaultValue() != null && !filterEntity.getDefaultValue().getCode().isEmpty() && !filterEntity.getDefaultValue().getDecode().isEmpty()) {
+ JsonObjectBuilder defaultValueBuilder = Json.createObjectBuilder();
+
+ defaultValueBuilder.add(KEY_DECODE, filterEntity.getDefaultValue().getDecode());
+ defaultValueBuilder.add(KEY_CODE, filterEntity.getDefaultValue().getCode());
+
+ subControl.add(KEY_DEFAULT_VALUE, defaultValueBuilder.build());
+ }
+
+ if(filterEntity.getOptionsValues() == null || filterEntity.getOptionsValues().isEmpty()) {
+ subControl.add(filterEntity.getOptionsType(), generateOptionsObject(filterValues));
+ } else {
+ subControl.add(filterEntity.getOptionsType(), generateOptionsValuesObject(filterEntity.getOptionsValues()));
+ }
+
+ controls.add(filterEntity.getFilterName(), subControl.build());
+
+ return controls.build();
+ }
+
+ /**
+ * Creates a JsonArray representing the list of options for a filter.
+ * Similar to function generateOptionsObject, except using different arguments.
+ *
+ * @param optionsValues - Values that are loaded from config.
+ * @return JsonArray of options for a filter.
+ */
+ private static JsonArray generateOptionsValuesObject(List<UiFilterOptionsValuesConfig> optionsValues) {
+ JsonArrayBuilder optionsBuilder = Json.createArrayBuilder();
+
+ if(optionsValues != null && !optionsValues.isEmpty()) {
+ for(UiFilterOptionsValuesConfig optionValue : optionsValues) {
+ JsonObjectBuilder option = Json.createObjectBuilder();
+
+ option.add(KEY_DECODE, optionValue.getDecode());
+ option.add(KEY_CODE, optionValue.getCode());
+
+ optionsBuilder.add(option.build());
+ }
+ }
+
+ return optionsBuilder.build();
+ }
+
+ /**
+ * Creates a JsonArray representing the list of options for a filter.
+ *
+ * @param filterValues - The list of values associates with a filter (likely from a data store query).
+ * @return JsonArray of options for a filter.
+ */
+ private static JsonArray generateOptionsObject(List<UiFilterValueEntity> filterValues) {
+ JsonArrayBuilder optionsBuilder = Json.createArrayBuilder();
+
+ if(filterValues != null && !filterValues.isEmpty()) {
+ for(UiFilterValueEntity valueEntity : filterValues) {
+ JsonObjectBuilder option = Json.createObjectBuilder();
+
+ option.add(KEY_DECODE, valueEntity.getDisplayName());
+ option.add(KEY_CODE, valueEntity.getFilterValue());
+
+ optionsBuilder.add(option.build());
+ }
+ }
+
+ return optionsBuilder.build();
+ }
+
+ public static JsonObject generateEmptyResponse() {
+ JsonObjectBuilder filterBuilder = Json.createObjectBuilder();
+ JsonObjectBuilder finalObject = Json.createObjectBuilder();
+ finalObject.add(KEY_FILTERS, filterBuilder.build());
+ return finalObject.build();
+ }
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/config/FiltersConfig.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/config/FiltersConfig.java
new file mode 100644
index 0000000..3aded85
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/config/FiltersConfig.java
@@ -0,0 +1,158 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.search.filters.config;
+
+import java.io.File;
+
+import org.onap.aai.cl.api.Logger;
+import org.onap.aai.cl.eelf.LoggerFactory;
+import org.onap.aai.sparky.config.SparkyResourceLoader;
+import org.onap.aai.sparky.logging.AaiUiMsgs;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+public class FiltersConfig {
+
+ private static final Logger LOG = LoggerFactory.getInstance().getLogger(FiltersConfig.class);
+
+ private String filtersFileName;
+
+ private String viewsFileName;
+
+ private FiltersForViewsConfig viewsConfig;
+
+ private FiltersDetailsConfig filtersConfig;
+
+ private SparkyResourceLoader resourceLoader;
+
+ public FiltersConfig() {
+ //exposed for testing
+ }
+
+ public FiltersConfig(String filtersFileName, String viewsFileName, SparkyResourceLoader resourceLoader) {
+ this.filtersFileName = filtersFileName;
+ this.viewsFileName = viewsFileName;
+ this.resourceLoader = resourceLoader;
+
+ initializeFilters();
+ }
+
+ /**
+ * Initialize config.
+ */
+ private void initializeFilters() {
+ viewsConfig = this.readUiViewsConfig();
+ filtersConfig = this.readUiFiltersConfig();
+ }
+
+ public String getViewsFileName() {
+ return viewsFileName;
+ }
+
+ public void setViewsFileName(String viewsFileName) {
+ this.viewsFileName = viewsFileName;
+ }
+
+ public String getFiltersFileName() {
+ return filtersFileName;
+ }
+
+ public void setFiltersFileName(String filtersFileName) {
+ this.filtersFileName = filtersFileName;
+ }
+
+ public FiltersForViewsConfig getViewsConfig() {
+ return viewsConfig;
+ }
+
+ public void setViewsConfig(FiltersForViewsConfig filtersMapEntity) {
+ this.viewsConfig = filtersMapEntity;
+ }
+
+ public FiltersDetailsConfig getFiltersConfig() {
+ return filtersConfig;
+ }
+
+ public UiFilterConfig getFilterById(String filterId) {
+ for ( UiFilterConfig filter : filtersConfig.getFilters()) {
+ if ( filter.getFilterId().equals(filterId)) {
+ return filter;
+ }
+ }
+
+ return null;
+ }
+
+ public void setFiltersConfig(FiltersDetailsConfig filtersConfig) {
+ this.filtersConfig = filtersConfig;
+ }
+
+ public FiltersDetailsConfig readUiFiltersConfig() {
+ ObjectMapper mapper = new ObjectMapper();
+ FiltersDetailsConfig filtersConfig = null;
+ try{
+ filtersConfig = mapper.readValue(resourceLoader.getResourceAsFile(this.getFiltersFileName(),true), FiltersDetailsConfig.class);
+ } catch (Exception e){
+ LOG.error(AaiUiMsgs.ERROR_READING_JSON_SCHEMA, this.getFiltersFileName());
+ }
+
+ return filtersConfig;
+ }
+
+ public FiltersForViewsConfig readUiViewsConfig() {
+ ObjectMapper mapper = new ObjectMapper();
+ FiltersForViewsConfig viewsConfig = null;
+
+ try {
+ viewsConfig = mapper.readValue(resourceLoader.getResourceAsFile(this.getViewsFileName(),true), FiltersForViewsConfig.class);
+ } catch (Exception e){
+ LOG.error(AaiUiMsgs.ERROR_READING_JSON_SCHEMA, this.getViewsFileName());
+ }
+
+ return viewsConfig;
+ }
+
+ public void initializeFiltersDetailsConfig(File filtersFile) {
+ ObjectMapper mapper = new ObjectMapper();
+ try{
+ this.filtersConfig = mapper.readValue(filtersFile, FiltersDetailsConfig.class);
+ } catch (Exception e){
+ LOG.error(AaiUiMsgs.ERROR_READING_JSON_SCHEMA, filtersFile.getAbsolutePath());
+ }
+ }
+
+ public void initializeFiltersForViewsConfig(File viewsFile) {
+ ObjectMapper mapper = new ObjectMapper();
+
+ try {
+ this.viewsConfig = mapper.readValue(viewsFile, FiltersForViewsConfig.class);
+ } catch (Exception e){
+ LOG.error(AaiUiMsgs.ERROR_READING_JSON_SCHEMA, viewsFile.getAbsolutePath());
+ }
+
+ }
+
+}
+
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/config/FiltersDetailsConfig.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/config/FiltersDetailsConfig.java
new file mode 100644
index 0000000..ab5e1d4
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/config/FiltersDetailsConfig.java
@@ -0,0 +1,58 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.search.filters.config;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+
+public class FiltersDetailsConfig {
+ @JsonProperty("filters")
+ private List<UiFilterConfig> filters = new ArrayList<UiFilterConfig>();
+
+ public FiltersDetailsConfig(){}
+
+ @JsonCreator
+ public FiltersDetailsConfig(@JsonProperty("filters") final List<UiFilterConfig> filters) {
+ this.filters = filters;
+ }
+
+ public List<UiFilterConfig> getFilters() {
+ return filters;
+ }
+
+ public void setFilters(List<UiFilterConfig> filters) {
+ this.filters = filters;
+ }
+
+ @Override
+ public String toString() {
+ return "UiFiltersConfig [filters=" + filters + "]";
+ }
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/config/FiltersForViewsConfig.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/config/FiltersForViewsConfig.java
new file mode 100644
index 0000000..1d0adfe
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/config/FiltersForViewsConfig.java
@@ -0,0 +1,57 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.search.filters.config;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+public class FiltersForViewsConfig {
+
+ private List<UiViewListItemConfig> views = new ArrayList<UiViewListItemConfig>();
+
+ public FiltersForViewsConfig(){}
+
+ @JsonCreator
+ public FiltersForViewsConfig(@JsonProperty("views") final List<UiViewListItemConfig> views) {
+ this.views = views;
+ }
+
+ @JsonProperty("views")
+ public List<UiViewListItemConfig> getViews() {
+ return views;
+ }
+
+ public void setViews(List<UiViewListItemConfig> views) {
+ this.views = views;
+ }
+
+ @Override
+ public String toString() {
+ return "UiViewToFilterMappingEntity [allUiViews=" + views + "]";
+ }
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/config/UiFilterConfig.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/config/UiFilterConfig.java
new file mode 100644
index 0000000..d3ef9ba
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/config/UiFilterConfig.java
@@ -0,0 +1,188 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.search.filters.config;
+
+import java.util.List;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonInclude.Include;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+@JsonInclude(Include.NON_NULL)
+public class UiFilterConfig {
+
+ @JsonProperty("filterId")
+ private String filterId;
+
+ @JsonProperty("filterName")
+ private String filterName;
+
+ @JsonProperty("displayName")
+ private String displayName;
+
+ @JsonProperty("dataType")
+ private String dataType;
+
+ @JsonProperty("multiSelect")
+ private String multiSelect;
+
+ @JsonProperty("watermark")
+ private String watermark;
+
+ @JsonProperty("defaultValue")
+ private UiFilterOptionsValuesConfig defaultValue;
+
+ @JsonProperty("optionsType")
+ private String optionsType;
+
+ @JsonProperty("optionsValues")
+ private List<UiFilterOptionsValuesConfig> optionsValues;
+
+ @JsonProperty("dataSource")
+ private UiFilterDataSourceConfig dataSource = new UiFilterDataSourceConfig();
+
+ @JsonCreator
+ public UiFilterConfig(@JsonProperty("filterId") final String filterId,
+ @JsonProperty("filterName") final String filterName,
+ @JsonProperty("displayName") final String displayName,
+ @JsonProperty("dataType") final String dataType,
+ @JsonProperty("multiSelect") final String multiSelect,
+ @JsonProperty("watermark") final String watermark,
+ @JsonProperty("defaultValue") final UiFilterOptionsValuesConfig defaultValue,
+ @JsonProperty("optionsType") final String optionsType,
+ @JsonProperty("optionsValues") final List<UiFilterOptionsValuesConfig> optionsValues,
+ @JsonProperty("dataSource") final UiFilterDataSourceConfig dataSource
+ ) {
+ this.filterId = filterId;
+ this.filterName = filterName;
+ this.displayName = displayName;
+ this.dataType = dataType;
+ this.multiSelect = multiSelect;
+ this.watermark = watermark;
+ this.defaultValue = defaultValue;
+ this.optionsType = optionsType;
+ this.optionsValues = optionsValues;
+ this.dataSource = dataSource;
+ }
+
+ @JsonProperty("filterId")
+ public String getFilterId() {
+ return filterId;
+ }
+
+ public void setFilterId(String filterId) {
+ this.filterId = filterId;
+ }
+
+ @JsonProperty("filterName")
+ public String getFilterName() {
+ return filterName;
+ }
+
+ public void setFilterName(String filterName) {
+ this.filterName = filterName;
+ }
+
+ @JsonProperty("displayName")
+ public String getDisplayName() {
+ return displayName;
+ }
+
+ public void setDisplayName(String displayName) {
+ this.displayName = displayName;
+ }
+
+ @JsonProperty("dataType")
+ public String getDataType() {
+ return dataType;
+ }
+
+ public void setDataType(String dataType) {
+ this.dataType = dataType;
+ }
+
+ @JsonProperty("multiSelect")
+ public String getMultiSelect() {
+ return multiSelect;
+ }
+
+ public void setMultiSelect(String multiSelect) {
+ this.multiSelect = multiSelect;
+ }
+
+ @JsonProperty("watermark")
+ public String getWatermark() {
+ return watermark;
+ }
+
+ public void setWatermark(String watermark) {
+ this.watermark = watermark;
+ }
+
+ @JsonProperty("defaultValue")
+ public UiFilterOptionsValuesConfig getDefaultValue() {
+ return defaultValue;
+ }
+
+ public void setDefaultValue(UiFilterOptionsValuesConfig defaultValue) {
+ this.defaultValue = defaultValue;
+ }
+
+ @JsonProperty("optionsType")
+ public String getOptionsType() {
+ return optionsType;
+ }
+
+ public void setOptionsType(String optionsType) {
+ this.optionsType = optionsType;
+ }
+ @JsonProperty("optionsValues")
+ public List<UiFilterOptionsValuesConfig> getOptionsValues() {
+ return optionsValues;
+ }
+
+ public void setOptionsValues(List<UiFilterOptionsValuesConfig> optionsValues) {
+ this.optionsValues = optionsValues;
+ }
+
+ @JsonProperty("dataSource")
+ public UiFilterDataSourceConfig getDataSource() {
+ return dataSource;
+ }
+
+ public void setDataSource(UiFilterDataSourceConfig dataSource) {
+ this.dataSource = dataSource;
+ }
+
+ @Override
+ public String toString() {
+ return "UiFilterConfig [filterId=" + filterId + ", filterName=" + filterName + ", displayName="
+ + displayName + ", dataType=" + dataType + ", multiSelect=" + multiSelect + ", watermark="
+ + watermark + ", optionsType=" + optionsType + ", optionsValues=" + optionsValues
+ + ", dataSource=" + dataSource + "]";
+ }
+}
+
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/config/UiFilterDataSourceConfig.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/config/UiFilterDataSourceConfig.java
new file mode 100644
index 0000000..4f9e2da
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/config/UiFilterDataSourceConfig.java
@@ -0,0 +1,99 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.search.filters.config;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonInclude.Include;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+@JsonInclude(Include.NON_NULL)
+public class UiFilterDataSourceConfig {
+
+ @JsonProperty("indexName")
+ private String indexName;
+
+ @JsonProperty("docType")
+ private String docType;
+
+ @JsonProperty("fieldName")
+ private String fieldName;
+
+ @JsonProperty("pathToField")
+ private String pathToField;
+
+ public UiFilterDataSourceConfig(){}
+
+ @JsonCreator
+ public UiFilterDataSourceConfig(@JsonProperty("indexName") final String indexName, @JsonProperty("docType") final String docType, @JsonProperty("fieldName") final String fieldName, @JsonProperty("pathToField") final String pathToField) {
+ this.indexName = indexName;
+ this.docType = docType;
+ this.fieldName = fieldName;
+ this.pathToField = pathToField;
+ }
+
+ @JsonProperty("indexName")
+ public String getIndexName() {
+ return indexName;
+ }
+
+ public void setIndexName(String indexName) {
+ this.indexName = indexName;
+ }
+
+ @JsonProperty("docType")
+ public String getDocType() {
+ return docType;
+ }
+
+ public void setDocType(String docType) {
+ this.docType = docType;
+ }
+
+ @JsonProperty("fieldName")
+ public String getFieldName() {
+ return fieldName;
+ }
+
+ public void setFieldName(String fieldName) {
+ this.fieldName = fieldName;
+ }
+
+ @JsonProperty("pathToField")
+ public String getPathToField() {
+ return pathToField;
+ }
+
+ public void setPathToField(String pathToField) {
+ this.pathToField = pathToField;
+ }
+
+ @Override
+ public String toString() {
+ return "UiFilterDataSourceConfig [indexName=" + indexName + ", docType=" + docType
+ + ", fieldName=" + fieldName + ", pathToField=" + pathToField + "]";
+ }
+}
+
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/config/UiFilterListItemConfig.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/config/UiFilterListItemConfig.java
new file mode 100644
index 0000000..2f955fc
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/config/UiFilterListItemConfig.java
@@ -0,0 +1,70 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.search.filters.config;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonInclude.Include;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+@JsonInclude(Include.NON_NULL)
+public class UiFilterListItemConfig {
+ @JsonProperty("filterId")
+ private String filterId;
+
+ @JsonProperty("defaultValue")
+ private UiFilterOptionsValuesConfig defaultValue;
+
+ @JsonCreator
+ public UiFilterListItemConfig(@JsonProperty("filterId") final String filterId,
+ @JsonProperty("defaultValue") final UiFilterOptionsValuesConfig defaultValue) {
+ this.filterId = filterId;
+ this.defaultValue = defaultValue;
+ }
+
+ @JsonProperty("filterId")
+ public String getFilterId() {
+ return filterId;
+ }
+
+ public void setFilterId(String filterId) {
+ this.filterId = filterId;
+ }
+
+ @JsonProperty("defaultValue")
+ public UiFilterOptionsValuesConfig getDefaultValue() {
+ return defaultValue;
+ }
+
+ public void setDefaultValue(UiFilterOptionsValuesConfig defaultValue) {
+ this.defaultValue = defaultValue;
+ }
+
+ @Override
+ public String toString() {
+ return "FilterListItemEntity [filterId=" + filterId + ", defaultValue=" + defaultValue + "]";
+ }
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/config/UiFilterOptionsValuesConfig.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/config/UiFilterOptionsValuesConfig.java
new file mode 100644
index 0000000..cf45d21
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/config/UiFilterOptionsValuesConfig.java
@@ -0,0 +1,68 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.search.filters.config;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonInclude.Include;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+@JsonInclude(Include.NON_NULL)
+public class UiFilterOptionsValuesConfig {
+ @JsonProperty("decode")
+ private String decode;
+
+ @JsonProperty("code")
+ private String code;
+
+ @JsonCreator
+ public UiFilterOptionsValuesConfig(@JsonProperty("decode") final String decode, @JsonProperty("code") final String code) {
+ this.decode = decode;
+ this.code = code;
+ }
+
+ @JsonProperty("decode")
+ public String getDecode() {
+ return decode;
+ }
+
+ public void setDecode(String decode) {
+ this.decode = decode;
+ }
+
+ @JsonProperty("code")
+ public String getCode() {
+ return code;
+ }
+
+ public void setCode(String code) {
+ this.code = code;
+ }
+
+ @Override
+ public String toString() {
+ return "UiFilterOptionsValuesConfig [decode=" + decode + ", code=" + code + "]";
+ }
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/config/UiViewListItemConfig.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/config/UiViewListItemConfig.java
new file mode 100644
index 0000000..1d70314
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/config/UiViewListItemConfig.java
@@ -0,0 +1,68 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.search.filters.config;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+public class UiViewListItemConfig {
+ @JsonProperty("viewName")
+ private String viewName;
+
+ private List<UiFilterListItemConfig> filters = new ArrayList<UiFilterListItemConfig>();
+
+ @JsonCreator
+ public UiViewListItemConfig(@JsonProperty("viewName") final String viewName, @JsonProperty("filters") final List<UiFilterListItemConfig> filters) {
+ this.viewName = viewName;
+ this.filters = filters;
+ }
+
+ @JsonProperty("viewName")
+ public String getViewName() {
+ return viewName;
+ }
+
+ public void setViewName(String viewName) {
+ this.viewName = viewName;
+ }
+
+ @JsonProperty("filters")
+ public List<UiFilterListItemConfig> getFilters() {
+ return filters;
+ }
+
+ public void setListOfFilters(List<UiFilterListItemConfig> filters) {
+ this.filters = filters;
+ }
+
+ @Override
+ public String toString() {
+ return "UiViewEntity [viewName=" + viewName + ", filters=" + filters + "]";
+ }
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/entity/AggregationEntity.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/entity/AggregationEntity.java
new file mode 100644
index 0000000..3fc61ac
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/entity/AggregationEntity.java
@@ -0,0 +1,80 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.search.filters.entity;
+
+import javax.json.Json;
+import javax.json.JsonBuilderFactory;
+import javax.json.JsonObject;
+
+public class AggregationEntity {
+
+ private String aggregationName;
+ private String aggregationFieldName;
+ private int size;
+
+ public AggregationEntity(String aggName, String fieldName, int size) {
+
+ this.aggregationName = aggName;
+ this.aggregationFieldName = fieldName;
+ this.size = size;
+ }
+
+ public String getAggregationName() {
+ return aggregationName;
+ }
+
+ public void setAggregationName(String aggregationName) {
+ this.aggregationName = aggregationName;
+ }
+
+ public String getAggregationFieldName() {
+ return aggregationFieldName;
+ }
+
+ public void setAggregationFieldName(String aggregationFieldName) {
+ this.aggregationFieldName = aggregationFieldName;
+ }
+
+ public int getSize() {
+ return size;
+ }
+
+ public void setSize(int size) {
+ this.size = size;
+ }
+
+ public JsonObject getJsonObject() {
+
+ JsonBuilderFactory factory = Json.createBuilderFactory(null);
+
+ return factory.createObjectBuilder()
+ .add("terms", factory.createObjectBuilder()
+ .add("field", aggregationFieldName)
+ .add("size", size))
+ .build();
+ }
+
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/entity/BoolQueryBuilder.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/entity/BoolQueryBuilder.java
new file mode 100644
index 0000000..750270a
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/entity/BoolQueryBuilder.java
@@ -0,0 +1,123 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.search.filters.entity;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.json.Json;
+import javax.json.JsonArray;
+import javax.json.JsonArrayBuilder;
+import javax.json.JsonBuilderFactory;
+import javax.json.JsonObject;
+import javax.json.JsonObjectBuilder;
+
+public class BoolQueryBuilder {
+
+ private List<MatchFilterCriteriaEntity> mustFilters;
+ private List<MatchFilterCriteriaEntity> shouldFilters;
+
+ private int minShouldMatch;
+
+ public BoolQueryBuilder() {
+
+ mustFilters = new ArrayList<MatchFilterCriteriaEntity>();
+ shouldFilters = new ArrayList<MatchFilterCriteriaEntity>();
+ minShouldMatch = -1;
+
+ }
+
+ public void addMustFilter(MatchFilterCriteriaEntity filter) {
+
+ if (!mustFilters.contains(filter)) {
+ mustFilters.add(filter);
+ }
+
+ }
+
+ public void addShouldFilter(MatchFilterCriteriaEntity filter) {
+
+ if (!shouldFilters.contains(filter)) {
+ shouldFilters.add(filter);
+ }
+
+ }
+
+ public void setMinShouldMatch(int minShouldMatch) {
+ this.minShouldMatch = minShouldMatch;
+ }
+
+ public boolean isMatchAll() {
+ return (mustFilters.isEmpty() && shouldFilters.isEmpty());
+ }
+
+ public JsonObject getJsonObject() {
+ /*
+ * Specify a null config for now, but if we want normalize all the builders, we can do it at one
+ * location, when we are ready.
+ */
+ JsonBuilderFactory factory = Json.createBuilderFactory(null);
+
+ JsonObjectBuilder boolBuilder = factory.createObjectBuilder();
+
+ if(!mustFilters.isEmpty()){
+ JsonArrayBuilder mustArrayBuilder = factory.createArrayBuilder();
+
+ for (MatchFilterCriteriaEntity matchCriteria : mustFilters) {
+ mustArrayBuilder.add(matchCriteria.getJsonObject());
+ }
+
+ JsonArray mustArray = mustArrayBuilder.build();
+ boolBuilder.add("must", mustArray);
+ }
+
+ if (!shouldFilters.isEmpty()) {
+ JsonArray shouldArray = null;
+ JsonArrayBuilder shouldArrayBuilder = factory.createArrayBuilder();
+
+ for (MatchFilterCriteriaEntity matchCriteria : shouldFilters) {
+ shouldArrayBuilder.add(matchCriteria.getJsonObject());
+ }
+
+ shouldArray = shouldArrayBuilder.build();
+ boolBuilder.add("should", shouldArray).add("min_should_match", minShouldMatch);
+ }
+
+ JsonObjectBuilder queryObjectBuilder = factory.createObjectBuilder();
+
+ /*
+ * If both filter lists are empty then we are doing an aggregation
+ * based off fields. Just match-all for the query.
+ */
+ if(isMatchAll()) {
+ JsonObject matchAllObject = factory.createObjectBuilder().build();
+ queryObjectBuilder.add("match_all", matchAllObject);
+ } else {
+ queryObjectBuilder.add("bool", boolBuilder.build());
+ }
+
+ return queryObjectBuilder.build();
+ }
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/entity/FilteredAggregationQueryBuilder.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/entity/FilteredAggregationQueryBuilder.java
new file mode 100644
index 0000000..fa9226e
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/entity/FilteredAggregationQueryBuilder.java
@@ -0,0 +1,65 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.search.filters.entity;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.json.Json;
+import javax.json.JsonBuilderFactory;
+import javax.json.JsonObject;
+import javax.json.JsonObjectBuilder;
+
+public class FilteredAggregationQueryBuilder {
+
+ private List<AggregationEntity> aggregationEntities;
+
+ public FilteredAggregationQueryBuilder() {
+ aggregationEntities = new ArrayList<AggregationEntity>();
+ }
+
+ public void addAggregationEntity(AggregationEntity aggregationEntity) {
+ if (!aggregationEntities.contains(aggregationEntity)) {
+ aggregationEntities.add(aggregationEntity);
+ }
+ }
+
+ public JsonObject getJsonObject() {
+
+ /*
+ * Specify a null config for now, but if we want normalize all the builders, we can do it at one
+ * location, when we are ready.
+ */
+ JsonBuilderFactory factory = Json.createBuilderFactory(null);
+
+ JsonObjectBuilder aggsArrayBuilder = factory.createObjectBuilder();
+
+ for (AggregationEntity aggEntity : aggregationEntities) {
+ aggsArrayBuilder.add(aggEntity.getAggregationName(), aggEntity.getJsonObject());
+ }
+
+ return aggsArrayBuilder.build();
+ }
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/entity/MatchFilterCriteriaEntity.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/entity/MatchFilterCriteriaEntity.java
new file mode 100644
index 0000000..68c058b
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/entity/MatchFilterCriteriaEntity.java
@@ -0,0 +1,77 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.search.filters.entity;
+
+import javax.json.Json;
+import javax.json.JsonBuilderFactory;
+import javax.json.JsonObject;
+
+public class MatchFilterCriteriaEntity {
+
+ private String criteriaName;
+ private String criteriaValue;
+
+ public MatchFilterCriteriaEntity(String criteriaName, String criteriaValue) {
+ super();
+ this.criteriaName = criteriaName;
+ this.criteriaValue = criteriaValue;
+ }
+
+ public String getCriteriaName() {
+ return criteriaName;
+ }
+
+ public void setCriteriaName(String criteriaName) {
+ this.criteriaName = criteriaName;
+ }
+
+ public String getCriteriaValue() {
+ return criteriaValue;
+ }
+
+ public void setCriteriaValue(String criteriaValue) {
+ this.criteriaValue = criteriaValue;
+ }
+
+ public JsonObject getJsonObject() {
+
+ /*
+ * Specify a null config for now, but if we want normalize all the builders, we can do it at one
+ * location, when we are ready.
+ */
+ JsonBuilderFactory factory = Json.createBuilderFactory(null);
+
+ return factory.createObjectBuilder()
+ .add("match", factory.createObjectBuilder().add(criteriaName, criteriaValue)).build();
+
+ }
+
+ @Override
+ public String toString() {
+ return "MatchFilterCriteriaEntity [criteriaName=" + criteriaName + ", criteriaValue="
+ + criteriaValue + "]";
+ }
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/entity/SearchFilter.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/entity/SearchFilter.java
new file mode 100644
index 0000000..2a6f05d
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/entity/SearchFilter.java
@@ -0,0 +1,88 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.search.filters.entity;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * A base entity to contain the details of the filter id and values from the FE to the BE for the
+ * purpose of driving DAL calls into ElasticSearch, Search Abstraction Service, or as a utility
+ * object within the query builders.
+ *
+ * The class has unique identifier for the filter id, and then 1 or more filter values. The value
+ * list has been introduced to help us with a multi-select use case that will need to be supported
+ * eventually.
+ */
+public class SearchFilter {
+
+ private String filterId;
+ private List<String> values;
+
+ public SearchFilter() {
+ values = new ArrayList<String>();
+ }
+
+ public SearchFilter(String filterId) {
+ this();
+ this.filterId = filterId;
+ }
+
+ public SearchFilter(String filterId, String... values) {
+ this();
+ this.filterId = filterId;
+ this.values.addAll(Arrays.asList(values));
+ }
+
+ public String getFilterId() {
+ return filterId;
+ }
+
+ public void setFilterId(String filterId) {
+ this.filterId = filterId;
+ }
+
+ public List<String> getValues() {
+ return values;
+ }
+
+ public void setValues(List<String> values) {
+ this.values = values;
+ }
+
+ public void addValue(String v) {
+ if (!values.contains(v)) {
+ values.add(v);
+ }
+
+ }
+
+ @Override
+ public String toString() {
+ return "SearchFilter [filterId=" + filterId + ", values=" + values + "]";
+ }
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/entity/UiFilterEntity.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/entity/UiFilterEntity.java
new file mode 100644
index 0000000..f90403c
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/entity/UiFilterEntity.java
@@ -0,0 +1,180 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.search.filters.entity;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.onap.aai.sparky.search.filters.config.UiFilterConfig;
+import org.onap.aai.sparky.search.filters.config.UiFilterOptionsValuesConfig;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonInclude.Include;
+
+/**
+ * Stores data for a single filter for a given UI view.
+ * <p>
+ * When a UI view wants to know which filters it should display, an object of this class is created for each
+ * filter discovered and stores data for that filter. Each filter/object of this class is added to a
+ * ViewFilterList object which is then serialized to JSON and returned to the view in the response body.
+ */
+@JsonInclude(Include.NON_NULL)
+public class UiFilterEntity {
+ private String filterId;
+ private String filterName;
+ private String displayName;
+ private String dataType;
+
+ private String multiSelect;
+ private String watermark;
+ private UiFilterOptionsValuesConfig defaultValue;
+ private String optionsType;
+
+ private List<UiFilterOptionsValuesConfig> optionsValues;
+
+ private List<UiFilterValueEntity> filterValueList;
+
+ public UiFilterEntity() {}
+
+ public UiFilterEntity(UiFilterConfig filterConfig) {
+ if (filterConfig.getFilterId() != null) {
+ this.setFilterId(filterConfig.getFilterId());
+ }
+ if (filterConfig.getFilterName() != null) {
+ this.setFilterName(filterConfig.getFilterName());
+ }
+ if (filterConfig.getDisplayName() != null) {
+ this.setDisplayName(filterConfig.getDisplayName());
+ }
+ if (filterConfig.getDataType() != null) {
+ this.setDataType(filterConfig.getDataType());
+ }
+ if (filterConfig.getMultiSelect() != null) {
+ this.setMultiSelect(filterConfig.getMultiSelect());
+ }
+ if (filterConfig.getWatermark() != null) {
+ this.setWatermark(filterConfig.getWatermark());
+ }
+ if (filterConfig.getDefaultValue() != null) {
+ this.setDefaultValue(filterConfig.getDefaultValue());
+ }
+ if (filterConfig.getOptionsType() != null) {
+ this.setOptionsType(filterConfig.getOptionsType());
+ }
+ if(filterConfig.getOptionsValues() != null && !filterConfig.getOptionsValues().isEmpty()) {
+ this.setOptionsValues(filterConfig.getOptionsValues());
+ } else {
+ this.optionsValues = new ArrayList<UiFilterOptionsValuesConfig>();
+ }
+ }
+
+ public void addFilterValue(UiFilterValueEntity valueEntity) {
+ if (null == filterValueList) {
+ filterValueList = new ArrayList<>();
+ }
+
+ this.filterValueList.add(valueEntity);
+ }
+
+ public String getFilterId() {
+ return filterId;
+ }
+
+ public String getFilterName() {
+ return filterName;
+ }
+
+ public String getDisplayName() {
+ return displayName;
+ }
+
+ public String getDataType() {
+ return dataType;
+ }
+
+ public UiFilterOptionsValuesConfig getDefaultValue() {
+ return defaultValue;
+ }
+
+ public List<UiFilterValueEntity> getFilterValueList() {
+ return filterValueList;
+ }
+
+ public void setFilterId(String filterId) {
+ this.filterId = filterId;
+ }
+
+ public void setFilterName(String filterName) {
+ this.filterName = filterName;
+ }
+
+ public void setDisplayName(String displayName) {
+ this.displayName = displayName;
+ }
+
+ public void setDataType(String dataType) {
+ this.dataType = dataType;
+ }
+
+ public String getMultiSelect() {
+ return multiSelect;
+ }
+
+ public void setMultiSelect(String multiSelect) {
+ this.multiSelect = multiSelect;
+ }
+
+ public String getWatermark() {
+ return watermark;
+ }
+
+ public void setWatermark(String watermark) {
+ this.watermark = watermark;
+ }
+
+ public String getOptionsType() {
+ return optionsType;
+ }
+
+ public void setOptionsType(String optionsType) {
+ this.optionsType = optionsType;
+ }
+
+ public List<UiFilterOptionsValuesConfig> getOptionsValues() {
+ return optionsValues;
+ }
+
+ public void setOptionsValues(List<UiFilterOptionsValuesConfig> optionsValues) {
+ this.optionsValues = optionsValues;
+ }
+
+ public void setDefaultValue(UiFilterOptionsValuesConfig defaultValue) {
+ this.defaultValue = defaultValue;
+ }
+
+ public void setFilterValueList(List<UiFilterValueEntity> values) {
+ this.filterValueList = values;
+ }
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/entity/UiFilterValueEntity.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/entity/UiFilterValueEntity.java
new file mode 100644
index 0000000..73b105b
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/entity/UiFilterValueEntity.java
@@ -0,0 +1,80 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.search.filters.entity;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonInclude.Include;
+
+/**
+ * This class represents a single item or value to populate the FE filter component with.
+ * A drop-down list, for example, may be populated with the values from several instances of this class.
+ */
+@JsonInclude(Include.NON_NULL)
+public class UiFilterValueEntity {
+ private String filterId;
+ private String filterValue;
+ private String displayName; // The string that will be rendered in the view
+
+ public UiFilterValueEntity() {}
+
+ public UiFilterValueEntity(String filterId, String filterValue, String displayName) {
+ this.filterId = filterId;
+ this.filterValue = filterValue;
+ this.displayName = displayName;
+ }
+
+ public String getFilterId() {
+ return filterId;
+ }
+
+ public String getFilterValue() {
+ return filterValue;
+ }
+
+ public String getDisplayName() {
+ return displayName;
+ }
+
+ public void setFilterId(String filterId) {
+ this.filterId = filterId;
+ }
+
+ public void setFilterValue(String filterValue) {
+ this.filterValue = filterValue;
+ }
+
+ public void setDisplayName(String displayName) {
+ this.displayName = displayName;
+ }
+
+ @Override
+ public String toString() {
+ return "UiFilterValueEntity [" + (filterId != null ? "filterId=" + filterId + ", " : "")
+ + (filterValue != null ? "filterValue=" + filterValue + ", " : "")
+ + (displayName != null ? "displayName=" + displayName : "") + "]";
+ }
+
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/entity/UiFiltersEntity.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/entity/UiFiltersEntity.java
new file mode 100644
index 0000000..7780418
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/entity/UiFiltersEntity.java
@@ -0,0 +1,53 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.search.filters.entity;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Represents a list of filters that a given UI view should display.
+ * <p>
+ * When a UI view wants to know which filters it should display, an object of this class is created to keep
+ * track of all the filters that are discovered for that view and is then serialized to JSON and returned to
+ * the view in the response body.
+ */
+public class UiFiltersEntity {
+ private List<UiFilterEntity> filters = new ArrayList<>();
+
+
+
+ public void addFilter(UiFilterEntity viewFilter) {
+ filters.add(viewFilter);
+ }
+
+ public List<UiFilterEntity> getFilters() {
+ return filters;
+ }
+
+ public void setFilters(List<UiFilterEntity> filters) {
+ this.filters = filters;
+ }
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/registry/SearchProviderRegistry.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/registry/SearchProviderRegistry.java
new file mode 100644
index 0000000..4e785ce
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/registry/SearchProviderRegistry.java
@@ -0,0 +1,76 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.search.registry;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.onap.aai.sparky.search.api.SearchProvider;
+
+/**
+ * Make this a java-scoped singleton to resolve the contextual issue spanning a Spring Context and
+ * accessing the SPR in other parts of the code that are not directly instantiated by a Spring Bean.
+ * Eventually the SPR doesn’t have to be a real singleton, it could simply be a Spring bean scoped
+ * as a singleton and then wired in via dependency injection to the classes that need it. But I’m
+ * not there yet. This will get a demonstrable extension mechanism in place quickly at practically
+ * no cost, beyond what’s already in the email plus some testing.
+ */
+
+public class SearchProviderRegistry {
+
+ private List<SearchProvider> searchProviders;
+
+ public SearchProviderRegistry() {
+ searchProviders = new ArrayList<SearchProvider>();
+ }
+
+ public List<SearchProvider> getSearchProviders() {
+ return searchProviders;
+ }
+
+ public final void addSearchProvider(SearchProvider searchProvider) {
+
+ if (searchProvider == null) {
+ return;
+ }
+
+ if (!searchProviders.contains(searchProvider)) {
+ searchProviders.add(searchProvider);
+ }
+ }
+
+ public final void addSearchProviders(List<SearchProvider> searchProviders) {
+
+ if (searchProviders == null) {
+ return;
+ }
+
+ for (SearchProvider searchProvider : searchProviders) {
+ addSearchProvider(searchProvider);
+ }
+
+ }
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/security/BaseCookieDecryptor.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/security/BaseCookieDecryptor.java
new file mode 100644
index 0000000..9dfb1bf
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/security/BaseCookieDecryptor.java
@@ -0,0 +1,51 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.security;
+
+import org.onap.aai.cl.api.Logger;
+import org.onap.aai.cl.eelf.LoggerFactory;
+import org.onap.aai.sparky.logging.AaiUiMsgs;
+import org.openecomp.portalsdk.core.onboarding.util.CipherUtil;
+
+public class BaseCookieDecryptor implements CookieDecryptor {
+
+ private static final Logger LOG = LoggerFactory.getInstance().getLogger(BaseCookieDecryptor.class);
+
+
+ public BaseCookieDecryptor(){}
+
+ public String decryptCookie(String encryptedCookie){
+
+ String decryptedCookie = "";
+ try {
+ decryptedCookie = CipherUtil.decrypt(encryptedCookie, "");
+ } catch (Exception e) {
+ LOG.error(AaiUiMsgs.LOGIN_FILTER_INFO, "decrypting base cookie failed " + e.getLocalizedMessage());
+ }
+ return decryptedCookie;
+
+ }
+
+} \ No newline at end of file
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/security/CookieDecryptor.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/security/CookieDecryptor.java
new file mode 100644
index 0000000..6e79b60
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/security/CookieDecryptor.java
@@ -0,0 +1,31 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.security;
+
+public interface CookieDecryptor {
+
+ String decryptCookie(String encryptedCookie);
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/security/EcompSso.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/security/EcompSso.java
new file mode 100644
index 0000000..3348b1f
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/security/EcompSso.java
@@ -0,0 +1,155 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.security;
+
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+
+import org.onap.aai.cl.api.Logger;
+import org.onap.aai.cl.eelf.LoggerFactory;
+import org.onap.aai.sparky.logging.AaiUiMsgs;
+import org.onap.aai.sparky.security.portal.config.PortalAuthenticationConfig;
+import org.openecomp.portalsdk.core.onboarding.util.CipherUtil;
+import org.openecomp.portalsdk.core.onboarding.util.PortalApiProperties;
+
+/**
+ * Provides authentication services for onboarded ECOMP applications.
+ */
+public class EcompSso {
+
+ public static final String EP_SERVICE = "EPService";
+ public static final String CSP_COOKIE_NAME = "csp_cookie_name";
+ public static final String CSP_GATE_KEEPER_PROD_KEY = "csp_gate_keeper_prod_key";
+ public static final String ONAP_ENABLED = "ONAP_ENABLED";
+ private static final Logger LOG = LoggerFactory.getInstance().getLogger(EcompSso.class);
+
+ /**
+ * Searches the request for a cookie with the specified name.
+ *
+ * @param request
+ * @param cookieName
+ * @return Cookie, or null if not found.
+ */
+ public static Cookie getCookie(HttpServletRequest request, String cookieName) {
+ Cookie[] cookies = request.getCookies();
+ if (cookies != null)
+ for (Cookie cookie : cookies) {
+ if (cookie.getName().equals(cookieName)) {
+ return cookie;
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Answers whether the ECOMP Portal service cookie is present in the specified request.
+ *
+ * @param request
+ * @return true if the cookie is found, else false.
+ */
+ private static boolean isEPServiceCookiePresent(HttpServletRequest request) {
+ Cookie ep = getCookie(request, EP_SERVICE);
+ return (ep != null);
+ }
+
+ /**
+ * Validates whether the ECOMP Portal sign-on process has completed, which relies the AT&T Global
+ * Log On single-sign on process. Checks for the ECOMP cookie (see {@link #EP_SERVICE}). If found,
+ * then searches for a CSP cookie; if not found, for a WebJunction header.
+ *
+ * @param request
+ * @return ATT UID if the ECOMP cookie is present and the sign-on process established an ATT UID;
+ * else null.
+ */
+ public static String validateEcompSso(HttpServletRequest request) {
+ boolean isOnapEnabled = PortalAuthenticationConfig.getInstance().getIsOnapEnabled();
+ if (isOnapEnabled) {
+ if (isEPServiceCookiePresent(request)) {
+ /*
+ * This is a "temporary" fix until proper separation between closed source and open source
+ * code is reached
+ */
+ return ONAP_ENABLED;
+ }
+ return null;
+ } else {
+ return getLoginIdFromCookie(request);
+ }
+ }
+
+ /**
+ * Searches the specified request for the CSP cookie, decodes it and gets the ATT UID.
+ *
+ * @param request
+ * @return ATTUID if the cookie is present in the request and can be decoded successfully (expired
+ * cookies do not decode); else null.
+ */
+ private static String getLoginIdFromCookie(HttpServletRequest request) {
+ String uid = null;
+ try {
+ String[] cspFields = getCspData(request);
+ if (cspFields != null && cspFields.length > 5)
+ uid = cspFields[5];
+ } catch (Throwable t) {
+ LOG.info(AaiUiMsgs.LOGIN_FILTER_INFO,
+ "getLoginIdFromCookie failed " + t.getLocalizedMessage());
+ }
+ return uid;
+ }
+
+ /**
+ * Searches the specified request for the CSP cookie, decodes it and parses it to a String array.
+ *
+ * @param request
+ * @return Array of String as parsed from the cookie; null if the cookie is not present; empty
+ * array if the cookie could not be decoded.
+ */
+ private static String[] getCspData(HttpServletRequest request) {
+ final String cookieName = PortalApiProperties.getProperty(CSP_COOKIE_NAME);
+ if (cookieName == null) {
+ LOG.debug(AaiUiMsgs.LOGIN_FILTER_DEBUG,
+ "getCspData: Failed to get property " + CSP_COOKIE_NAME);
+ return null;
+ }
+ Cookie csp = getCookie(request, cookieName);
+ if (csp == null) {
+ LOG.debug(AaiUiMsgs.LOGIN_FILTER_DEBUG, "getCspData failed to get cookie " + cookieName);
+ return null;
+ }
+ final String cspCookieEncrypted = csp.getValue();
+
+ String cspCookieDecrypted = null;
+ try {
+ cspCookieDecrypted = PortalAuthenticationConfig.getInstance().getCookieDecryptor().decryptCookie(cspCookieEncrypted);
+ return cspCookieDecrypted.split("\\|");
+
+ } catch (ClassNotFoundException e) {
+ LOG.error(AaiUiMsgs.DECRYPTION_ERROR,"Unable to find the Cookie Decryptor Class");
+ }
+
+ return null;
+ }
+} \ No newline at end of file
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/security/SecurityContextFactory.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/security/SecurityContextFactory.java
new file mode 100644
index 0000000..f251c31
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/security/SecurityContextFactory.java
@@ -0,0 +1,78 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.security;
+
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.security.KeyManagementException;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.CertificateException;
+
+import javax.net.ssl.SSLContext;
+
+/**
+ * A factory for creating SecurityContext objects.
+ */
+public interface SecurityContextFactory {
+
+ public String getSslAlgorithm();
+
+ public void setSslAlgorithm(String sslAlgorithm);
+
+ public String getKeyManagerAlgortihm();
+
+ public void setKeyManagerAlgortihm(String keyManagerAlgortihm);
+
+ public String getKeyStoreType();
+
+ public void setKeyStoreType(String keyStoreType);
+
+ public boolean isServerCertificationChainValidationEnabled();
+
+ public void setServerCertificationChainValidationEnabled(
+ boolean serverCertificationChainValidationEnabled);
+
+ public String getTrustStoreFileName();
+
+ public void setTrustStoreFileName(String filename);
+
+ public String getClientCertPassword();
+
+ public void setClientCertPassword(String password);
+
+ public void setClientCertFileInputStream(FileInputStream fis);
+
+ public void setClientCertFileName(String filename) throws IOException;
+
+ public FileInputStream getClientCertFileInputStream();
+
+ public SSLContext getSecureContext()
+ throws KeyManagementException, NoSuchAlgorithmException, FileNotFoundException,
+ KeyStoreException, CertificateException, IOException, UnrecoverableKeyException;
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/security/SecurityContextFactoryImpl.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/security/SecurityContextFactoryImpl.java
new file mode 100644
index 0000000..c09fa97
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/security/SecurityContextFactoryImpl.java
@@ -0,0 +1,205 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.security;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.security.KeyManagementException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.X509TrustManager;
+
+/**
+ * The Class SecurityContextFactoryImpl.
+ */
+public class SecurityContextFactoryImpl implements SecurityContextFactory {
+
+ protected String sslAlgorithm;
+ protected String keyManagerAlgortihm;
+ protected String keyStoreType;
+ protected boolean serverCertificationChainValidationEnabled;
+ protected String trustStoreFileName;
+ protected String clientCertPassword;
+ protected FileInputStream clientCertFileInputStream;
+ protected String clientCertFileName;
+ protected byte[] clientCertBytes;
+
+ /**
+ * Instantiates a new security context factory impl.
+ */
+ public SecurityContextFactoryImpl() {
+ this.sslAlgorithm = "TLS";
+ this.keyManagerAlgortihm = "SunX509";
+ this.keyStoreType = "PKCS12";
+ this.serverCertificationChainValidationEnabled = false;
+ this.clientCertFileInputStream = null;
+ this.clientCertFileName = null;
+ }
+
+ @Override
+ public String getSslAlgorithm() {
+ return sslAlgorithm;
+ }
+
+ @Override
+ public void setSslAlgorithm(String sslAlgorithm) {
+ this.sslAlgorithm = sslAlgorithm;
+ }
+
+ @Override
+ public String getKeyManagerAlgortihm() {
+ return keyManagerAlgortihm;
+ }
+
+ @Override
+ public void setKeyManagerAlgortihm(String keyManagerAlgortihm) {
+ this.keyManagerAlgortihm = keyManagerAlgortihm;
+ }
+
+ @Override
+ public String getKeyStoreType() {
+ return keyStoreType;
+ }
+
+ @Override
+ public void setKeyStoreType(String keyStoreType) {
+ this.keyStoreType = keyStoreType;
+ }
+
+ @Override
+ public boolean isServerCertificationChainValidationEnabled() {
+ return serverCertificationChainValidationEnabled;
+ }
+
+ @Override
+ public void setServerCertificationChainValidationEnabled(
+ boolean serverCertificationChainValidationEnabled) {
+ this.serverCertificationChainValidationEnabled = serverCertificationChainValidationEnabled;
+ }
+
+ @Override
+ public void setClientCertFileName(String filename) throws IOException {
+ this.clientCertFileName = filename;
+
+ if (filename == null) {
+ this.clientCertBytes = null;
+ } else {
+ this.clientCertBytes = Files.readAllBytes(new File(filename).toPath());
+ }
+ }
+
+ @Override
+ public void setClientCertFileInputStream(FileInputStream fis) {
+ this.clientCertFileInputStream = fis;
+ }
+
+ @Override
+ public FileInputStream getClientCertFileInputStream() {
+ return this.clientCertFileInputStream;
+ }
+
+ @Override
+ public SSLContext getSecureContext() throws KeyManagementException, NoSuchAlgorithmException,
+ KeyStoreException, CertificateException, IOException, UnrecoverableKeyException {
+
+ TrustManager[] trustAllCerts = null;
+
+ if (serverCertificationChainValidationEnabled) {
+
+ System.setProperty("javax.net.ssl.trustStore", trustStoreFileName);
+
+ } else {
+
+ // Create a trust manager that does not validate certificate chains
+ trustAllCerts = new TrustManager[] {new X509TrustManager() {
+ @Override
+ public X509Certificate[] getAcceptedIssuers() {
+ return null;
+ }
+
+ @Override
+ public void checkClientTrusted(X509Certificate[] certs, String authType) {}
+
+ @Override
+ public void checkServerTrusted(X509Certificate[] certs, String authType) {}
+ } };
+ }
+
+ KeyManagerFactory kmf = KeyManagerFactory.getInstance(keyManagerAlgortihm);
+
+ KeyStore ks = KeyStore.getInstance(keyStoreType);
+
+ char[] pwd = null;
+ if (clientCertPassword != null) {
+ pwd = clientCertPassword.toCharArray();
+ }
+
+ if (clientCertBytes != null) {
+ ks.load(new ByteArrayInputStream(clientCertBytes), pwd);
+ } else {
+ ks.load(null, pwd);
+ }
+
+ kmf.init(ks, pwd);
+
+ SSLContext ctx = SSLContext.getInstance(sslAlgorithm);
+ ctx.init(kmf.getKeyManagers(), trustAllCerts, null);
+
+ return ctx;
+
+ }
+
+ @Override
+ public String getTrustStoreFileName() {
+ return this.trustStoreFileName;
+ }
+
+ @Override
+ public void setTrustStoreFileName(String filename) {
+ this.trustStoreFileName = filename;
+ }
+
+ @Override
+ public String getClientCertPassword() {
+ return this.clientCertPassword;
+ }
+
+ @Override
+ public void setClientCertPassword(String password) {
+ this.clientCertPassword = password;
+ }
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/security/filter/CspCookieFilter.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/security/filter/CspCookieFilter.java
new file mode 100644
index 0000000..795739b
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/security/filter/CspCookieFilter.java
@@ -0,0 +1,267 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.security.filter;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Properties;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.onap.aai.cl.api.Logger;
+import org.onap.aai.cl.eelf.LoggerFactory;
+import org.onap.aai.cl.mdc.MdcContext;
+import org.onap.aai.sparky.logging.AaiUiMsgs;
+import org.onap.aai.sparky.util.NodeUtils;
+import org.onap.aai.sparky.viewandinspect.config.SparkyConstants;
+
+// import esGateKeeper.esGateKeeper;
+
+/**
+ * Redirects to the AT&T global login page if the user is not authenticated.<br>
+ * Filter properties need to be configured in: csp-cookie-filter.properties
+ */
+public class CspCookieFilter implements Filter {
+
+ /** Redirect URL for the login page. */
+ private String globalLoginUrl;
+
+ /** Application identifier. */
+ private String applicationId;
+
+ /** Gatekeeper environment setting (development or production). */
+ private String gateKeeperEnvironment;
+
+ private static final String FILTER_PARAMETER_CONFIG = "config";
+ private static final String PROPERTY_GLOBAL_LOGIN_URL = "global.login.url";
+ private static final String PROPERTY_APPLICATION_ID = "application.id";
+ private static final String PROPERTY_GATEKEEPER_ENVIRONMENT = "gatekeeper.environment";
+ // valid open redirect domains
+ private List<String> redirectDomains = new ArrayList<>();
+ private static final String PROPERTY_REDIRECT_DOMAINS = "redirect-domain";
+
+ /** Needed by esGateKeeper, does not accept any other value. */
+ private static final String GATEKEEPER_ACCOUNT_NAME = "CSP";
+
+ private static final Logger LOG = LoggerFactory.getInstance().getLogger(CspCookieFilter.class);
+
+
+ /* (non-Javadoc)
+ * @see javax.servlet.Filter#init(javax.servlet.FilterConfig)
+ */
+ @Override
+ public void init(FilterConfig filterConfig) throws ServletException {
+ String txnID = NodeUtils.getRandomTxnId();
+ MdcContext.initialize(txnID, "CspCookieFilter", "", "Init", "");
+
+ try {
+ setConfigurationProperties(filterConfig);
+ } catch (IOException exc) {
+ LOG.error(AaiUiMsgs.ERROR_CSP_CONFIG_FILE);
+ throw new ServletException(exc);
+ }
+ }
+
+
+ /* (non-Javadoc)
+ * @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain)
+ */
+ @Override
+ public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
+ throws IOException, ServletException {
+ HttpServletRequest request = (HttpServletRequest) req;
+ HttpServletResponse response = (HttpServletResponse) res;
+
+ Cookie[] cookies = request.getCookies();
+ if ((cookies == null) || (cookies.length == 0)) {
+ doLogin(request, response);
+ return;
+ }
+
+ /*
+ * String attEsSec = getSecurityCookie(cookies);
+ *
+ * if (attESSec == null || attESSec.length() == 0) { doLogin(request, response); return; }
+ *
+ * String attESSecUnEncrypted = esGateKeeper.esGateKeeper(attESSec, GATEKEEPER_ACCOUNT_NAME,
+ * gateKeeperEnvironment); if (attESSecUnEncrypted == null) { doLogin(request, response); } else
+ * {
+ */
+ // LOG.info("User has valid cookie");
+ chain.doFilter(request, response);
+ // }
+ }
+
+
+ /* (non-Javadoc)
+ * @see javax.servlet.Filter#destroy()
+ */
+ @Override
+ public void destroy() {}
+
+ /**
+ * Sets all required properties needed by this filter.
+ *
+ * @param filterConfig the filter configuration defined in the application web.xml
+ * @throws IOException if the properties failed to load.
+ */
+ private void setConfigurationProperties(FilterConfig filterConfig) throws IOException {
+ InputStream inputStream = new FileInputStream(SparkyConstants.CONFIG_HOME
+ + filterConfig.getInitParameter(FILTER_PARAMETER_CONFIG));
+ Properties cspProperties = new Properties();
+ cspProperties.load(inputStream);
+ globalLoginUrl = cspProperties.getProperty(PROPERTY_GLOBAL_LOGIN_URL);
+ applicationId = cspProperties.getProperty(PROPERTY_APPLICATION_ID);
+ gateKeeperEnvironment = cspProperties.getProperty(PROPERTY_GATEKEEPER_ENVIRONMENT);
+ redirectDomains = Arrays.asList(cspProperties.getProperty(PROPERTY_REDIRECT_DOMAINS).split(","));
+ }
+
+ /**
+ * Returns the attESSec cookie if found in the client.
+ *
+ * @param cookies the cookies available in the client
+ * @return the attESSec authentication cookie generated by the login page.
+ */
+ private String getSecurityCookie(Cookie[] cookies) {
+ String attEsSec = null;
+ for (int i = 0; i < cookies.length; i++) {
+ Cookie thisCookie = cookies[i];
+ String cookieName = thisCookie.getName();
+
+ if ("attESSec".equals(cookieName)) {
+ attEsSec = thisCookie.getValue();
+ break;
+ }
+ }
+ return attEsSec;
+ }
+
+ /**
+ * Redirects to the AT&T global login page. If this is an AJAX request it returns an unauthorized
+ * HTTP error in the response.
+ *
+ * @param request the filter request object
+ * @param response the filter response object
+ * @throws IOException if there is an error setting the error response
+ */
+ private void doLogin(HttpServletRequest request, HttpServletResponse response)
+ throws IOException {
+ if (isAjaxRequest(request)) {
+ response.sendError(HttpServletResponse.SC_UNAUTHORIZED,
+ "User is not authorized. Please login to application");
+ } else {
+ // Fix for Safari 7.0.2 onwards to avoid login page cache
+ response.addHeader("Cache-Control", "no-cache, no-store");
+ String redirectURL = createRedirectUrl(request);
+ if (this.isValidRedirectURL(redirectURL)){
+ response.sendRedirect(redirectURL);
+ LOG.debug(AaiUiMsgs.VALID_REDIRECT_URL, redirectURL);
+ } else{
+ response.sendError(400, "Bad redirect URL");
+ LOG.error(AaiUiMsgs.INVALID_REDIRECT_URL, redirectURL);
+ }
+ }
+ }
+
+ /**
+ * Checks if a redirect url is valid
+ * @param url URL to validate
+ * @return true if URL is a valid redirect URL, false otherwise
+ */
+ private boolean isValidRedirectURL (String url){
+ String redirectTo = url.substring(url.indexOf("?retURL=")+ "?retURL=".length());
+ try {
+ redirectTo = URLDecoder.decode(redirectTo, StandardCharsets.UTF_8.toString());
+ } catch (UnsupportedEncodingException e) {
+ LOG.error(AaiUiMsgs.UNSUPPORTED_URL_ENCODING, e.getLocalizedMessage());
+ return false;
+ }
+ for (String domain: this.redirectDomains){
+ if (redirectTo.endsWith(domain))
+ return true;
+ }
+ return false;
+ }
+
+
+ /**
+ * Returns <code>true</code> if the request is an AJAX request.
+ *
+ * @param request the filter request object
+ * @return <code>true</code> if the request is an AJAX request.
+ */
+ private boolean isAjaxRequest(HttpServletRequest request) {
+ String headerValue = request.getHeader("X-Requested-With");
+ if ("XMLHttpRequest".equals(headerValue)) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Returns the redirection URL to the AT&T Global login page.
+ *
+ * @param request the request
+ * @return the string
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ */
+ private String createRedirectUrl(HttpServletRequest request) throws UnsupportedEncodingException {
+ String returnUrl = getReturnUrl(request);
+
+ return globalLoginUrl + "?retURL=" + returnUrl + "&sysName=" + applicationId;
+ }
+
+ /**
+ * Gets the URL encoded return URL.
+ *
+ * @param request the HTTP request
+ * @return an encoded URL to return to following login
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ */
+ private String getReturnUrl(HttpServletRequest request) throws UnsupportedEncodingException {
+ StringBuffer retUrl = request.getRequestURL();
+ String urlParams = request.getQueryString();
+ if (urlParams != null) {
+ retUrl.append("?" + urlParams);
+ }
+ return URLEncoder.encode(retUrl.toString(), StandardCharsets.UTF_8.toString());
+ }
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/security/filter/LoginFilter.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/security/filter/LoginFilter.java
new file mode 100644
index 0000000..dd90573
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/security/filter/LoginFilter.java
@@ -0,0 +1,236 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.security.filter;
+
+import java.io.IOException;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import javax.ws.rs.core.HttpHeaders;
+
+import org.onap.aai.cl.api.Logger;
+import org.onap.aai.cl.eelf.LoggerFactory;
+import org.onap.aai.sparky.logging.AaiUiMsgs;
+import org.onap.aai.sparky.security.EcompSso;
+import org.onap.aai.sparky.security.portal.config.PortalAuthenticationConfig;
+import org.openecomp.portalsdk.core.onboarding.listener.PortalTimeoutHandler;
+import org.openecomp.portalsdk.core.onboarding.util.PortalApiConstants;
+import org.openecomp.portalsdk.core.onboarding.util.PortalApiProperties;
+import org.openecomp.portalsdk.core.onboarding.util.SSOUtil;
+
+/**
+ * This filter checks every request for proper ECOMP Portal single sign on initialization. The
+ * possible paths and actions:
+ * <OL>
+ * <LI>User starts at an app page via a bookmark. No ECOMP portal cookie is set. Redirect there to
+ * get one; then continue as below.
+ * <LI>User starts at ECOMP Portal and goes to app. Alternately, the user's session times out and
+ * the user hits refresh. The ECOMP Portal cookie is set, but there is no valid session. Create one
+ * and publish info.
+ * <LI>User has valid ECOMP Portal cookie and session. Reset the max idle in that session.
+ * </OL>
+ * <P>
+ * Notes:
+ * <UL>
+ * <LI>Portal Session should be up prior to App Session</LI>
+ * <LI>If App Session Expires or if EPService cookie is unavailable, we need to redirect to Portal.
+ * <LI>Method {@link #initiateSessionMgtHandler(HttpServletRequest)} should be called for Session
+ * management when the initial session is created
+ * <LI>While redirecting, the cookie "redirectUrl" should also be set so that Portal knows where to
+ * forward the request to once the Portal Session is created and EPService cookie is set.
+ * <LI>Method {@link #resetSessionMaxIdleTimeOut(HttpServletRequest)} should be called for every
+ * request to reset the MaxInactiveInterval to the right value.
+ * </UL>
+ * <P>
+ * This filter incorporates most features of the SDK application's SessionTimeoutInterceptor and
+ * SingleSignOnController classes
+ */
+public class LoginFilter implements Filter {
+
+ private static final Logger LOG = LoggerFactory.getInstance().getLogger(LoginFilter.class);
+
+ @Override
+ public void init(FilterConfig filterConfig) throws ServletException {
+ // Validate that app has provided useful portal properties
+ if (PortalApiProperties.getProperty(PortalApiConstants.ECOMP_REDIRECT_URL) == null) {
+ throw new ServletException("Failed to find URL in portal.properties");
+ }
+
+ PortalAuthenticationConfig appProperties;
+ try {
+ appProperties = PortalAuthenticationConfig.getInstance();
+ } catch (Exception ex) {
+ throw new ServletException("Failed to get properties", ex);
+ }
+
+ String restUser = appProperties.getUsername();
+ String restPassword = appProperties.getPassword();
+ if (restUser == null || restPassword == null) {
+ throw new ServletException("Failed to find user and/or password from properties");
+ }
+ }
+
+ @Override
+ public void destroy() {
+ // No resources to release
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse,
+ * javax.servlet.FilterChain)
+ */
+ @Override
+ public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
+ throws ServletException, IOException {
+ HttpServletRequest request = (HttpServletRequest) req;
+ HttpServletResponse response = (HttpServletResponse) res;
+
+ // Choose authentication appropriate for the request.
+ final String restApiURI = request.getContextPath() + PortalApiConstants.API_PREFIX;
+ if (request.getRequestURI().startsWith(restApiURI)) {
+ // REST servlet checks credentials
+ LOG.debug(AaiUiMsgs.LOGIN_FILTER_DEBUG, "doFilter: delegating auth to REST servlet for request " + request.getRequestURI());
+ chain.doFilter(request, response);
+ } else {
+ // All other requests require ECOMP Portal authentication
+ if (EcompSso.validateEcompSso(request) == null) {
+ String redirectURL, logMessage;
+ if (request.getRequestURI().contains("/editAttributes")) {
+ // If request is for Edit Attributes UI, redirect straight to the application.
+ String appPath = request.getRequestURI().substring(request.getContextPath().length() + 1)
+ + (request.getQueryString() != null ? ("?" + request.getQueryString()) : "");
+ redirectURL = SSOUtil.getECOMPSSORedirectURL(request, response, appPath);
+ logMessage = "Unauthenticated Edit Attributes UI login attempt.";
+ } else {
+ // Redirect to Portal UI
+ redirectURL = PortalApiProperties.getProperty(PortalApiConstants.ECOMP_REDIRECT_URL);
+ logMessage = "Unauthorized login attempt.";
+ }
+
+ LOG.debug(AaiUiMsgs.LOGIN_FILTER_DEBUG,
+ logMessage +
+ " | Remote IP: " + request.getRemoteAddr() +
+ " | User agent: " + request.getHeader(HttpHeaders.USER_AGENT) +
+ " | Request URL: " + request.getRequestURL() +
+ " | Redirecting to: " + redirectURL);
+
+ response.sendRedirect(redirectURL);
+ } else {
+ HttpSession session = request.getSession(false);
+ if (session == null) {
+ // New session
+ session = request.getSession(true);
+ LOG.debug(AaiUiMsgs.LOGIN_FILTER_DEBUG, "doFilter: created new session " + session.getId());
+ initiateSessionMgtHandler(request);
+ } else {
+ // Existing session
+ LOG.debug(AaiUiMsgs.LOGIN_FILTER_DEBUG, "doFilter: resetting idle in existing session " + session.getId());
+ resetSessionMaxIdleTimeOut(request);
+ }
+ // Pass request back down the filter chain
+ chain.doFilter(request, response);
+ }
+ }
+ }
+
+ /**
+ * Publishes information about the session.
+ *
+ * @param request
+ */
+ private void initiateSessionMgtHandler(HttpServletRequest request) {
+ String portalJSessionId = getPortalJSessionId(request);
+ String jSessionId = getJessionId(request);
+ storeMaxInactiveTime(request);
+ PortalTimeoutHandler.sessionCreated(portalJSessionId, jSessionId, request.getSession(false));
+ }
+
+ /**
+ * Gets the ECOMP Portal service cookie value.
+ *
+ * @param request
+ * @return Cookie value, or null if not found.
+ */
+ private String getPortalJSessionId(HttpServletRequest request) {
+ Cookie ep = EcompSso.getCookie(request, EcompSso.EP_SERVICE);
+ return ep == null ? null : ep.getValue();
+ }
+
+ /**
+ * Gets the container session ID.
+ *
+ * @param request
+ * @return Session ID, or null if no session.
+ */
+ private String getJessionId(HttpServletRequest request) {
+ HttpSession session = request.getSession();
+ return session == null ? null : session.getId();
+ }
+
+ /**
+ * Sets the global session's max idle time to the session's max inactive interval.
+ *
+ * @param request
+ */
+ private void storeMaxInactiveTime(HttpServletRequest request) {
+ HttpSession session = request.getSession(false);
+ if (session != null
+ && session.getAttribute(PortalApiConstants.GLOBAL_SESSION_MAX_IDLE_TIME) == null) {
+ session.setAttribute(PortalApiConstants.GLOBAL_SESSION_MAX_IDLE_TIME,
+ session.getMaxInactiveInterval());
+ }
+ }
+
+ /**
+ * Sets the session's max inactive interval.
+ *
+ * @param request
+ */
+ private void resetSessionMaxIdleTimeOut(HttpServletRequest request) {
+ try {
+ HttpSession session = request.getSession(false);
+ if (session != null) {
+ final Object maxIdleAttribute = session
+ .getAttribute(PortalApiConstants.GLOBAL_SESSION_MAX_IDLE_TIME);
+ if (maxIdleAttribute != null) {
+ session.setMaxInactiveInterval(Integer.parseInt(maxIdleAttribute.toString()));
+ }
+ }
+ } catch (Exception e) {
+ LOG.info(AaiUiMsgs.LOGIN_FILTER_INFO, "resetSessionMaxIdleTimeOut: failed to set session max inactive interval - " + e.getLocalizedMessage());
+ }
+ }
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/security/portal/PortalRestAPIServiceImpl.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/security/portal/PortalRestAPIServiceImpl.java
new file mode 100644
index 0000000..ad64c63
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/security/portal/PortalRestAPIServiceImpl.java
@@ -0,0 +1,213 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.security.portal;
+
+import java.io.File;
+import java.io.IOException;
+import java.text.MessageFormat;
+import java.util.LinkedHashSet;
+import java.util.List;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.onap.aai.sparky.security.EcompSso;
+import org.onap.aai.sparky.security.portal.config.PortalAuthenticationConfig;
+import org.onap.aai.sparky.viewandinspect.config.SparkyConstants;
+import org.openecomp.portalsdk.core.onboarding.crossapi.IPortalRestAPIService;
+import org.openecomp.portalsdk.core.onboarding.exception.PortalAPIException;
+import org.openecomp.portalsdk.core.restful.domain.EcompRole;
+import org.openecomp.portalsdk.core.restful.domain.EcompUser;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Responds to ECOMP Portal's REST queries for user and role information and management.
+ */
+public class PortalRestAPIServiceImpl implements IPortalRestAPIService {
+
+ private static final Logger LOG = LoggerFactory.getLogger(PortalRestAPIServiceImpl.class);
+ private static final String ERROR_MESSAGE = "Failed to {0} user [loginId:{1}]";
+
+ private UserManager userManager;
+
+ /**
+ * Initialise user manager.
+ */
+ public PortalRestAPIServiceImpl() {
+ userManager = new UserManager(new File(SparkyConstants.USERS_FILE_LOCATION));
+ }
+
+ /////////////////////////////////////////////////////////////////////////////
+ // User interface
+ /////////////////////////////////////////////////////////////////////////////
+
+ /*
+ * (non-Javadoc)
+ *
+ */
+ @Override
+ public void pushUser(EcompUser user) throws PortalAPIException {
+ LOG.debug("Push user [loginId:" + user.getLoginId() + "]");
+
+ if (userManager.getUser(user.getLoginId()).isPresent()) {
+ String message = getMessage(ERROR_MESSAGE, "push", user.getLoginId())
+ + ", user is already stored";
+ LOG.error(message);
+ throw new PortalAPIException(message);
+ }
+
+ try {
+ userManager.pushUser(user);
+ } catch (IOException e) {
+ String message = getMessage(ERROR_MESSAGE, "push", user.getLoginId());
+ LOG.error(message, e);
+ throw new PortalAPIException(message, e);
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ */
+ @Override
+ public void editUser(String loginId, EcompUser user) throws PortalAPIException {
+ LOG.debug("Edit user [loginId:" + loginId + "]");
+
+ userManager.getUser(loginId).orElseThrow(() -> {
+ String message = getMessage(ERROR_MESSAGE, "edit", loginId) + ", unknown user";
+ LOG.error(message);
+ return new PortalAPIException(message);
+ });
+
+ try {
+ userManager.editUser(loginId, user);
+ } catch (IOException e) {
+ String message = getMessage(ERROR_MESSAGE, "edit", loginId);
+ LOG.error(message, e);
+ throw new PortalAPIException(message, e);
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ */
+ @Override
+ public EcompUser getUser(String loginId) throws PortalAPIException {
+ LOG.debug("Get user [loginId:" + loginId + "]");
+ return userManager.getUser(loginId).orElseThrow(() -> {
+ String message = getMessage(ERROR_MESSAGE, "get", loginId) + ", unknown user";
+ LOG.error(message);
+ return new PortalAPIException(message);
+ });
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ */
+ @Override
+ public List<EcompUser> getUsers() throws PortalAPIException {
+ LOG.debug("Get users");
+ return userManager.getUsers();
+ }
+
+ @Override
+ public String getUserId(HttpServletRequest request) throws PortalAPIException {
+ return EcompSso.validateEcompSso(request);
+ }
+
+ /////////////////////////////////////////////////////////////////////////////
+ // Role interface
+ /////////////////////////////////////////////////////////////////////////////
+
+ public List<EcompRole> getAvailableRoles() throws PortalAPIException {
+ LOG.debug("Get available roles");
+ return UserManager.getRoles();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ */
+ @Override
+ public List<EcompRole> getUserRoles(String loginId) throws PortalAPIException {
+ LOG.debug("Get user roles");
+ return userManager.getUserRoles(loginId);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ */
+ @Override
+ public void pushUserRole(String loginId, List<EcompRole> roles) throws PortalAPIException {
+ LOG.debug("Push user role [loginId:" + loginId + "]");
+ try {
+ EcompUser user = getUser(loginId);
+ if (roles != null) {
+ user.setRoles(new LinkedHashSet<EcompRole>(roles));
+ } else {
+ user.setRoles(new LinkedHashSet<EcompRole>());
+ }
+ editUser(loginId, user);
+ } catch (PortalAPIException e) {
+ String message = getMessage(ERROR_MESSAGE, "push role", loginId);
+ LOG.error(message);
+ throw new PortalAPIException(message, e);
+ }
+ }
+
+ /////////////////////////////////////////////////////////////////////////////
+ // Security interface
+ /////////////////////////////////////////////////////////////////////////////
+
+ /*
+ * (non-Javadoc)
+ *
+ */
+ @Override
+ public boolean isAppAuthenticated(HttpServletRequest request) throws PortalAPIException {
+ LOG.debug("Authentication request");
+ PortalAuthenticationConfig config = PortalAuthenticationConfig.getInstance();
+ String restUsername = request.getHeader(PortalAuthenticationConfig.PROP_USERNAME);
+ String restPassword = request.getHeader(PortalAuthenticationConfig.PROP_PASSWORD);
+ return restUsername != null && restPassword != null && restUsername.equals(config.getUsername())
+ && restPassword.equals(config.getPassword());
+ }
+
+ private String getMessage(String message, Object... args) {
+ MessageFormat formatter = new MessageFormat("");
+ formatter.applyPattern(message);
+ return formatter.format(args);
+ }
+
+ public List<EcompRole> getAvailableRoles(String requestedLoginId) throws PortalAPIException {
+ LOG.debug("Get available roles");
+ return UserManager.getRoles();
+ }
+
+} \ No newline at end of file
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/security/portal/UserManager.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/security/portal/UserManager.java
new file mode 100644
index 0000000..ea9b204
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/security/portal/UserManager.java
@@ -0,0 +1,170 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.security.portal;
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.Type;
+import java.nio.file.Files;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+import java.util.stream.Collectors;
+
+import org.onap.aai.sparky.security.portal.config.RolesConfig;
+import org.openecomp.portalsdk.core.restful.domain.EcompRole;
+import org.openecomp.portalsdk.core.restful.domain.EcompUser;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.reflect.TypeToken;
+
+/**
+ * Basic file based user storage.
+ */
+public class UserManager {
+
+ private File usersFile;
+
+ private static final ReadWriteLock LOCK = new ReentrantReadWriteLock(true);
+ private static final Lock READ_LOCK = LOCK.readLock();
+ private static final Lock WRITE_LOCK = LOCK.writeLock();
+
+ private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create();
+
+ /**
+ *
+ * @param usersFile a file to store the users
+ */
+ public UserManager(File usersFile) {
+ this.usersFile = usersFile;
+ }
+
+ /**
+ * Returns all users stored.
+ *
+ * @return a list of users.
+ */
+ public List<EcompUser> getUsers() {
+ Type collectionType = new TypeToken<List<EcompUser>>() {
+ }.getType();
+
+ Optional<String> users = read(usersFile);
+ if (users.isPresent()) {
+ return GSON.fromJson(users.get(), collectionType);
+ }
+
+ return new ArrayList<>();
+ }
+
+ /**
+ * Returns a stored user.
+ *
+ * @param loginId the identifier of the user
+ * @return an optional user.
+ */
+ public Optional<EcompUser> getUser(String loginId) {
+ if (!getUsers().isEmpty()) {
+ return getUsers().stream().filter(u -> loginId.equals(u.getLoginId())).findFirst();
+ }
+ return Optional.empty();
+ }
+
+ /**
+ * Stores a user if not already stored.
+ *
+ * @param user the user to be stored
+ * @throws IOException
+ */
+ public void pushUser(EcompUser user) throws IOException {
+ WRITE_LOCK.lock();
+ try {
+ if (!getUser(user.getLoginId()).isPresent()) {
+ addUser(getUsers(), user);
+ }
+ } finally {
+ WRITE_LOCK.unlock();
+ }
+ }
+
+ /**
+ * Replaces an existing user.
+ *
+ * @param loginId the id of the user
+ * @param user the new user details
+ * @throws IOException
+ */
+ public void editUser(String loginId, EcompUser user) throws IOException {
+ WRITE_LOCK.lock();
+ try {
+ if (getUser(loginId).isPresent()) {
+ List<EcompUser> users = getUsers().stream().filter(u -> !u.getLoginId().equals(loginId))
+ .collect(Collectors.toList());
+ addUser(users, user);
+ }
+ } finally {
+ WRITE_LOCK.unlock();
+ }
+ }
+
+ /**
+ * Gets the roles assigned to a user.
+ *
+ * @param loginId the id of the user
+ * @return the assigned roles
+ */
+ public List<EcompRole> getUserRoles(String loginId) {
+ List<EcompRole> roles = new ArrayList<>();
+ roles.addAll(getUser(loginId).orElseGet(EcompUser::new).getRoles());
+ return roles;
+ }
+
+ public static List<EcompRole> getRoles() {
+ return RolesConfig.getInstance().getRoles();
+ }
+
+ private void addUser(List<EcompUser> users, EcompUser user) throws IOException {
+ users.add(user);
+ write(users);
+ }
+
+ private void write(List<EcompUser> users) throws IOException {
+ Files.write(usersFile.toPath(), GSON.toJson(users).getBytes());
+ }
+
+ private Optional<String> read(File file) {
+ READ_LOCK.lock();
+ try {
+ return Optional.of(new String(Files.readAllBytes(file.toPath())));
+ } catch (IOException e) { // NOSONAR
+ return Optional.empty();
+ } finally {
+ READ_LOCK.unlock();
+ }
+ }
+} \ No newline at end of file
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/security/portal/config/PortalAuthenticationConfig.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/security/portal/config/PortalAuthenticationConfig.java
new file mode 100644
index 0000000..e1b7eda
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/security/portal/config/PortalAuthenticationConfig.java
@@ -0,0 +1,124 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.security.portal.config;
+
+
+import java.util.Properties;
+
+import org.onap.aai.cl.api.Logger;
+import org.onap.aai.cl.eelf.LoggerFactory;
+import org.onap.aai.sparky.logging.AaiUiMsgs;
+import org.onap.aai.sparky.security.CookieDecryptor;
+import org.onap.aai.sparky.util.ConfigHelper;
+import org.onap.aai.sparky.util.Encryptor;
+import org.onap.aai.sparky.viewandinspect.config.SparkyConstants;
+
+
+/**
+ * Provides Portal authentication configuration.
+ */
+public class PortalAuthenticationConfig {
+
+ private String username;
+ private String password;
+ private boolean isOnapEnabled;
+ private CookieDecryptor cookieDecryptor;
+ private String cookieDecryptorClassName;
+
+ public static final String PROP_USERNAME = "username";
+ public static final String PROP_PASSWORD = "password"; // NOSONAR
+ public static final String PROP_IS_ONAP_ENABLED = "onap_enabled"; // NOSONAR
+ private static final String AUTHENTICATION_CONFIG_FILE = SparkyConstants.PORTAL_AUTHENTICATION_FILE_LOCATION;
+ public static final String PROP_COOKIEDECRYPTORCLASSNAME = "cookie_decryptor_classname";
+ private static final Logger LOG = LoggerFactory.getInstance().getLogger(PortalAuthenticationConfig.class);
+
+ private PortalAuthenticationConfig() {
+ // Prevent instantiation
+ }
+
+ private static class PortalAuthenticationConfigHelper {
+ private static final PortalAuthenticationConfig INSTANCE = new PortalAuthenticationConfig();
+
+ private PortalAuthenticationConfigHelper() {
+ // Deliberately empty
+ }
+ }
+
+ /**
+ * Get a singleton instance of the configuration.
+ *
+ * @return
+ */
+ public static PortalAuthenticationConfig getInstance() {
+ PortalAuthenticationConfigHelper.INSTANCE.load();
+ return PortalAuthenticationConfigHelper.INSTANCE;
+ }
+
+ public String getUsername() {
+ return username;
+ }
+
+ public String getPassword() {
+ Encryptor encryptor = new Encryptor();
+ return encryptor.decryptValue(password);
+ }
+
+ public boolean getIsOnapEnabled() {
+ return isOnapEnabled;
+ }
+ public String getcookieDecryptorClassName() {
+ return cookieDecryptorClassName;
+ }
+
+ /**
+ * Reload the Portal authentication properties from the classpath.
+ */
+ public void reload() {
+ load();
+ }
+
+ /**
+ * Load the Portal authentication properties from the classpath.
+ */
+ private void load() {
+ Properties props = ConfigHelper.loadConfigFromExplicitPath(AUTHENTICATION_CONFIG_FILE);
+ username = props.getProperty(PROP_USERNAME);
+ password = props.getProperty(PROP_PASSWORD);
+ isOnapEnabled = Boolean.parseBoolean(props.getProperty(PROP_IS_ONAP_ENABLED, "true"));
+ cookieDecryptorClassName= props.getProperty(PROP_COOKIEDECRYPTORCLASSNAME);
+ }
+
+ public CookieDecryptor getCookieDecryptor() throws ClassNotFoundException{
+
+ Class cookieDecrypterClass = Class.forName(cookieDecryptorClassName);
+ try {
+ cookieDecryptor = (CookieDecryptor) cookieDecrypterClass.newInstance();
+ } catch (InstantiationException | IllegalAccessException e) {
+ LOG.error(AaiUiMsgs.DECRYPTION_ERROR,"Unable to instantiate Cookie Decryptor Class");
+ }
+ return cookieDecryptor;
+ }
+
+} \ No newline at end of file
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/security/portal/config/RolesConfig.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/security/portal/config/RolesConfig.java
new file mode 100644
index 0000000..283834c
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/security/portal/config/RolesConfig.java
@@ -0,0 +1,90 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.security.portal.config;
+
+import java.io.IOException;
+import java.lang.reflect.Type;
+import java.net.URISyntaxException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.Collections;
+import java.util.List;
+
+import org.onap.aai.sparky.viewandinspect.config.SparkyConstants;
+import org.openecomp.portalsdk.core.restful.domain.EcompRole;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonSyntaxException;
+import com.google.gson.reflect.TypeToken;
+
+/**
+ * Provides roles configuration.
+ */
+public class RolesConfig {
+
+ private List<EcompRole> roles;
+
+ private static final Gson GSON = new Gson();
+ private static final String ROLES_CONFIG_FILE = SparkyConstants.ROLES_FILE_LOCATION;
+
+ private RolesConfig() {
+ // Prevent instantiation
+ }
+
+ private static class RolesConfigHelper {
+ private static final RolesConfig INSTANCE = new RolesConfig();
+
+ private RolesConfigHelper() {
+ // Deliberately empty
+ }
+ }
+
+ /**
+ * Get a singleton instance of the configuration.
+ *
+ * @return
+ */
+ public static RolesConfig getInstance() {
+ try {
+ RolesConfigHelper.INSTANCE.load();
+ } catch (Exception e) {
+ throw new ExceptionInInitializerError(e);
+ }
+
+ return RolesConfigHelper.INSTANCE;
+ }
+
+ public List<EcompRole> getRoles() {
+ return roles;
+ }
+
+ private void load() throws JsonSyntaxException, IOException, URISyntaxException {
+ Type collectionType = new TypeToken<List<EcompRole>>() {
+ }.getType();
+
+ roles = Collections.unmodifiableList(GSON
+ .fromJson(new String(Files.readAllBytes(Paths.get(ROLES_CONFIG_FILE))), collectionType));
+ }
+} \ No newline at end of file
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/subscription/SubscriptionServiceProcessor.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/subscription/SubscriptionServiceProcessor.java
new file mode 100644
index 0000000..a8dd131
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/subscription/SubscriptionServiceProcessor.java
@@ -0,0 +1,74 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.subscription;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.camel.Exchange;
+import org.onap.aai.cl.api.Logger;
+import org.onap.aai.cl.eelf.LoggerFactory;
+import org.onap.aai.restclient.client.OperationResult;
+import org.onap.aai.sparky.logging.AaiUiMsgs;
+import org.onap.aai.sparky.logging.util.ServletUtils;
+import org.onap.aai.sparky.subscription.services.SubscriptionService;
+
+public class SubscriptionServiceProcessor {
+
+ private static final String EMPTY_RESPONSE = "{}";
+
+ private static final Logger LOG =
+ LoggerFactory.getInstance().getLogger(SubscriptionServiceProcessor.class);
+
+ SubscriptionService subService;
+
+
+ public SubscriptionServiceProcessor(SubscriptionService subscriptionService) {
+ this.subService = subscriptionService;
+ }
+
+
+ public void getSubscription(Exchange exchange) {
+
+ HttpServletRequest request = exchange.getIn().getBody(HttpServletRequest.class);
+ ServletUtils.setUpMdcContext(exchange, request);
+
+ OperationResult subscriptionResult = null;
+
+ try {
+
+ subscriptionResult = subService.buildSubscriptionPayload();
+
+ } catch (Exception exc) {
+ subscriptionResult = new OperationResult();
+ subscriptionResult.setResult(EMPTY_RESPONSE);
+ LOG.error(AaiUiMsgs.FAILURE_TO_PROCESS_REQUEST,
+ "Exception thrown during subscription processing: " + exc.getLocalizedMessage());
+ }
+
+ exchange.getOut().setBody(subscriptionResult.getResult());
+
+
+ }
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/subscription/config/SubscriptionConfig.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/subscription/config/SubscriptionConfig.java
new file mode 100644
index 0000000..37c6c4d
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/subscription/config/SubscriptionConfig.java
@@ -0,0 +1,139 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.subscription.config;
+
+import java.util.Collection;
+
+
+/**
+ * The Class SubscriptionConfig.
+ */
+public class SubscriptionConfig {
+
+ private static final String EMPTY_TARGET = "";
+ private static final String EMPTY_ORIGIN = "";
+ private static final String EMPTY_MESSAGE_TYPE = "";
+ private static final String EMPTY_TOPIC = "";
+
+
+ private String subscriptionTarget = EMPTY_TARGET;
+ private String subscriptionOrigin = EMPTY_ORIGIN;
+ private String subscriptionMessageType = EMPTY_MESSAGE_TYPE;
+ private String subscriptionTopic = EMPTY_TOPIC;
+
+ private String launchOITarget = EMPTY_TARGET;
+ private String launchOIOrigin = EMPTY_ORIGIN;
+ private String launchOIMessageType = EMPTY_MESSAGE_TYPE;
+ private String launchOITopic = EMPTY_TOPIC;
+
+ private Boolean isLaunchOIEnabled = false;
+
+ private Collection<String> annEntitiyTypes;
+
+ /**
+ * Instantiates a new Subscription config.
+ */
+ public SubscriptionConfig() {}
+
+ public String getSubscriptionTarget() {
+ return subscriptionTarget;
+ }
+
+ public void setSubscriptionTarget(String target) {
+ this.subscriptionTarget = target;
+ }
+
+ public String getSubscriptionOrigin() {
+ return subscriptionOrigin;
+ }
+
+ public void setSubscriptionOrigin(String origin) {
+ this.subscriptionOrigin = origin;
+ }
+
+ public String getSubscriptionMessageType() {
+ return subscriptionMessageType;
+ }
+
+ public void setSubscriptionMessageType(String messageType) {
+ this.subscriptionMessageType = messageType;
+ }
+
+ public String getSubscriptionTopic() {
+ return subscriptionTopic;
+ }
+
+ public void setSubscriptionTopic(String topic) {
+ this.subscriptionTopic = topic;
+ }
+
+ public String getLaunchOITarget() {
+ return launchOITarget;
+ }
+
+ public void setLaunchOITarget(String launchOITarget) {
+ this.launchOITarget = launchOITarget;
+ }
+
+ public String getLaunchOIOrigin() {
+ return launchOIOrigin;
+ }
+
+ public void setLaunchOIOrigin(String launchOIOrigin) {
+ this.launchOIOrigin = launchOIOrigin;
+ }
+
+ public String getLaunchOIMessageType() {
+ return launchOIMessageType;
+ }
+
+ public void setLaunchOIMessageType(String launchOIMessageType) {
+ this.launchOIMessageType = launchOIMessageType;
+ }
+
+ public String getLaunchOITopic() {
+ return launchOITopic;
+ }
+
+ public void setLaunchOITopic(String launchOITopic) {
+ this.launchOITopic = launchOITopic;
+ }
+
+ public Collection<String> getAnnEntitiyTypes() {
+ return annEntitiyTypes;
+ }
+
+ public void setAnnEntitiyTypes(Collection<String> annEntitiyTypes) {
+ this.annEntitiyTypes = annEntitiyTypes;
+ }
+
+ public Boolean getIsLaunchOIEnabled() {
+ return isLaunchOIEnabled;
+ }
+
+ public void setIsLaunchOIEnabled(Boolean isLaunchOIEnabled) {
+ this.isLaunchOIEnabled = isLaunchOIEnabled;
+ }
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/subscription/payload/entity/Message.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/subscription/payload/entity/Message.java
new file mode 100644
index 0000000..89489f3
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/subscription/payload/entity/Message.java
@@ -0,0 +1,60 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.subscription.payload.entity;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+
+@JsonInclude(JsonInclude.Include.NON_NULL)
+@JsonPropertyOrder({ "applicationName", "payload" })
+public class Message {
+
+ @JsonProperty("applicationName")
+ private String applicationName;
+ @JsonProperty("payload")
+ private Payload payload;
+
+ @JsonProperty("applicationName")
+ public String getApplicationName() {
+ return applicationName;
+ }
+
+ @JsonProperty("applicationName")
+ public void setApplicationName(String applicationName) {
+ this.applicationName = applicationName;
+ }
+
+ @JsonProperty("payload")
+ public Payload getPayload() {
+ return payload;
+ }
+
+ @JsonProperty("payload")
+ public void setPayload(Payload payload) {
+ this.payload = payload;
+ }
+
+} \ No newline at end of file
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/subscription/payload/entity/ObjectInspectorPayload.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/subscription/payload/entity/ObjectInspectorPayload.java
new file mode 100644
index 0000000..eae1df1
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/subscription/payload/entity/ObjectInspectorPayload.java
@@ -0,0 +1,128 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.subscription.payload.entity;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.onap.aai.sparky.subscription.config.SubscriptionConfig;
+import org.onap.aai.sparky.viewandinspect.config.SparkyConstants;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+import com.fasterxml.jackson.core.JsonParseException;
+import com.fasterxml.jackson.databind.JsonMappingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+@JsonInclude(JsonInclude.Include.NON_NULL)
+@JsonPropertyOrder({ "target", "origin", "messageType", "topic", "message" })
+public class ObjectInspectorPayload {
+
+ @JsonProperty("target")
+ private String target;
+ @JsonProperty("origin")
+ private String origin;
+ @JsonProperty("messageType")
+ private String messageType;
+ @JsonProperty("topic")
+ private String topic;
+ @JsonProperty("message")
+ private Message message;
+
+ @JsonProperty("target")
+ public String getTarget() {
+ return target;
+ }
+
+ @JsonProperty("target")
+ public void setTarget(String target) {
+ this.target = target;
+ }
+
+ @JsonProperty("origin")
+ public String getOrigin() {
+ return origin;
+ }
+
+ @JsonProperty("origin")
+ public void setOrigin(String origin) {
+ this.origin = origin;
+ }
+
+ @JsonProperty("messageType")
+ public String getMessageType() {
+ return messageType;
+ }
+
+ @JsonProperty("messageType")
+ public void setMessageType(String messageType) {
+ this.messageType = messageType;
+ }
+
+ @JsonProperty("topic")
+ public String getTopic() {
+ return topic;
+ }
+
+ @JsonProperty("topic")
+ public void setTopic(String topic) {
+ this.topic = topic;
+ }
+
+ @JsonProperty("message")
+ public Message getMessage() {
+ return message;
+ }
+
+ @JsonProperty("message")
+ public void setMessage(Message message) {
+ this.message = message;
+ }
+
+ private static ObjectInspectorPayload lic;
+ public static ObjectInspectorPayload getOIPayload(SubscriptionConfig subscriptionConf) throws JsonParseException, JsonMappingException, IOException{
+ if(lic == null){
+ ObjectMapper mapper = new ObjectMapper();
+ lic = mapper.readValue(new File(SparkyConstants.SUBSCRIPTION_OI_MAPPING), ObjectInspectorPayload.class);
+ lic.intitializeOIPayload(subscriptionConf);
+ }
+
+ return lic;
+ }
+
+ private void intitializeOIPayload(SubscriptionConfig subscriptionConf) {
+ try {
+ lic.setOrigin(subscriptionConf.getLaunchOIOrigin());
+ lic.setTarget(subscriptionConf.getLaunchOITarget());
+ lic.setTopic(subscriptionConf.getLaunchOITopic());
+ lic.setMessageType(subscriptionConf.getLaunchOIMessageType());
+ } catch (Exception e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+
+ }
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/subscription/payload/entity/Params.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/subscription/payload/entity/Params.java
new file mode 100644
index 0000000..e3bb4c7
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/subscription/payload/entity/Params.java
@@ -0,0 +1,60 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.subscription.payload.entity;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+
+@JsonInclude(JsonInclude.Include.NON_NULL)
+@JsonPropertyOrder({ "contexts", "objectName", "externalClassId"})
+public class Params {
+
+ @JsonProperty("objectName")
+ private String objectName;
+ @JsonProperty("externalClassId")
+ private String externalClassId;
+
+ @JsonProperty("objectName")
+ public String getObjectName() {
+ return objectName;
+ }
+
+ @JsonProperty("objectName")
+ public void setObjectName(String objectName) {
+ this.objectName = objectName;
+ }
+
+ @JsonProperty("externalClassId")
+ public String getExternalClassId() {
+ return externalClassId;
+ }
+
+ @JsonProperty("externalClassId")
+ public void setExternalClassId(String externalClassId) {
+ this.externalClassId = externalClassId;
+ }
+
+} \ No newline at end of file
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/subscription/payload/entity/Payload.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/subscription/payload/entity/Payload.java
new file mode 100644
index 0000000..71db011
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/subscription/payload/entity/Payload.java
@@ -0,0 +1,60 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.subscription.payload.entity;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+
+@JsonInclude(JsonInclude.Include.NON_NULL)
+@JsonPropertyOrder({ "action", "params" })
+public class Payload {
+
+ @JsonProperty("action")
+ private String action;
+ @JsonProperty("params")
+ private Params params;
+
+ @JsonProperty("action")
+ public String getAction() {
+ return action;
+ }
+
+ @JsonProperty("action")
+ public void setAction(String action) {
+ this.action = action;
+ }
+
+ @JsonProperty("params")
+ public Params getParams() {
+ return params;
+ }
+
+ @JsonProperty("params")
+ public void setParams(Params params) {
+ this.params = params;
+ }
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/subscription/services/SubscriptionService.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/subscription/services/SubscriptionService.java
new file mode 100644
index 0000000..78f1d3f
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/subscription/services/SubscriptionService.java
@@ -0,0 +1,65 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.subscription.services;
+
+import org.json.JSONObject;
+import org.onap.aai.restclient.client.OperationResult;
+import org.onap.aai.sparky.subscription.config.SubscriptionConfig;
+
+
+public class SubscriptionService {
+
+ SubscriptionConfig config;
+
+ public SubscriptionService(SubscriptionConfig subscriptionConfig) {
+ this.config = subscriptionConfig;
+ }
+
+ public OperationResult buildSubscriptionPayload() throws Exception {
+ OperationResult returnValue = new OperationResult();
+ returnValue.setResultCode(200);
+ JSONObject subscriptionResponse = new JSONObject();
+ JSONObject subscriptionDetails = new JSONObject();
+
+
+ if (config.getSubscriptionTarget().isEmpty()
+ && config.getSubscriptionTopic().isEmpty()
+ && config.getSubscriptionMessageType().isEmpty()
+ && config.getSubscriptionOrigin().isEmpty()) {
+ subscriptionResponse.put("subscriptionEnabled", false);
+ } else {
+ subscriptionResponse.put("subscriptionEnabled", true);
+ subscriptionDetails.put("target", config.getSubscriptionTarget());
+ subscriptionDetails.put("topic", config.getSubscriptionTopic());
+ subscriptionDetails.put("messageType", config.getSubscriptionMessageType());
+ subscriptionDetails.put("origin", config.getSubscriptionOrigin());
+ }
+
+ subscriptionResponse.put("subscriptionDetails", subscriptionDetails);
+ returnValue.setResult(subscriptionResponse.toString());
+
+ return returnValue;
+ }
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/AbstractEntitySynchronizer.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/AbstractEntitySynchronizer.java
new file mode 100644
index 0000000..a2b750b
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/AbstractEntitySynchronizer.java
@@ -0,0 +1,524 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.sync;
+
+import java.util.EnumSet;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.onap.aai.cl.api.Logger;
+import org.onap.aai.cl.mdc.MdcContext;
+import org.onap.aai.restclient.client.OperationResult;
+import org.onap.aai.sparky.dal.ActiveInventoryAdapter;
+import org.onap.aai.sparky.dal.ElasticSearchAdapter;
+import org.onap.aai.sparky.dal.NetworkTransaction;
+import org.onap.aai.sparky.dal.aai.ActiveInventoryEntityStatistics;
+import org.onap.aai.sparky.dal.aai.ActiveInventoryProcessingExceptionStatistics;
+import org.onap.aai.sparky.dal.elasticsearch.ElasticSearchEntityStatistics;
+import org.onap.aai.sparky.dal.rest.HttpMethod;
+import org.onap.aai.sparky.dal.rest.RestOperationalStatistics;
+import org.onap.aai.sparky.logging.AaiUiMsgs;
+import org.onap.aai.sparky.sync.config.NetworkStatisticsConfig;
+import org.onap.aai.sparky.util.NodeUtils;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+/**
+ * The Class AbstractEntitySynchronizer.
+ *
+ * @author davea.
+ */
+public abstract class AbstractEntitySynchronizer {
+
+ protected static final int VERSION_CONFLICT_EXCEPTION_CODE = 409;
+ protected static final Integer RETRY_COUNT_PER_ENTITY_LIMIT = new Integer(3);
+
+ protected final Logger logger;
+ protected ObjectMapper mapper;
+ protected long syncDurationInMs;
+
+ /**
+ * The Enum StatFlag.
+ */
+ protected enum StatFlag {
+ AAI_REST_STATS, AAI_ENTITY_STATS, AAI_PROCESSING_EXCEPTION_STATS,
+ AAI_TASK_PROCESSING_STATS, ES_REST_STATS, ES_ENTITY_STATS, ES_TASK_PROCESSING_STATS
+ }
+
+ protected EnumSet<StatFlag> enabledStatFlags;
+
+ protected ElasticSearchAdapter elasticSearchAdapter;
+ protected ActiveInventoryAdapter aaiAdapter;
+
+ protected ExecutorService synchronizerExecutor;
+ protected ExecutorService aaiExecutor;
+ protected ExecutorService esExecutor;
+
+ private RestOperationalStatistics esRestStats;
+ protected ElasticSearchEntityStatistics esEntityStats;
+
+ private RestOperationalStatistics aaiRestStats;
+ protected ActiveInventoryEntityStatistics aaiEntityStats;
+ private ActiveInventoryProcessingExceptionStatistics aaiProcessingExceptionStats;
+
+ private TaskProcessingStats aaiTaskProcessingStats;
+ private TaskProcessingStats esTaskProcessingStats;
+
+ private TransactionRateMonitor aaiTransactionRateController;
+ private TransactionRateMonitor esTransactionRateController;
+
+ protected AtomicInteger aaiWorkOnHand;
+ protected AtomicInteger esWorkOnHand;
+ protected String synchronizerName;
+
+ protected abstract boolean isSyncDone();
+ protected boolean shouldSkipSync;
+
+ public String getActiveInventoryStatisticsReport() {
+
+ StringBuilder sb = new StringBuilder(128);
+
+ if (enabledStatFlags.contains(StatFlag.AAI_REST_STATS)) {
+ sb.append("\n\n ").append("REST Operational Stats:");
+ sb.append(aaiRestStats.getStatisticsReport());
+ }
+
+ if (enabledStatFlags.contains(StatFlag.AAI_ENTITY_STATS)) {
+ sb.append("\n\n ").append("Entity Stats:");
+ sb.append(aaiEntityStats.getStatisticsReport());
+ }
+
+ if (enabledStatFlags.contains(StatFlag.AAI_PROCESSING_EXCEPTION_STATS)) {
+ sb.append("\n\n ").append("Processing Exception Stats:");
+ sb.append(aaiProcessingExceptionStats.getStatisticsReport());
+ }
+
+ return sb.toString();
+
+ }
+
+ public String getElasticSearchStatisticsReport() {
+
+ StringBuilder sb = new StringBuilder(128);
+
+ if (enabledStatFlags.contains(StatFlag.ES_REST_STATS)) {
+ sb.append("\n\n ").append("REST Operational Stats:");
+ sb.append(esRestStats.getStatisticsReport());
+ }
+
+ if (enabledStatFlags.contains(StatFlag.ES_ENTITY_STATS)) {
+ sb.append("\n\n ").append("Entity Stats:");
+ sb.append(esEntityStats.getStatisticsReport());
+ }
+
+ return sb.toString();
+
+ }
+
+ /**
+ * Adds the active inventory stat report.
+ *
+ * @param sb the sb
+ */
+ private void addActiveInventoryStatReport(StringBuilder sb) {
+
+ if (sb == null) {
+ return;
+ }
+
+ sb.append("\n\n AAI");
+ sb.append(getActiveInventoryStatisticsReport());
+
+ double currentTps = 0;
+ if (enabledStatFlags.contains(StatFlag.AAI_TASK_PROCESSING_STATS)) {
+ sb.append("\n\n ").append("Task Processor Stats:");
+ sb.append(aaiTaskProcessingStats.getStatisticsReport(false, " "));
+
+ currentTps = aaiTransactionRateController.getCurrentTps();
+
+ sb.append("\n ").append("Current TPS: ").append(currentTps);
+ }
+
+ sb.append("\n ").append("Current WOH: ").append(aaiWorkOnHand.get());
+
+ if (enabledStatFlags.contains(StatFlag.AAI_TASK_PROCESSING_STATS)) {
+ if (currentTps > 0) {
+ double numMillisecondsToCompletion = (aaiWorkOnHand.get() / currentTps) * 1000;
+ sb.append("\n ").append("SyncDurationRemaining=")
+ .append(NodeUtils.getDurationBreakdown((long) numMillisecondsToCompletion));
+ }
+ }
+
+ }
+
+ /**
+ * Adds the elastic stat report.
+ *
+ * @param sb the sb
+ */
+ private void addElasticStatReport(StringBuilder sb) {
+
+ if (sb == null) {
+ return;
+ }
+
+ sb.append("\n\n ELASTIC");
+ sb.append(getElasticSearchStatisticsReport());
+
+ double currentTps = 0;
+
+ if (enabledStatFlags.contains(StatFlag.ES_TASK_PROCESSING_STATS)) {
+ sb.append("\n\n ").append("Task Processor Stats:");
+ sb.append(esTaskProcessingStats.getStatisticsReport(false, " "));
+
+ currentTps = esTransactionRateController.getCurrentTps();
+
+ sb.append("\n ").append("Current TPS: ").append(currentTps);
+ }
+
+ sb.append("\n ").append("Current WOH: ").append(esWorkOnHand.get());
+
+ if (enabledStatFlags.contains(StatFlag.ES_TASK_PROCESSING_STATS)) {
+ if (currentTps > 0) {
+ double numMillisecondsToCompletion = (esWorkOnHand.get() / currentTps) * 1000;
+ sb.append("\n ").append("SyncDurationRemaining=")
+ .append(NodeUtils.getDurationBreakdown((long) numMillisecondsToCompletion));
+ }
+ }
+
+
+ }
+
+ /**
+ * Gets the stat report.
+ *
+ * @param syncOpTimeInMs the sync op time in ms
+ * @param showFinalReport the show final report
+ * @return the stat report
+ */
+ protected String getStatReport(long syncOpTimeInMs, boolean showFinalReport) {
+
+ StringBuilder sb = new StringBuilder(128);
+
+ sb.append("\n").append(synchronizerName + " Statistics: ( Sync Operation Duration = "
+ + NodeUtils.getDurationBreakdown(syncOpTimeInMs) + " )");
+
+ addActiveInventoryStatReport(sb);
+ addElasticStatReport(sb);
+
+ if (showFinalReport) {
+ sb.append("\n\n ").append("Sync Completed!\n");
+ } else {
+ sb.append("\n\n ").append("Sync in Progress...\n");
+ }
+
+ return sb.toString();
+
+ }
+
+ protected String indexName;
+ protected long syncStartedTimeStampInMs;
+
+ /**
+ * Instantiates a new abstract entity synchronizer.
+ *
+ * @param logger the logger
+ * @param syncName the sync name
+ * @param numSyncWorkers the num sync workers
+ * @param numActiveInventoryWorkers the num active inventory workers
+ * @param numElasticsearchWorkers the num elasticsearch workers
+ * @param indexName the index name
+ * @throws Exception the exception
+ */
+ protected AbstractEntitySynchronizer(Logger logger, String syncName, int numSyncWorkers,
+ int numActiveInventoryWorkers, int numElasticsearchWorkers, String indexName,
+ NetworkStatisticsConfig aaiStatConfig, NetworkStatisticsConfig esStatConfig)
+ throws Exception {
+ this.logger = logger;
+ this.synchronizerExecutor =
+ NodeUtils.createNamedExecutor(syncName + "-INTERNAL", numSyncWorkers, logger);
+ this.aaiExecutor =
+ NodeUtils.createNamedExecutor(syncName + "-AAI", numActiveInventoryWorkers, logger);
+ this.esExecutor =
+ NodeUtils.createNamedExecutor(syncName + "-ES", numElasticsearchWorkers, logger);
+ this.mapper = new ObjectMapper();
+ this.indexName = indexName;
+ this.esRestStats = new RestOperationalStatistics();
+ this.esEntityStats = new ElasticSearchEntityStatistics();
+ this.aaiRestStats = new RestOperationalStatistics();
+ this.aaiEntityStats = new ActiveInventoryEntityStatistics();
+ this.aaiProcessingExceptionStats = new ActiveInventoryProcessingExceptionStatistics();
+ this.aaiTaskProcessingStats =
+ new TaskProcessingStats(aaiStatConfig);
+ this.esTaskProcessingStats =
+ new TaskProcessingStats(esStatConfig);
+
+ this.aaiTransactionRateController =
+ new TransactionRateMonitor(numActiveInventoryWorkers, aaiStatConfig);
+ this.esTransactionRateController =
+ new TransactionRateMonitor(numElasticsearchWorkers, esStatConfig);
+
+ this.aaiWorkOnHand = new AtomicInteger(0);
+ this.esWorkOnHand = new AtomicInteger(0);
+
+ enabledStatFlags = EnumSet.allOf(StatFlag.class);
+
+ this.synchronizerName = "Abstact Entity Synchronizer";
+
+ String txnID = NodeUtils.getRandomTxnId();
+ MdcContext.initialize(txnID, "AbstractEntitySynchronizer", "", "Sync", "");
+
+ this.shouldSkipSync = false;
+ this.syncStartedTimeStampInMs = System.currentTimeMillis();
+ this.syncDurationInMs = -1;
+ }
+
+ public boolean shouldSkipSync() {
+ return shouldSkipSync;
+ }
+
+ public void setShouldSkipSync(boolean shouldSkipSync) {
+ this.shouldSkipSync = shouldSkipSync;
+ }
+
+ /**
+ * Inc active inventory work on hand counter.
+ */
+ protected void incActiveInventoryWorkOnHandCounter() {
+ aaiWorkOnHand.incrementAndGet();
+ }
+
+ /**
+ * Dec active inventory work on hand counter.
+ */
+ protected void decActiveInventoryWorkOnHandCounter() {
+ aaiWorkOnHand.decrementAndGet();
+ }
+
+ /**
+ * Inc elastic search work on hand counter.
+ */
+ protected void incElasticSearchWorkOnHandCounter() {
+ esWorkOnHand.incrementAndGet();
+ }
+
+ /**
+ * Dec elastic search work on hand counter.
+ */
+ protected void decElasticSearchWorkOnHandCounter() {
+ esWorkOnHand.decrementAndGet();
+ }
+
+ /**
+ * Shutdown executors.
+ */
+ protected void shutdownExecutors() {
+ try {
+
+ if (synchronizerExecutor != null) {
+ synchronizerExecutor.shutdown();
+ }
+
+ if (aaiExecutor != null) {
+ aaiExecutor.shutdown();
+ }
+
+ if (esExecutor != null) {
+ esExecutor.shutdown();
+ }
+
+ } catch (Exception exc) {
+ logger.error(AaiUiMsgs.ERROR_SHUTDOWN_EXECUTORS, exc );
+ }
+ }
+
+ /**
+ * Clear cache.
+ */
+ public void clearCache() {}
+
+ public ElasticSearchAdapter getElasticSearchAdapter() {
+ return elasticSearchAdapter;
+ }
+
+ public void setElasticSearchAdapter(ElasticSearchAdapter elasticSearchAdapter) {
+ this.elasticSearchAdapter = elasticSearchAdapter;
+ }
+
+ public ActiveInventoryAdapter getAaiAdapter() {
+ return aaiAdapter;
+ }
+
+ public void setAaiAdapter(ActiveInventoryAdapter aaiAdapter) {
+ this.aaiAdapter = aaiAdapter;
+ }
+
+ public String getIndexName() {
+ return indexName;
+ }
+
+ public void setIndexName(String indexName) {
+ this.indexName = indexName;
+ }
+
+
+ /**
+ * Gets the response length.
+ *
+ * @param txn the txn
+ * @return the response length
+ */
+ private long getResponseLength(NetworkTransaction txn) {
+
+ if (txn == null) {
+ return -1;
+ }
+
+ OperationResult result = txn.getOperationResult();
+
+ if (result == null) {
+ return -1;
+ }
+
+ if (result.getResult() != null) {
+ return result.getResult().length();
+ }
+
+ return -1;
+ }
+
+ /**
+ * Update elastic search counters.
+ *
+ * @param method the method
+ * @param entityType the entity type
+ * @param or the or
+ */
+ protected void updateElasticSearchCounters(HttpMethod method, String entityType,
+ OperationResult or) {
+ updateElasticSearchCounters(new NetworkTransaction(method, entityType, or));
+ }
+
+ /**
+ * Update elastic search counters.
+ *
+ * @param txn the txn
+ */
+ protected void updateElasticSearchCounters(NetworkTransaction txn) {
+
+ if (enabledStatFlags.contains(StatFlag.ES_REST_STATS)) {
+ esRestStats.updateCounters(txn);
+ }
+
+ if (enabledStatFlags.contains(StatFlag.ES_ENTITY_STATS)) {
+ esEntityStats.updateCounters(txn);
+ }
+
+ if (enabledStatFlags.contains(StatFlag.ES_TASK_PROCESSING_STATS)) {
+
+ esTransactionRateController.trackResponseTime(txn.getOpTimeInMs());
+
+ esTaskProcessingStats
+ .updateTaskResponseStatsHistogram(txn.getOpTimeInMs());
+ esTaskProcessingStats.updateTaskAgeStatsHistogram(txn.getTaskAgeInMs());
+
+ // don't know the cost of the lengh calc, we'll see if it causes a
+ // problem
+
+ long responsePayloadSizeInBytes = getResponseLength(txn);
+ if (responsePayloadSizeInBytes >= 0) {
+ esTaskProcessingStats.updateResponseSizeInBytesHistogram(responsePayloadSizeInBytes);
+ }
+
+ esTaskProcessingStats
+ .updateTransactionsPerSecondHistogram((long) esTransactionRateController.getCurrentTps());
+ }
+ }
+
+ /**
+ * Update active inventory counters.
+ *
+ * @param method the method
+ * @param entityType the entity type
+ * @param or the or
+ */
+ protected void updateActiveInventoryCounters(HttpMethod method, String entityType,
+ OperationResult or) {
+ updateActiveInventoryCounters(new NetworkTransaction(method, entityType, or));
+ }
+
+ /**
+ * Update active inventory counters.
+ *
+ * @param txn the txn
+ */
+ protected void updateActiveInventoryCounters(NetworkTransaction txn) {
+
+ if (enabledStatFlags.contains(StatFlag.AAI_REST_STATS)) {
+ aaiRestStats.updateCounters(txn);
+ }
+
+ if (enabledStatFlags.contains(StatFlag.AAI_ENTITY_STATS)) {
+ aaiEntityStats.updateCounters(txn);
+ }
+
+ if (enabledStatFlags.contains(StatFlag.AAI_PROCESSING_EXCEPTION_STATS)) {
+ aaiProcessingExceptionStats.updateCounters(txn);
+ }
+
+ if (enabledStatFlags.contains(StatFlag.AAI_TASK_PROCESSING_STATS)) {
+ aaiTransactionRateController
+ .trackResponseTime(txn.getOpTimeInMs());
+
+ aaiTaskProcessingStats
+ .updateTaskResponseStatsHistogram(txn.getOpTimeInMs());
+ aaiTaskProcessingStats.updateTaskAgeStatsHistogram(txn.getTaskAgeInMs());
+
+ // don't know the cost of the lengh calc, we'll see if it causes a
+ // problem
+
+ long responsePayloadSizeInBytes = getResponseLength(txn);
+ if (responsePayloadSizeInBytes >= 0) {
+ aaiTaskProcessingStats.updateResponseSizeInBytesHistogram(responsePayloadSizeInBytes);
+ }
+
+ aaiTaskProcessingStats.updateTransactionsPerSecondHistogram(
+ (long) aaiTransactionRateController.getCurrentTps());
+ }
+ }
+
+ /**
+ * Reset counters.
+ */
+ protected void resetCounters() {
+ aaiRestStats.reset();
+ aaiEntityStats.reset();
+ aaiProcessingExceptionStats.reset();
+
+ esRestStats.reset();
+ esEntityStats.reset();
+ }
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/ElasticSearchIndexCleaner.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/ElasticSearchIndexCleaner.java
new file mode 100644
index 0000000..3255e39
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/ElasticSearchIndexCleaner.java
@@ -0,0 +1,604 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.sync;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.ws.rs.core.MediaType;
+
+import org.onap.aai.cl.api.Logger;
+import org.onap.aai.cl.eelf.LoggerFactory;
+import org.onap.aai.restclient.client.OperationResult;
+import org.onap.aai.sparky.dal.ElasticSearchAdapter;
+import org.onap.aai.sparky.logging.AaiUiMsgs;
+import org.onap.aai.sparky.sync.config.ElasticSearchEndpointConfig;
+import org.onap.aai.sparky.sync.config.ElasticSearchSchemaConfig;
+import org.onap.aai.sparky.sync.entity.ObjectIdCollection;
+import org.onap.aai.sparky.sync.entity.SearchableEntity;
+import org.onap.aai.sparky.sync.enumeration.OperationState;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+/**
+ * The Class ElasticSearchIndexCleaner.
+ */
+public class ElasticSearchIndexCleaner implements IndexCleaner {
+
+ private static final Logger LOG =
+ LoggerFactory.getInstance().getLogger(ElasticSearchIndexCleaner.class);
+
+ private static final String BULK_OP_LINE_TEMPLATE = "%s\n";
+ private static final String TIMESTAMP_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSSZ";
+
+ private ObjectIdCollection before;
+ private ObjectIdCollection after;
+
+ private ObjectMapper mapper;
+ private ElasticSearchAdapter esAdapter;
+ private ElasticSearchEndpointConfig endpointConfig;
+ private ElasticSearchSchemaConfig schemaConfig;
+
+ /**
+ * Instantiates a new elastic search index cleaner.
+ *
+ * @param restDataProvider the rest data provider
+ * @param indexName the index name
+ * @param indexType the index type
+ * @param host the host
+ * @param port the port
+ * @param scrollContextTimeToLiveInMinutes the scroll context time to live in minutes
+ * @param numItemsToGetBulkRequest the num items to get bulk request
+ */
+ public ElasticSearchIndexCleaner(ElasticSearchAdapter esAdapter, ElasticSearchEndpointConfig endpointConfig, ElasticSearchSchemaConfig schemaConfig) {
+ this.esAdapter = esAdapter;
+ this.before = null;
+ this.after = null;
+ this.endpointConfig = endpointConfig;
+ this.schemaConfig = schemaConfig;
+ this.mapper = new ObjectMapper();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.openecomp.sparky.synchronizer.IndexCleaner#populatePreOperationCollection()
+ */
+ @Override
+ public OperationState populatePreOperationCollection() {
+
+ try {
+ before = retrieveAllDocumentIdentifiers();
+ return OperationState.OK;
+ } catch (Exception exc) {
+ LOG.error(AaiUiMsgs.ES_PRE_SYNC_FAILURE, schemaConfig.getIndexName(), exc.getMessage());
+ return OperationState.ERROR;
+ }
+
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.openecomp.sparky.synchronizer.IndexCleaner#populatePostOperationCollection()
+ */
+ @Override
+ public OperationState populatePostOperationCollection() {
+ try {
+ after = retrieveAllDocumentIdentifiers();
+ return OperationState.OK;
+ } catch (Exception exc) {
+ LOG.error(AaiUiMsgs.ES_PRE_SYNC_FAILURE, schemaConfig.getIndexName(), exc.getMessage());
+ return OperationState.ERROR;
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.openecomp.sparky.synchronizer.IndexCleaner#performCleanup()
+ */
+ @Override
+ public OperationState performCleanup() {
+ // TODO Auto-generated method stub
+ LOG.info(AaiUiMsgs.ES_SYNC_CLEAN_UP, schemaConfig.getIndexName());
+
+ int sizeBefore = before.getSize();
+ int sizeAfter = after.getSize();
+
+ LOG.info(AaiUiMsgs.ES_SYNC_CLEAN_UP_SIZE, String.valueOf(sizeBefore),
+ String.valueOf(sizeAfter));
+
+ /*
+ * If the processedImportIds size <= 0, then something has failed in the sync operation and we
+ * shouldn't do the selective delete right now.
+ */
+
+ if (sizeAfter > 0) {
+
+ Collection<String> presyncIds = before.getImportedObjectIds();
+ presyncIds.removeAll(after.getImportedObjectIds());
+
+ try {
+ LOG.info(AaiUiMsgs.ES_SYNC_SELECTIVE_DELETE, schemaConfig.getIndexName(), schemaConfig.getIndexDocType(),
+ String.valueOf(presyncIds.size()));
+
+ ObjectIdCollection bulkIds = new ObjectIdCollection();
+
+ Iterator<String> it = presyncIds.iterator();
+ int numItemsInBulkRequest = 0;
+ int numItemsRemainingToBeDeleted = presyncIds.size();
+
+ while (it.hasNext()) {
+
+ bulkIds.addObjectId(it.next());
+ numItemsInBulkRequest++;
+
+ if (numItemsInBulkRequest >= endpointConfig.getScrollContextBatchRequestSize()) {
+ LOG.info(AaiUiMsgs.ES_BULK_DELETE, schemaConfig.getIndexName(), String.valueOf(bulkIds.getSize()));
+ bulkDelete(bulkIds.getImportedObjectIds());
+ numItemsRemainingToBeDeleted -= numItemsInBulkRequest;
+ numItemsInBulkRequest = 0;
+ bulkIds.clear();
+ }
+ }
+
+ if (numItemsRemainingToBeDeleted > 0) {
+ LOG.info(AaiUiMsgs.ES_BULK_DELETE, schemaConfig.getIndexName(), String.valueOf(bulkIds.getSize()));
+ bulkDelete(bulkIds.getImportedObjectIds());
+ }
+
+
+ } catch (Exception exc) {
+ LOG.error(AaiUiMsgs.ES_BULK_DELETE_ERROR, schemaConfig.getIndexName(), exc.getLocalizedMessage());
+
+ }
+ }
+
+ return OperationState.OK;
+ }
+
+ @Override
+ public String getIndexName() {
+ return schemaConfig.getIndexName();
+ }
+
+ /**
+ * Builds the initial scroll request payload.
+ *
+ * @param numItemsToGetPerRequest the num items to get per request
+ * @param fieldList the field list
+ * @return the string
+ * @throws JsonProcessingException the json processing exception
+ */
+ protected String buildInitialScrollRequestPayload(int numItemsToGetPerRequest,
+ List<String> fieldList) throws JsonProcessingException {
+
+ ObjectNode rootNode = mapper.createObjectNode();
+ rootNode.put("size", numItemsToGetPerRequest);
+
+ ArrayNode fields = mapper.createArrayNode();
+
+ for (String f : fieldList) {
+ fields.add(f);
+ }
+
+ rootNode.set("fields", fields);
+
+ ObjectNode queryNode = mapper.createObjectNode();
+ queryNode.set("match_all", mapper.createObjectNode());
+
+ rootNode.set("query", queryNode);
+
+ return mapper.writeValueAsString(rootNode);
+
+ }
+
+ /**
+ * Builds the subsequent scroll context request payload.
+ *
+ * @param scrollId the scroll id
+ * @param contextTimeToLiveInMinutes the context time to live in minutes
+ * @return the string
+ * @throws JsonProcessingException the json processing exception
+ */
+ protected String buildSubsequentScrollContextRequestPayload(String scrollId,
+ int contextTimeToLiveInMinutes) throws JsonProcessingException {
+
+ ObjectNode rootNode = mapper.createObjectNode();
+
+ rootNode.put("scroll", contextTimeToLiveInMinutes + "m");
+ rootNode.put("scroll_id", scrollId);
+
+ return mapper.writeValueAsString(rootNode);
+
+ }
+
+ /**
+ * Parses the elastic search result.
+ *
+ * @param jsonResult the json result
+ * @return the json node
+ * @throws JsonProcessingException the json processing exception
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ protected JsonNode parseElasticSearchResult(String jsonResult)
+ throws JsonProcessingException, IOException {
+ ObjectMapper mapper = new ObjectMapper();
+ return mapper.readTree(jsonResult);
+ }
+
+ /**
+ * Lookup index doc.
+ *
+ * @param ids the ids
+ * @param docs the docs
+ * @return the array list
+ */
+ protected ArrayList<SearchableEntity> lookupIndexDoc(ArrayList<String> ids,
+ List<SearchableEntity> docs) {
+ ArrayList<SearchableEntity> objs = new ArrayList<SearchableEntity>();
+
+ if (ids != null && docs != null) {
+ for (SearchableEntity d : docs) {
+ if (ids.contains(d.getId())) {
+ objs.add(d);
+ }
+ }
+ }
+
+ return objs;
+ }
+
+ /**
+ * Builds the delete data object.
+ *
+ * @param index the index
+ * @param type the type
+ * @param id the id
+ * @return the object node
+ */
+ protected ObjectNode buildDeleteDataObject(String index, String type, String id) {
+
+ ObjectNode indexDocProperties = mapper.createObjectNode();
+
+ indexDocProperties.put("_index", index);
+ indexDocProperties.put("_type", type);
+ indexDocProperties.put("_id", id);
+
+ ObjectNode rootNode = mapper.createObjectNode();
+ rootNode.set("delete", indexDocProperties);
+
+ return rootNode;
+ }
+
+ /**
+ * This method might appear to be a little strange, and is simply an optimization to take an
+ * elipsed JsonNode key path and retrieve the node at the end of the path, if it exists.
+ *
+ * @param startNode the start node
+ * @param fieldPath the field path
+ * @return the node path
+ */
+ protected JsonNode getNodePath(JsonNode startNode, String... fieldPath) {
+
+ JsonNode jsonNode = null;
+
+ for (String field : fieldPath) {
+ if (jsonNode == null) {
+ jsonNode = startNode.get(field);
+ } else {
+ jsonNode = jsonNode.get(field);
+ }
+
+ /*
+ * This is our safety net in case any intermediate path returns a null
+ */
+
+ if (jsonNode == null) {
+ return null;
+ }
+
+ }
+
+ return jsonNode;
+ }
+
+ /**
+ * Gets the full url.
+ *
+ * @param resourceUrl the resource url
+ * @return the full url
+ */
+ private String getFullUrl(String resourceUrl) {
+ return String.format("http://%s:%s%s", endpointConfig.getEsIpAddress(),
+ endpointConfig.getEsServerPort(), resourceUrl);
+ }
+
+ /**
+ * Retrieve all document identifiers.
+ *
+ * @return the object id collection
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public ObjectIdCollection retrieveAllDocumentIdentifiers() throws IOException {
+
+ ObjectIdCollection currentDocumentIds = new ObjectIdCollection();
+
+ long opStartTimeInMs = System.currentTimeMillis();
+
+ List<String> fields = new ArrayList<String>();
+ fields.add("_id");
+ // fields.add("entityType");
+
+ String scrollRequestPayload =
+ buildInitialScrollRequestPayload(endpointConfig.getScrollContextBatchRequestSize(), fields);
+
+ final String fullUrlStr = getFullUrl("/" + schemaConfig.getIndexName()+ "/" + schemaConfig.getIndexDocType() + "/_search?scroll="
+ + endpointConfig.getScrollContextTimeToLiveInMinutes() + "m");
+
+ OperationResult result =
+ esAdapter.doPost(fullUrlStr, scrollRequestPayload, MediaType.APPLICATION_JSON_TYPE);
+
+ if (result.wasSuccessful()) {
+
+ JsonNode rootNode = parseElasticSearchResult(result.getResult());
+
+ /*
+ * Check the result for success / failure, and enumerate all the index ids that resulted in
+ * success, and ignore the ones that failed or log them so we have a record of the failure.
+ */
+ int totalRecordsAvailable = 0;
+ String scrollId = null;
+ int numRecordsFetched = 0;
+
+ if (rootNode != null) {
+
+ scrollId = getFieldValue(rootNode, "_scroll_id");
+ final String tookStr = getFieldValue(rootNode, "took");
+ int tookInMs = (tookStr == null) ? 0 : Integer.parseInt(tookStr);
+ boolean timedOut = Boolean.parseBoolean(getFieldValue(rootNode, "timed_out"));
+
+ if (timedOut) {
+ LOG.error(AaiUiMsgs.COLLECT_TIME_WITH_ERROR, "all document Identifiers",
+ String.valueOf(tookInMs));
+ } else {
+ LOG.info(AaiUiMsgs.COLLECT_TIME_WITH_SUCCESS, "all document Identifiers",
+ String.valueOf(tookInMs));
+ }
+
+ JsonNode hitsNode = rootNode.get("hits");
+ totalRecordsAvailable = Integer.parseInt(hitsNode.get("total").asText());
+
+ LOG.info(AaiUiMsgs.COLLECT_TOTAL, "all document Identifiers",
+ String.valueOf(totalRecordsAvailable));
+
+ /*
+ * Collect all object ids
+ */
+
+ ArrayNode hitsArray = (ArrayNode) hitsNode.get("hits");
+
+ Iterator<JsonNode> nodeIterator = hitsArray.iterator();
+
+ String key = null;
+ String value = null;
+ JsonNode jsonNode = null;
+
+ while (nodeIterator.hasNext()) {
+
+ jsonNode = nodeIterator.next();
+
+ key = getFieldValue(jsonNode, "_id");
+
+ if (key != null) {
+ currentDocumentIds.addObjectId(key);
+ }
+
+ }
+
+ int totalRecordsRemainingToFetch = (totalRecordsAvailable - numRecordsFetched);
+
+ int numRequiredAdditionalFetches =
+ (totalRecordsRemainingToFetch / endpointConfig.getScrollContextBatchRequestSize());
+
+ /*
+ * Do an additional fetch for the remaining items (if needed)
+ */
+
+ if (totalRecordsRemainingToFetch % endpointConfig.getScrollContextBatchRequestSize() != 0) {
+ numRequiredAdditionalFetches += 1;
+ }
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug(AaiUiMsgs.SYNC_NUMBER_REQ_FETCHES,
+ String.valueOf(numRequiredAdditionalFetches));
+ }
+
+
+ for (int x = 0; x < numRequiredAdditionalFetches; x++) {
+
+ if (collectItemsFromScrollContext(scrollId, currentDocumentIds) != OperationState.OK) {
+ // abort the whole thing because now we can't reliably cleanup the orphans.
+ throw new IOException(
+ "Failed to collect pre-sync doc collection from index. Aborting operation");
+ }
+ if (LOG.isDebugEnabled()) {
+ LOG.debug(AaiUiMsgs.SYNC_NUMBER_TOTAL_FETCHES,
+ String.valueOf(currentDocumentIds.getSize()),
+ String.valueOf(totalRecordsAvailable));
+ }
+
+ }
+
+ }
+
+ } else {
+ // scroll context get failed, nothing else to do
+ LOG.error(AaiUiMsgs.ERROR_GENERIC, result.toString());
+ }
+
+ LOG.info(AaiUiMsgs.COLLECT_TOTAL_TIME, "all document Identifiers",
+ String.valueOf((System.currentTimeMillis() - opStartTimeInMs)));
+
+ return currentDocumentIds;
+
+ }
+
+ /**
+ * Collect items from scroll context.
+ *
+ * @param scrollId the scroll id
+ * @param objectIds the object ids
+ * @return the operation state
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ private OperationState collectItemsFromScrollContext(String scrollId,
+ ObjectIdCollection objectIds) throws IOException {
+
+ String requestPayload = buildSubsequentScrollContextRequestPayload(scrollId,
+ endpointConfig.getScrollContextTimeToLiveInMinutes());
+
+ final String fullUrlStr = getFullUrl("/_search/scroll");
+
+ OperationResult opResult =
+ esAdapter.doPost(fullUrlStr, requestPayload, MediaType.APPLICATION_JSON_TYPE);
+
+ if (opResult.getResultCode() >= 300) {
+ LOG.warn(AaiUiMsgs.ES_SCROLL_CONTEXT_ERROR, opResult.getResult());
+ return OperationState.ERROR;
+ }
+
+ JsonNode rootNode = parseElasticSearchResult(opResult.getResult());
+ boolean timedOut = Boolean.parseBoolean(getFieldValue(rootNode, "timed_out"));
+ final String tookStr = getFieldValue(rootNode, "took");
+ int tookInMs = (tookStr == null) ? 0 : Integer.parseInt(tookStr);
+
+ JsonNode hitsNode = rootNode.get("hits");
+
+ /*
+ * Check the result for success / failure, and enumerate all the index ids that resulted in
+ * success, and ignore the ones that failed or log them so we have a record of the failure.
+ */
+
+ if (rootNode != null) {
+
+ if (timedOut) {
+ LOG.info(AaiUiMsgs.COLLECT_TIME_WITH_ERROR, "Scroll Context", String.valueOf(tookInMs));
+ } else {
+ LOG.info(AaiUiMsgs.COLLECT_TIME_WITH_SUCCESS, "Scroll Context", String.valueOf(tookInMs));
+ }
+
+ /*
+ * Collect all object ids
+ */
+
+ ArrayNode hitsArray = (ArrayNode) hitsNode.get("hits");
+ String key = null;
+ String value = null;
+ JsonNode jsonNode = null;
+
+ Iterator<JsonNode> nodeIterator = hitsArray.iterator();
+
+ while (nodeIterator.hasNext()) {
+
+ jsonNode = nodeIterator.next();
+
+ key = getFieldValue(jsonNode, "_id");
+
+ if (key != null) {
+ objectIds.addObjectId(key);
+
+ }
+
+ }
+ }
+
+ return OperationState.OK;
+ }
+
+ /**
+ * Gets the field value.
+ *
+ * @param node the node
+ * @param fieldName the field name
+ * @return the field value
+ */
+ protected String getFieldValue(JsonNode node, String fieldName) {
+
+ JsonNode field = node.get(fieldName);
+
+ if (field != null) {
+ return field.asText();
+ }
+
+ return null;
+
+ }
+
+ /**
+ * Bulk delete.
+ *
+ * @param docIds the doc ids
+ * @return the operation result
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public OperationResult bulkDelete(Collection<String> docIds) throws IOException {
+
+ if (docIds == null || docIds.size() == 0) {
+ LOG.info(AaiUiMsgs.ES_BULK_DELETE_SKIP);
+ return new OperationResult(500,
+ "Skipping bulkDelete(); operation because docs to delete list is empty");
+ }
+
+ LOG.info(AaiUiMsgs.ES_BULK_DELETE_START, String.valueOf(docIds.size()));
+
+ StringBuilder sb = new StringBuilder(128);
+
+ for (String id : docIds) {
+ sb.append(String.format(BULK_OP_LINE_TEMPLATE,
+ buildDeleteDataObject(schemaConfig.getIndexName(), schemaConfig.getIndexDocType(), id)));
+ }
+
+ sb.append("\n");
+
+ final String fullUrlStr = getFullUrl("/_bulk");
+
+ return esAdapter.doPost(fullUrlStr, sb.toString(), MediaType.APPLICATION_FORM_URLENCODED_TYPE);
+
+ }
+
+ /*
+
+ */
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/ElasticSearchSchemaFactory.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/ElasticSearchSchemaFactory.java
new file mode 100644
index 0000000..a2ff6cf
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/ElasticSearchSchemaFactory.java
@@ -0,0 +1,97 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.sync;
+
+import java.io.IOException;
+
+import org.onap.aai.sparky.config.SparkyResourceLoader;
+import org.onap.aai.sparky.dal.exception.ElasticSearchOperationException;
+import org.onap.aai.sparky.sync.config.ElasticSearchSchemaConfig;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+public class ElasticSearchSchemaFactory {
+
+ private static final String SETTINGS = "settings";
+ private static final String MAPPINGS = "mappings";
+
+ private static ObjectMapper mapper = new ObjectMapper();
+ private SparkyResourceLoader resourceLoader;
+
+ public String getIndexSchema(ElasticSearchSchemaConfig schemaConfig)
+ throws ElasticSearchOperationException {
+
+ JsonNode esSettingsNode = null;
+ JsonNode esMappingsNodes = null;
+
+ try {
+
+ if (schemaConfig.getIndexSettingsFileName() != null) {
+ esSettingsNode = mapper
+ .readTree(resourceLoader.getResourceAsString(schemaConfig.getIndexSettingsFileName(),true));
+ }
+
+ if (schemaConfig.getIndexMappingsFileName() != null) {
+ esMappingsNodes = mapper
+ .readTree(resourceLoader.getResourceAsString(schemaConfig.getIndexMappingsFileName(),true));
+ }
+
+ } catch (IOException e1) {
+
+ throw new ElasticSearchOperationException("Caught an exception building initial ES index. Error: " + e1.getMessage());
+ }
+
+ ObjectNode esConfig = null;
+
+ ObjectNode mappings =
+ (ObjectNode) mapper.createObjectNode().set(schemaConfig.getIndexDocType(), esMappingsNodes);
+
+ if (esSettingsNode == null) {
+ esConfig = (ObjectNode) mapper.createObjectNode().set(MAPPINGS, mappings);
+ } else {
+ esConfig = (ObjectNode) mapper.createObjectNode().set(SETTINGS, esSettingsNode);
+ esConfig.set(MAPPINGS, mappings);
+ }
+
+ try {
+ return mapper.writeValueAsString(esConfig);
+ } catch (JsonProcessingException exc) {
+ throw new ElasticSearchOperationException("Error getting object node as string", exc);
+ }
+
+ }
+
+ public SparkyResourceLoader getResourceLoader() {
+ return resourceLoader;
+ }
+
+ public void setResourceLoader(SparkyResourceLoader resourceLoader) {
+ this.resourceLoader = resourceLoader;
+ }
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/IndexCleaner.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/IndexCleaner.java
new file mode 100644
index 0000000..bc47fa8
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/IndexCleaner.java
@@ -0,0 +1,57 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.sync;
+
+import org.onap.aai.sparky.sync.enumeration.OperationState;
+
+/**
+ * The Interface IndexCleaner.
+ */
+public interface IndexCleaner {
+
+ /**
+ * Populate pre operation collection.
+ *
+ * @return the operation state
+ */
+ public OperationState populatePreOperationCollection();
+
+ /**
+ * Populate post operation collection.
+ *
+ * @return the operation state
+ */
+ public OperationState populatePostOperationCollection();
+
+ /**
+ * Perform cleanup.
+ *
+ * @return the operation state
+ */
+ public OperationState performCleanup();
+
+ public String getIndexName();
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/IndexIntegrityValidator.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/IndexIntegrityValidator.java
new file mode 100644
index 0000000..2c1bb16
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/IndexIntegrityValidator.java
@@ -0,0 +1,178 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.sync;
+
+import javax.ws.rs.core.MediaType;
+
+import org.onap.aai.cl.api.Logger;
+import org.onap.aai.cl.eelf.LoggerFactory;
+import org.onap.aai.restclient.client.OperationResult;
+import org.onap.aai.sparky.dal.ElasticSearchAdapter;
+import org.onap.aai.sparky.logging.AaiUiMsgs;
+import org.onap.aai.sparky.sync.config.ElasticSearchEndpointConfig;
+import org.onap.aai.sparky.sync.config.ElasticSearchSchemaConfig;
+
+/**
+ * The Class IndexIntegrityValidator.
+ */
+public class IndexIntegrityValidator implements IndexValidator {
+
+ private static final Logger LOG =
+ LoggerFactory.getInstance().getLogger(IndexIntegrityValidator.class);
+
+ private ElasticSearchEndpointConfig endpointConfig;
+ private ElasticSearchSchemaConfig schemaConfig;
+ private String tableConfigJson;
+
+ private final ElasticSearchAdapter esAdapter;
+
+ /**
+ * Instantiates a new index integrity validator.
+ *
+ * @param restDataProvider the rest data provider
+ * @param indexName the index name
+ * @param indexType the index type
+ * @param host the host
+ * @param port the port
+ * @param tableConfigJson the table config json
+ */
+ public IndexIntegrityValidator(ElasticSearchAdapter esAdapter,
+ ElasticSearchSchemaConfig esSchemaConfig, ElasticSearchEndpointConfig esEndpointConfig,
+ String tableConfigJson) {
+
+ this.esAdapter = esAdapter;
+ this.schemaConfig = esSchemaConfig;
+ this.endpointConfig = esEndpointConfig;
+ this.tableConfigJson = tableConfigJson;
+ }
+
+ public ElasticSearchEndpointConfig getEndpointConfig() {
+ return endpointConfig;
+ }
+
+ public void setEndpointConfig(ElasticSearchEndpointConfig endpointConfig) {
+ this.endpointConfig = endpointConfig;
+ }
+
+ public ElasticSearchSchemaConfig getSchemaConfig() {
+ return schemaConfig;
+ }
+
+ public void setSchemaConfig(ElasticSearchSchemaConfig schemaConfig) {
+ this.schemaConfig = schemaConfig;
+ }
+
+ public ElasticSearchAdapter getEsAdapter() {
+ return esAdapter;
+ }
+
+ @Override
+ public String getIndexName() {
+ return schemaConfig.getIndexName();
+ }
+
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.openecomp.sparky.synchronizer.IndexValidator#exists()
+ */
+ @Override
+ public boolean exists() {
+ final String fullUrlStr = getFullUrl("/" + schemaConfig.getIndexName() + "/");
+ OperationResult existsResult = esAdapter.doHead(fullUrlStr, MediaType.APPLICATION_JSON_TYPE);
+
+ int rc = existsResult.getResultCode();
+
+ if (rc >= 200 && rc < 300) {
+ LOG.info(AaiUiMsgs.INDEX_EXISTS, schemaConfig.getIndexName());
+ return true;
+ } else {
+ LOG.info(AaiUiMsgs.INDEX_NOT_EXIST, schemaConfig.getIndexName());
+ return false;
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.openecomp.sparky.synchronizer.IndexValidator#integrityValid()
+ */
+ @Override
+ public boolean integrityValid() {
+ return true;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.openecomp.sparky.synchronizer.IndexValidator#createOrRepair()
+ */
+ @Override
+ public void createOrRepair() {
+
+ String message =
+ "IndexIntegrityValidator.createOrRepair() for indexName = " + schemaConfig.getIndexName();
+ LOG.info(AaiUiMsgs.INFO_GENERIC, message);
+
+ final String fullUrlStr = getFullUrl("/" + schemaConfig.getIndexName() + "/");
+ OperationResult createResult =
+ esAdapter.doPut(fullUrlStr, tableConfigJson, MediaType.APPLICATION_JSON_TYPE);
+
+ int rc = createResult.getResultCode();
+
+ if (rc >= 200 && rc < 300) {
+ LOG.info(AaiUiMsgs.INDEX_RECREATED, schemaConfig.getIndexName());
+ } else if (rc == 400) {
+ LOG.info(AaiUiMsgs.INDEX_ALREADY_EXISTS, schemaConfig.getIndexName());
+ } else {
+ LOG.warn(AaiUiMsgs.INDEX_INTEGRITY_CHECK_FAILED, schemaConfig.getIndexName(),
+ createResult.getResult());
+ }
+
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.openecomp.sparky.synchronizer.IndexValidator#destroyIndex()
+ */
+ @Override
+ public void destroyIndex() {
+ // we don't do this for now
+ }
+
+ /**
+ * Gets the full url.
+ *
+ * @param resourceUrl the resource url
+ * @return the full url
+ */
+ private String getFullUrl(String resourceUrl) {
+ return String.format("http://%s:%s%s", endpointConfig.getEsIpAddress(),
+ endpointConfig.getEsServerPort(), resourceUrl);
+ }
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/IndexSynchronizer.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/IndexSynchronizer.java
new file mode 100644
index 0000000..05c7a5e
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/IndexSynchronizer.java
@@ -0,0 +1,67 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.sync;
+
+import org.onap.aai.sparky.sync.enumeration.OperationState;
+import org.onap.aai.sparky.sync.enumeration.SynchronizerState;
+
+/**
+ * The Interface IndexSynchronizer.
+ *
+ * @author davea.
+ */
+public interface IndexSynchronizer {
+
+ /**
+ * Do sync.
+ *
+ * @return the operation state
+ */
+ public OperationState doSync();
+
+ public SynchronizerState getState();
+
+ /**
+ * Gets the stat report.
+ *
+ * @param finalReport the final report
+ * @return the stat report
+ */
+ public String getStatReport(boolean finalReport);
+
+ /**
+ * Shutdown.
+ */
+ public void shutdown();
+
+ public String getIndexName();
+
+ /**
+ * Clear cache.
+ */
+ public void clearCache();
+
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/IndexValidator.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/IndexValidator.java
new file mode 100644
index 0000000..05e7d91
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/IndexValidator.java
@@ -0,0 +1,58 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.sync;
+
+/**
+ * The Interface IndexValidator.
+ */
+public interface IndexValidator {
+
+ /**
+ * Exists.
+ *
+ * @return true, if successful
+ */
+ public boolean exists();
+
+ /**
+ * Integrity valid.
+ *
+ * @return true, if successful
+ */
+ public boolean integrityValid();
+
+ /**
+ * Creates the or repair.
+ */
+ public void createOrRepair();
+
+ /**
+ * Destroy index.
+ */
+ public void destroyIndex();
+
+ public String getIndexName();
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/SyncController.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/SyncController.java
new file mode 100644
index 0000000..bdd009b
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/SyncController.java
@@ -0,0 +1,96 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.sync;
+
+import java.util.Calendar;
+import java.util.Date;
+
+import org.onap.aai.sparky.sync.SyncControllerImpl.SyncActions;
+import org.onap.aai.sparky.sync.enumeration.OperationState;
+import org.onap.aai.sparky.sync.enumeration.SynchronizerState;
+
+public interface SyncController {
+
+ String getControllerName();
+ boolean isPeriodicSyncEnabled();
+ boolean isRunOnceSyncEnabled();
+
+ /**
+ * Perform action.
+ *
+ * @param requestedAction the requested action
+ * @return
+ */
+ OperationState performAction(SyncActions requestedAction);
+
+ /**
+ * Register entity synchronizer.
+ *
+ * @param entitySynchronizer the entity synchronizer
+ */
+ void registerEntitySynchronizer(IndexSynchronizer entitySynchronizer);
+
+ /**
+ * Register index validator.
+ *
+ * @param indexValidator the index validator
+ */
+ void registerIndexValidator(IndexValidator indexValidator);
+
+ /**
+ * Register index cleaner.
+ *
+ * @param indexCleaner the index cleaner
+ */
+ void registerIndexCleaner(IndexCleaner indexCleaner);
+
+ /**
+ * Shutdown.
+ */
+ void shutdown();
+
+ SynchronizerState getState();
+
+ long getDelayInMs();
+
+ void setDelayInMs(long delayInMs);
+
+ long getSyncFrequencyInMs();
+
+ void setSyncFrequencyInMs(long syncFrequencyInMs);
+
+ Date getSyncStartTime();
+
+ void setSyncStartTime(Date syncStartTime);
+
+ Date getLastExecutionDate();
+
+ void setLastExecutionDate(Date lastExecutionDate);
+
+ Calendar getCreationTime();
+
+ String getNextSyncTime();
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/SyncControllerImpl.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/SyncControllerImpl.java
new file mode 100644
index 0000000..0e0b193
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/SyncControllerImpl.java
@@ -0,0 +1,682 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.sync;
+
+import static java.util.concurrent.CompletableFuture.supplyAsync;
+
+import java.util.Calendar;
+import java.util.Collection;
+import java.util.Date;
+import java.util.LinkedHashSet;
+import java.util.TimeZone;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Supplier;
+
+import org.onap.aai.cl.api.Logger;
+import org.onap.aai.cl.eelf.LoggerFactory;
+import org.onap.aai.sparky.logging.AaiUiMsgs;
+import org.onap.aai.sparky.sync.config.SyncControllerConfig;
+import org.onap.aai.sparky.sync.enumeration.OperationState;
+import org.onap.aai.sparky.sync.enumeration.SynchronizerState;
+import org.onap.aai.sparky.util.NodeUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+/**
+ * The Class SyncController.
+ *
+ * @author davea.
+ */
+public class SyncControllerImpl implements SyncController {
+ private static final Logger LOG = LoggerFactory.getInstance().getLogger(SyncControllerImpl.class);
+
+ /**
+ * The Enum InternalState.
+ */
+ private enum InternalState {
+ IDLE, PRE_SYNC, SYNC_OPERATION, SELECTIVE_DELETE, ABORTING_SYNC, REPAIRING_INDEX, POST_SYNC,
+ TEST_INDEX_INTEGRITY, GENERATE_FINAL_REPORT
+ }
+
+ /**
+ * The Enum SyncActions.
+ */
+ public enum SyncActions {
+ SYNCHRONIZE, REPAIR_INDEX, INDEX_INTEGRITY_VALIDATION_COMPLETE, PRE_SYNC_COMPLETE,
+ SYNC_COMPLETE, SYNC_ABORTED, SYNC_FAILURE, POST_SYNC_COMPLETE, PURGE_COMPLETE, REPORT_COMPLETE
+ }
+
+ private Collection<IndexSynchronizer> registeredSynchronizers;
+ private Collection<IndexValidator> registeredIndexValidators;
+ private Collection<IndexCleaner> registeredIndexCleaners;
+ private InternalState currentInternalState;
+ private ExecutorService syncControllerExecutor;
+ private ExecutorService statReporterExecutor;
+
+ private long delayInMs;
+ private long syncFrequencyInMs;
+ private Date syncStartTime;
+
+ private Date lastExecutionDate;
+ private AtomicInteger runCount;
+ private Semaphore performingActionGate;
+ private Calendar creationTime;
+
+ private String syncStartTimeWithTimeZone;
+ private String controllerName;
+
+ protected SyncControllerConfig syncControllerConfig;
+
+
+
+
+ /**
+ * Instantiates a new sync controller.
+ *
+ * @param name the name
+ * @throws Exception the exception
+ */
+ public SyncControllerImpl(SyncControllerConfig syncControllerConfig) throws Exception {
+ this(syncControllerConfig,null);
+ }
+
+ public SyncControllerImpl(SyncControllerConfig syncControllerConfig, String targetEntityType)
+ throws Exception {
+
+ this.syncControllerConfig = syncControllerConfig;
+
+ this.delayInMs = 0L;
+ this.syncFrequencyInMs = 86400000L;
+ this.syncStartTime = null;
+ this.lastExecutionDate = null;
+ this.runCount = new AtomicInteger(0);
+ this.performingActionGate = new Semaphore(1);
+ registeredSynchronizers = new LinkedHashSet<IndexSynchronizer>();
+ registeredIndexValidators = new LinkedHashSet<IndexValidator>();
+ registeredIndexCleaners = new LinkedHashSet<IndexCleaner>();
+
+ String controllerName = syncControllerConfig.getControllerName();
+
+ if (targetEntityType != null) {
+ controllerName += " (" + targetEntityType + ")";
+ }
+
+ this.controllerName = controllerName;
+
+ this.syncControllerExecutor = NodeUtils.createNamedExecutor("SyncController-" + controllerName,
+ syncControllerConfig.getNumSyncControllerWorkers(), LOG);
+ this.statReporterExecutor =
+ NodeUtils.createNamedExecutor("StatReporter-" + controllerName, 1, LOG);
+
+ this.currentInternalState = InternalState.IDLE;
+
+ this.creationTime =
+ Calendar.getInstance(TimeZone.getTimeZone(syncControllerConfig.getTimeZoneOfSyncStartTimeStamp()));
+
+ }
+
+
+
+
+
+
+ /**
+ * Change internal state.
+ *
+ * @param newState the new state
+ * @param causedByAction the caused by action
+ */
+ private void changeInternalState(InternalState newState, SyncActions causedByAction) {
+ LOG.info(AaiUiMsgs.SYNC_INTERNAL_STATE_CHANGED, controllerName,
+ currentInternalState.toString(), newState.toString(), causedByAction.toString());
+
+ this.currentInternalState = newState;
+
+ performStateAction();
+ }
+
+
+
+ /* (non-Javadoc)
+ * @see org.openecomp.sparky.synchronizer.SyncController2#getDelayInMs()
+ */
+ @Override
+ public long getDelayInMs() {
+ return delayInMs;
+ }
+
+ /* (non-Javadoc)
+ * @see org.openecomp.sparky.synchronizer.SyncController2#setDelayInMs(long)
+ */
+ @Override
+ public void setDelayInMs(long delayInMs) {
+ this.delayInMs = delayInMs;
+ }
+
+ /* (non-Javadoc)
+ * @see org.openecomp.sparky.synchronizer.SyncController2#getSyncFrequencyInMs()
+ */
+ @Override
+ public long getSyncFrequencyInMs() {
+ return syncFrequencyInMs;
+ }
+
+ /* (non-Javadoc)
+ * @see org.openecomp.sparky.synchronizer.SyncController2#setSyncFrequencyInMs(long)
+ */
+ @Override
+ public void setSyncFrequencyInMs(long syncFrequencyInMs) {
+ this.syncFrequencyInMs = syncFrequencyInMs;
+ }
+
+ /* (non-Javadoc)
+ * @see org.openecomp.sparky.synchronizer.SyncController2#getSyncStartTime()
+ */
+ @Override
+ public Date getSyncStartTime() {
+ return syncStartTime;
+ }
+
+ /* (non-Javadoc)
+ * @see org.openecomp.sparky.synchronizer.SyncController2#setSyncStartTime(java.util.Date)
+ */
+ @Override
+ public void setSyncStartTime(Date syncStartTime) {
+ this.syncStartTime = syncStartTime;
+ }
+
+ /* (non-Javadoc)
+ * @see org.openecomp.sparky.synchronizer.SyncController2#getLastExecutionDate()
+ */
+ @Override
+ public Date getLastExecutionDate() {
+ return lastExecutionDate;
+ }
+
+ /* (non-Javadoc)
+ * @see org.openecomp.sparky.synchronizer.SyncController2#setLastExecutionDate(java.util.Date)
+ */
+ @Override
+ public void setLastExecutionDate(Date lastExecutionDate) {
+ this.lastExecutionDate = lastExecutionDate;
+ }
+
+ @Override
+ public String getControllerName() {
+ return controllerName;
+ }
+
+
+
+
+ @Override
+ public OperationState performAction(SyncActions requestedAction) {
+
+ if (currentInternalState == InternalState.IDLE) {
+
+ try {
+
+ /*
+ * non-blocking semaphore acquire used to guarantee only 1 execution of the synchronization
+ * at a time.
+ */
+
+ switch (requestedAction) {
+ case SYNCHRONIZE:
+
+ if (performingActionGate.tryAcquire()) {
+ try {
+
+ long opStartTime = System.currentTimeMillis();
+
+ LOG.info(AaiUiMsgs.INFO_GENERIC,
+ getControllerName() + " started synchronization at "
+ + SynchronizerConstants.SIMPLE_DATE_FORMAT.format(opStartTime).replaceAll(
+ SynchronizerConstants.TIME_STD, SynchronizerConstants.TIME_CONFIG_STD));
+
+ runCount.incrementAndGet();
+
+ changeInternalState(InternalState.TEST_INDEX_INTEGRITY, requestedAction);
+
+ long opEndTime = System.currentTimeMillis();
+
+ long opTime = (opEndTime - opStartTime);
+
+ String durationMessage =
+ String.format(getControllerName() + " synchronization took '%d' ms.", opTime);
+
+ LOG.info(AaiUiMsgs.SYNC_DURATION, durationMessage);
+
+ if (syncControllerConfig.isPeriodicSyncEnabled()) {
+
+ LOG.info(AaiUiMsgs.INFO_GENERIC,
+ getControllerName() + " next sync to begin at " + getNextSyncTime());
+
+ TimeZone tz = TimeZone.getTimeZone(syncControllerConfig.getTimeZoneOfSyncStartTimeStamp());
+
+ if (opTime > this.getSyncFrequencyInMs()) {
+
+ String durationWasLongerMessage = String.format(
+ getControllerName() + " synchronization took '%d' ms which is larger than"
+ + " synchronization interval of '%d' ms.",
+ opTime, this.getSyncFrequencyInMs());
+
+ LOG.info(AaiUiMsgs.SYNC_DURATION, durationWasLongerMessage);
+ }
+ }
+
+ } catch (Exception syncException) {
+ String message = "An error occurred while performing action = " + requestedAction
+ + ". Error = " + syncException.getMessage();
+ LOG.error(AaiUiMsgs.ERROR_GENERIC, message);
+ } finally {
+ performingActionGate.release();
+ }
+ } else {
+ return OperationState.IGNORED_SYNC_NOT_IDLE;
+ }
+
+ break;
+
+ default:
+ break;
+ }
+
+ return OperationState.OK;
+
+ } catch (Exception exc) {
+ String message = "An error occurred while performing action = " + requestedAction
+ + ". Error = " + exc.getMessage();
+ LOG.error(AaiUiMsgs.ERROR_GENERIC, message);
+ return OperationState.ERROR;
+ } finally {
+
+ }
+ } else {
+ LOG.error(AaiUiMsgs.SYNC_NOT_VALID_STATE_DURING_REQUEST, currentInternalState.toString());
+ return OperationState.IGNORED_SYNC_NOT_IDLE;
+ }
+ }
+
+ /**
+ * Perform state action.
+ */
+ private void performStateAction() {
+
+ try {
+ switch (currentInternalState) {
+
+ case TEST_INDEX_INTEGRITY:
+ performIndexIntegrityValidation();
+ break;
+
+ case PRE_SYNC:
+ performPreSyncCleanupCollection();
+ break;
+
+ case SYNC_OPERATION:
+ performSynchronization();
+ break;
+
+ case POST_SYNC:
+ performIndexSyncPostCollection();
+ changeInternalState(InternalState.SELECTIVE_DELETE, SyncActions.POST_SYNC_COMPLETE);
+ break;
+
+ case SELECTIVE_DELETE:
+ performIndexCleanup();
+ changeInternalState(InternalState.GENERATE_FINAL_REPORT, SyncActions.PURGE_COMPLETE);
+ break;
+
+ case GENERATE_FINAL_REPORT:
+
+ dumpStatReport(true);
+ clearCaches();
+ changeInternalState(InternalState.IDLE, SyncActions.REPORT_COMPLETE);
+ break;
+
+ case ABORTING_SYNC:
+ performSyncAbort();
+ break;
+
+ default:
+ break;
+ }
+ } catch (Exception exc) {
+ /*
+ * Perhaps we should abort the sync on an exception
+ */
+ String message = "Caught an error which performing action. Error = " + exc.getMessage();
+ LOG.error(AaiUiMsgs.ERROR_GENERIC, message);
+ }
+ }
+
+ @Override
+ public void registerEntitySynchronizer(IndexSynchronizer entitySynchronizer) {
+
+ String indexName = entitySynchronizer.getIndexName();
+
+ if (indexName != null) {
+ registeredSynchronizers.add(entitySynchronizer);
+ } else {
+ String message = "Failed to register entity synchronizer because index name is null";
+ LOG.error(AaiUiMsgs.FAILED_TO_REGISTER_DUE_TO_NULL, message);
+ }
+
+ }
+
+ @Override
+ public void registerIndexValidator(IndexValidator indexValidator) {
+
+ String indexName = indexValidator.getIndexName();
+
+ if (indexName != null) {
+ registeredIndexValidators.add(indexValidator);
+ } else {
+ String message = "Failed to register index validator because index name is null";
+ LOG.error(AaiUiMsgs.FAILED_TO_REGISTER_DUE_TO_NULL, message);
+ }
+
+ }
+
+ @Override
+ public void registerIndexCleaner(IndexCleaner indexCleaner) {
+
+ String indexName = indexCleaner.getIndexName();
+
+ if (indexName != null) {
+ registeredIndexCleaners.add(indexCleaner);
+ } else {
+ String message = "Failed to register index cleaner because index name is null";
+ LOG.error(AaiUiMsgs.FAILED_TO_REGISTER_DUE_TO_NULL, message);
+ }
+ }
+
+ /*
+ * State machine should drive our flow dosync just dispatches an action and the state machine
+ * determines what is in play and what is next
+ */
+
+ /**
+ * Dump stat report.
+ *
+ * @param showFinalReport the show final report
+ */
+ private void dumpStatReport(boolean showFinalReport) {
+
+ for (IndexSynchronizer synchronizer : registeredSynchronizers) {
+
+ String statReport = synchronizer.getStatReport(showFinalReport);
+
+ if (statReport != null) {
+ LOG.info(AaiUiMsgs.INFO_GENERIC, statReport);
+ }
+ }
+ }
+
+ /**
+ * Clear caches.
+ */
+ private void clearCaches() {
+
+ /*
+ * Any entity caches that were built as part of the sync operation should be cleared to save
+ * memory. The original intent of the caching was to provide a short-lived cache to satisfy
+ * entity requests from multiple synchronizers yet minimizing interactions with the AAI.
+ */
+
+ for (IndexSynchronizer synchronizer : registeredSynchronizers) {
+ synchronizer.clearCache();
+ }
+ }
+
+ /**
+ * Perform pre sync cleanup collection.
+ */
+ private void performPreSyncCleanupCollection() {
+
+ /*
+ * ask the index cleaners to collect the their pre-sync object id collections
+ */
+
+ for (IndexCleaner cleaner : registeredIndexCleaners) {
+ cleaner.populatePreOperationCollection();
+ }
+
+ changeInternalState(InternalState.SYNC_OPERATION, SyncActions.PRE_SYNC_COMPLETE);
+
+ }
+
+ /**
+ * Perform index sync post collection.
+ */
+ private void performIndexSyncPostCollection() {
+
+ /*
+ * ask the entity purgers to collect the their pre-sync object id collections
+ */
+
+ for (IndexCleaner cleaner : registeredIndexCleaners) {
+ cleaner.populatePostOperationCollection();
+ }
+
+ }
+
+ /**
+ * Perform index cleanup.
+ */
+ private void performIndexCleanup() {
+
+ /*
+ * ask the entity purgers to collect the their pre-sync object id collections
+ */
+
+ for (IndexCleaner cleaner : registeredIndexCleaners) {
+ cleaner.performCleanup();
+ }
+
+ }
+
+ /**
+ * Perform sync abort.
+ */
+ private void performSyncAbort() {
+ changeInternalState(InternalState.IDLE, SyncActions.SYNC_ABORTED);
+ }
+
+ /**
+ * Perform index integrity validation.
+ */
+ private void performIndexIntegrityValidation() {
+
+ /*
+ * loop through registered index validators and test and fix, if needed
+ */
+
+ for (IndexValidator validator : registeredIndexValidators) {
+ try {
+ if (!validator.exists()) {
+ validator.createOrRepair();
+ }
+ } catch (Exception exc) {
+ String message = "Index validator caused an error = " + exc.getMessage();
+ LOG.error(AaiUiMsgs.ERROR_GENERIC, message);
+ }
+ }
+
+ changeInternalState(InternalState.PRE_SYNC, SyncActions.INDEX_INTEGRITY_VALIDATION_COMPLETE);
+
+ }
+
+ /* (non-Javadoc)
+ * @see org.openecomp.sparky.synchronizer.SyncControllerInterface#shutdown()
+ */
+ @Override
+ public void shutdown() {
+
+ this.syncControllerExecutor.shutdown();
+ for (IndexSynchronizer synchronizer : registeredSynchronizers) {
+
+ try {
+ synchronizer.shutdown();
+ } catch (Exception exc) {
+ LOG.error(AaiUiMsgs.ERROR_GENERIC,
+ "Synchronizer shutdown caused an error = " + exc.getMessage());
+ }
+
+ }
+ this.statReporterExecutor.shutdown();
+ }
+
+ /*
+ * Need some kind of task running that responds to a transient boolean to kill it or we just stop
+ * the executor that it is in?
+ */
+
+
+
+ /**
+ * Perform synchronization.
+ */
+ private void performSynchronization() {
+
+ /*
+ * Get all the synchronizers running in parallel
+ */
+
+ for (IndexSynchronizer synchronizer : registeredSynchronizers) {
+ supplyAsync(new Supplier<Void>() {
+
+ @Override
+ public Void get() {
+
+ synchronizer.doSync();
+ return null;
+ }
+
+ }, this.syncControllerExecutor).whenComplete((result, error) -> {
+
+ /*
+ * We don't bother checking the result, because it will always be null as the doSync() is
+ * non-blocking.
+ */
+
+ if (error != null) {
+ LOG.error(AaiUiMsgs.ERROR_GENERIC,
+ "doSync operation failed with an error = " + error.getMessage());
+ }
+ });
+ }
+
+ boolean allDone = false;
+ long nextReportTimeStampInMs = System.currentTimeMillis() + 30000L;
+ boolean dumpPeriodicStatReport = false;
+
+ while (!allDone) {
+ int totalFinished = 0;
+
+ for (IndexSynchronizer synchronizer : registeredSynchronizers) {
+ if (dumpPeriodicStatReport) {
+ if (synchronizer.getState() == SynchronizerState.PERFORMING_SYNCHRONIZATION) {
+ String statReport = synchronizer.getStatReport(false);
+
+ if (statReport != null) {
+ LOG.info(AaiUiMsgs.INFO_GENERIC, statReport);
+ }
+ }
+ }
+
+ if (synchronizer.getState() == SynchronizerState.IDLE
+ || synchronizer.getState() == SynchronizerState.ABORTED) {
+ totalFinished++;
+ }
+ }
+
+ if ( System.currentTimeMillis() > nextReportTimeStampInMs) {
+ dumpPeriodicStatReport = true;
+ nextReportTimeStampInMs = System.currentTimeMillis() + 30000L;
+ } else {
+ dumpPeriodicStatReport = false;
+ }
+
+ allDone = (totalFinished == registeredSynchronizers.size());
+
+ try {
+ Thread.sleep(250);
+ } catch (InterruptedException exc) {
+ LOG.error(AaiUiMsgs.ERROR_GENERIC,
+ "An error occurred while waiting for sync to complete. Error = " + exc.getMessage());
+ }
+
+ }
+
+ changeInternalState(InternalState.POST_SYNC, SyncActions.SYNC_COMPLETE);
+
+ }
+
+ /* (non-Javadoc)
+ * @see org.openecomp.sparky.synchronizer.SyncControllerInterface#getState()
+ */
+ @Override
+ public SynchronizerState getState() {
+
+ switch (currentInternalState) {
+
+ case IDLE: {
+ return SynchronizerState.IDLE;
+ }
+
+ default: {
+ return SynchronizerState.PERFORMING_SYNCHRONIZATION;
+
+ }
+ }
+
+ }
+
+ @Override
+ public Calendar getCreationTime() {
+ return creationTime;
+ }
+
+ @Override
+ public String getNextSyncTime() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public boolean isPeriodicSyncEnabled() {
+ return syncControllerConfig.isPeriodicSyncEnabled();
+ }
+
+ @Override
+ public boolean isRunOnceSyncEnabled() {
+ return syncControllerConfig.isRunOnceSyncEnabled();
+ }
+
+} \ No newline at end of file
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/SyncControllerRegistrar.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/SyncControllerRegistrar.java
new file mode 100644
index 0000000..f20eceb
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/SyncControllerRegistrar.java
@@ -0,0 +1,29 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.sync;
+
+public interface SyncControllerRegistrar {
+ public void registerController();
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/SyncControllerRegistry.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/SyncControllerRegistry.java
new file mode 100644
index 0000000..d4013d3
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/SyncControllerRegistry.java
@@ -0,0 +1,50 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.sync;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class SyncControllerRegistry {
+
+ private List<SyncController> controllers;
+
+ public SyncControllerRegistry() {
+ controllers = new ArrayList<SyncController>();
+ }
+
+ public void registerSyncController(SyncController controller) {
+ controllers.add(controller);
+ }
+
+ public List<SyncController> getControllers() {
+ return controllers;
+ }
+
+ public void setControllers(List<SyncController> controllers) {
+ this.controllers = controllers;
+ }
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/SyncControllerService.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/SyncControllerService.java
new file mode 100644
index 0000000..07653b7
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/SyncControllerService.java
@@ -0,0 +1,222 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.sync;
+
+import java.lang.Thread.UncaughtExceptionHandler;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+
+import org.onap.aai.cl.api.Logger;
+import org.onap.aai.cl.eelf.LoggerFactory;
+import org.onap.aai.sparky.logging.AaiUiMsgs;
+import org.onap.aai.sparky.sync.SyncControllerImpl.SyncActions;
+import org.onap.aai.sparky.sync.enumeration.OperationState;
+import org.onap.aai.sparky.sync.enumeration.SynchronizerState;
+import org.springframework.context.ApplicationListener;
+import org.springframework.context.event.ApplicationContextEvent;
+
+import com.google.common.util.concurrent.ThreadFactoryBuilder;
+
+public class SyncControllerService implements ApplicationListener<ApplicationContextEvent> {
+
+ private SyncControllerRegistry syncControllerRegistry;
+ private ExecutorService runonceSyncExecutor;
+ private ScheduledExecutorService periodicSyncExecutor;
+ private boolean syncStarted;
+
+ private static final Logger LOG =
+ LoggerFactory.getInstance().getLogger(SyncControllerService.class);
+
+ private class SyncControllerTask implements Runnable {
+
+ private SyncController controller;
+
+ public SyncControllerTask(SyncController controller) {
+ this.controller = controller;
+ }
+
+ @Override
+ public void run() {
+
+ try {
+
+ if (controller.getState() == SynchronizerState.IDLE) {
+
+ /*
+ * This is a blocking-call, but would be nicer if it was async internally within the
+ * controller but at the moment, that's not the way it works.
+ */
+
+ if (controller.performAction(SyncActions.SYNCHRONIZE) != OperationState.OK) {
+
+ LOG.info(AaiUiMsgs.INFO_GENERIC,
+ controller.getControllerName() + " is not idle, sync attempt has been skipped.");
+ }
+ } else {
+
+ LOG.info(AaiUiMsgs.INFO_GENERIC,
+ controller.getControllerName() + " is not idle, sync attempt has been skipped.");
+ }
+
+ } catch (Exception exception) {
+ LOG.error(AaiUiMsgs.ERROR_GENERIC,
+ "Error while attempting synchronization. Error = " + exception.getMessage());
+ }
+
+ }
+
+ }
+
+ public SyncControllerService(SyncControllerRegistry syncControllerRegistry, int numRunOnceWorkers,
+ int numPeriodicWorkers) {
+ this.syncControllerRegistry = syncControllerRegistry;
+ this.syncStarted = false;
+
+ UncaughtExceptionHandler uncaughtExceptionHandler = new Thread.UncaughtExceptionHandler() {
+
+ @Override
+ public void uncaughtException(Thread thread, Throwable exc) {
+ LOG.error(AaiUiMsgs.ERROR_GENERIC, thread.getName() + ": " + exc);
+ }
+ };
+
+ runonceSyncExecutor = Executors.newFixedThreadPool(numRunOnceWorkers,
+ new ThreadFactoryBuilder().setNameFormat("RunonceSyncWorker-%d")
+ .setUncaughtExceptionHandler(uncaughtExceptionHandler).build());
+
+
+ periodicSyncExecutor = Executors.newScheduledThreadPool(numPeriodicWorkers,
+ new ThreadFactoryBuilder().setNameFormat("PeriodicSyncWorker-%d")
+ .setUncaughtExceptionHandler(uncaughtExceptionHandler).build());
+
+ }
+
+ public SyncControllerRegistry getSyncControllerRegistry() {
+ return syncControllerRegistry;
+ }
+
+ public void startSync() {
+
+ long syncInitialDelayInMs = 0;
+
+ for (SyncController controller : syncControllerRegistry.getControllers()) {
+
+ syncInitialDelayInMs = controller.getDelayInMs();
+
+ if (!controller.isPeriodicSyncEnabled()) {
+
+ if (controller.isRunOnceSyncEnabled()) {
+ LOG.info(AaiUiMsgs.INFO_GENERIC, controller.getControllerName() + " is enabled.");
+ runonceSyncExecutor.submit(new SyncControllerTask(controller));
+ } else {
+ LOG.info(AaiUiMsgs.INFO_GENERIC, controller.getControllerName() + " is disabled.");
+ }
+
+ } else {
+
+ /**
+ * Do both. We'll take one instance of the SyncController and wrap the object instance into
+ * two SyncControllerTasks. The responsibility for preventing a conflicting sync should live
+ * in the SyncController instance. If a sync is underway when the periodic sync kicks in,
+ * then it will be ignored by the SyncController which is already underway.
+ *
+ * The SyncController instance itself would then also be stateful such that it would know
+ * the last time it ran, and the next time it is supposed to run, the number times a sync
+ * has executed, etc.
+ */
+
+ if (controller.isRunOnceSyncEnabled()) {
+ LOG.info(AaiUiMsgs.INFO_GENERIC,
+ controller.getControllerName() + " run-once sync is enabled.");
+ runonceSyncExecutor.submit(new SyncControllerTask(controller));
+ } else {
+ LOG.info(AaiUiMsgs.INFO_GENERIC,
+ controller.getControllerName() + " run-once sync is disabled.");
+ }
+
+ /*
+ * The controller knows it's configuredfrequency and we can just ask it to tell us what the
+ * delay and frequency needs to be, rather than trying to calculate the configured frequency
+ * per controller which "could" be different for each controller.
+ */
+
+ if (controller.isPeriodicSyncEnabled()) {
+
+ LOG.info(AaiUiMsgs.INFO_GENERIC,
+ controller.getControllerName() + " periodic sync is enabled and scheduled to start @ "
+ + controller.getNextSyncTime());
+
+ periodicSyncExecutor.scheduleAtFixedRate(new SyncControllerTask(controller),
+ controller.getDelayInMs(), controller.getSyncFrequencyInMs(), TimeUnit.MILLISECONDS);
+
+ } else {
+
+ LOG.info(AaiUiMsgs.INFO_GENERIC,
+ controller.getControllerName() + " periodic sync is disabled.");
+
+ }
+
+ }
+
+ }
+
+ }
+
+ public void shutdown() {
+
+ if (runonceSyncExecutor != null) {
+ runonceSyncExecutor.shutdown();
+ }
+
+ if (periodicSyncExecutor != null) {
+ periodicSyncExecutor.shutdown();
+ }
+
+ if (syncControllerRegistry != null) {
+ for (SyncController controller : syncControllerRegistry.getControllers()) {
+ controller.shutdown();
+ }
+ }
+
+ }
+
+ @Override
+ public synchronized void onApplicationEvent(ApplicationContextEvent arg0) {
+
+ /*
+ * Start sync service processing when spring-context-initialization has finished
+ */
+
+ if (!syncStarted) {
+ syncStarted = true;
+ startSync();
+ }
+
+ }
+
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/SynchronizerConstants.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/SynchronizerConstants.java
new file mode 100644
index 0000000..9201f07
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/SynchronizerConstants.java
@@ -0,0 +1,65 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.sync;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+/**
+ * The Class SynchronizerConstants.
+ */
+public final class SynchronizerConstants {
+ // Error values for invalid user input
+ public static final int DEFAULT_CONFIG_ERROR_INT_VALUE = Integer.MAX_VALUE;
+ public static final Date DEFAULT_CONFIG_ERROR_DATE_VALUE = new Date(Long.MAX_VALUE);
+ public static final SimpleDateFormat SIMPLE_DATE_FORMAT =
+ new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z");
+
+ public static final String DEPTH_MODIFIER = "?depth=0";
+ public static final String DEPTH_ALL_MODIFIER = "?depth=all";
+ public static final String DEPTH_AND_NODES_ONLY_MODIFIER = "?depth=0&nodes-only";
+ public static final String NODES_ONLY_MODIFIER = "?nodes-only";
+
+ // constants for scheduling synchronizer
+ public static final int COMPONENTS_IN_TIMESTAMP = 2;
+ public static final String DEFAULT_INITIAL_DELAY_IN_MS = "0";
+ public static final String DEFAULT_TASK_FREQUENCY_IN_DAY = "0";
+ public static final String DEFAULT_START_TIMESTAMP = "05:00:00 UTC";
+ public static final long DELAY_NO_STARTUP_SYNC_IN_MS = 0;
+ public static final long DELAY_NO_PERIODIC_SYNC_IN_MS = 0;
+ public static final int IDX_TIME_IN_TIMESTAMP = 0;
+ public static final int IDX_TIMEZONE_IN_TIMESTAMP = 1;
+ public static final long MILLISEC_IN_A_MIN = 60000;
+ public static final long MILLISEC_IN_A_DAY = 24 * 60 * 60 * 1000;
+ public static final String TIME_STD = "GMT";
+ public static final String TIME_CONFIG_STD = "UTC";
+ public static final String TIMESTAMP24HOURS_PATTERN =
+ "([01]?[0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9] UTC[+|-][0-5][0-9]:[0-5][0-9]";
+
+ /**
+ * Instantiates a new synchronizer constants.
+ */
+ private SynchronizerConstants() {}
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/TaskProcessingStats.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/TaskProcessingStats.java
new file mode 100644
index 0000000..48625c0
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/TaskProcessingStats.java
@@ -0,0 +1,135 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.sync;
+
+import org.onap.aai.sparky.analytics.AbstractStatistics;
+import org.onap.aai.sparky.sync.config.NetworkStatisticsConfig;
+
+/**
+ * The Class TaskProcessingStats.
+ */
+public class TaskProcessingStats extends AbstractStatistics {
+
+ private static String TASK_AGE_STATS = "taskAgeStats";
+ private static String TASK_RESPONSE_STATS = "taskResponseStats";
+ private static String RESPONSE_SIZE_IN_BYTES = "taskResponseSizeInBytes";
+ // private static String QUEUE_ITEM_LENGTH = "queueItemLength";
+ private static String TPS = "transactionsPerSecond";
+
+ /**
+ * Instantiates a new task processing stats.
+ *
+ * @param config the config
+ */
+ public TaskProcessingStats(NetworkStatisticsConfig config) {
+
+ addHistogram(TASK_AGE_STATS, config.getTaskAgeHistogramLabel(),
+ config.getTaskAgeHistogramMaxYAxis(), config.getTaskAgeHistogramNumBins(),
+ config.getTaskAgeHistogramNumDecimalPoints());
+
+ addHistogram(TASK_RESPONSE_STATS, config.getResponseTimeHistogramLabel(),
+ config.getResponseTimeHistogramMaxYAxis(), config.getResponseTimeHistogramNumBins(),
+ config.getResponseTimeHistogramNumDecimalPoints());
+
+ addHistogram(RESPONSE_SIZE_IN_BYTES, config.getBytesHistogramLabel(),
+ config.getBytesHistogramMaxYAxis(), config.getBytesHistogramNumBins(),
+ config.getBytesHistogramNumDecimalPoints());
+
+ /*
+ * addHistogram(QUEUE_ITEM_LENGTH, config.getQueueLengthHistogramLabel(),
+ * config.getQueueLengthHistogramMaxYAxis(), config.getQueueLengthHistogramNumBins(),
+ * config.getQueueLengthHistogramNumDecimalPoints());
+ */
+
+ addHistogram(TPS, config.getTpsHistogramLabel(), config.getTpsHistogramMaxYAxis(),
+ config.getTpsHistogramNumBins(), config.getTpsHistogramNumDecimalPoints());
+
+ }
+
+ /*
+ * public void updateQueueItemLengthHistogram(long value) { updateHistogram(QUEUE_ITEM_LENGTH,
+ * value); }
+ */
+
+ /**
+ * Update task age stats histogram.
+ *
+ * @param value the value
+ */
+ public void updateTaskAgeStatsHistogram(long value) {
+ updateHistogram(TASK_AGE_STATS, value);
+ }
+
+ /**
+ * Update task response stats histogram.
+ *
+ * @param value the value
+ */
+ public void updateTaskResponseStatsHistogram(long value) {
+ updateHistogram(TASK_RESPONSE_STATS, value);
+ }
+
+ /**
+ * Update response size in bytes histogram.
+ *
+ * @param value the value
+ */
+ public void updateResponseSizeInBytesHistogram(long value) {
+ updateHistogram(RESPONSE_SIZE_IN_BYTES, value);
+ }
+
+ /**
+ * Update transactions per second histogram.
+ *
+ * @param value the value
+ */
+ public void updateTransactionsPerSecondHistogram(long value) {
+ updateHistogram(TPS, value);
+ }
+
+ /**
+ * Gets the statistics report.
+ *
+ * @param verboseEnabled the verbose enabled
+ * @param indentPadding the indent padding
+ * @return the statistics report
+ */
+ public String getStatisticsReport(boolean verboseEnabled, String indentPadding) {
+
+ StringBuilder sb = new StringBuilder();
+
+ sb.append("\n").append(getHistogramStats(TASK_AGE_STATS, verboseEnabled, indentPadding));
+ // sb.append("\n").append(getHistogramStats(QUEUE_ITEM_LENGTH, verboseEnabled, indentPadding));
+ sb.append("\n").append(getHistogramStats(TASK_RESPONSE_STATS, verboseEnabled, indentPadding));
+ sb.append("\n")
+ .append(getHistogramStats(RESPONSE_SIZE_IN_BYTES, verboseEnabled, indentPadding));
+ sb.append("\n").append(getHistogramStats(TPS, verboseEnabled, indentPadding));
+
+ return sb.toString();
+
+ }
+
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/TransactionRateMonitor.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/TransactionRateMonitor.java
new file mode 100644
index 0000000..e639eff
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/TransactionRateMonitor.java
@@ -0,0 +1,75 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.sync;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.onap.aai.sparky.analytics.AveragingRingBuffer;
+import org.onap.aai.sparky.sync.config.NetworkStatisticsConfig;
+
+public class TransactionRateMonitor {
+
+ private AtomicInteger numTransactions;
+ private AveragingRingBuffer responseTimeTracker;
+ private long startTimeInMs;
+
+ /**
+ * Instantiates a new transaction rate controller.
+ *
+ * @param config the config
+ */
+ public TransactionRateMonitor(int numWorkerThreads, NetworkStatisticsConfig config) {
+
+ this.responseTimeTracker = new AveragingRingBuffer(
+ config.getNumSamplesPerThreadForRunningAverage() * numWorkerThreads);
+ this.startTimeInMs = System.currentTimeMillis();
+ this.numTransactions = new AtomicInteger(0);
+ }
+
+ /**
+ * Track response time.
+ *
+ * @param responseTimeInMs the response time in ms
+ */
+ public void trackResponseTime(long responseTimeInMs) {
+ this.numTransactions.incrementAndGet();
+ responseTimeTracker.addSample(responseTimeInMs);
+ }
+
+ public long getAvg() {
+ return responseTimeTracker.getAvg();
+ }
+
+ public double getCurrentTps() {
+ if (numTransactions.get() > 0) {
+ double timeDelta = System.currentTimeMillis() - startTimeInMs;
+ double numTxns = numTransactions.get();
+ return (numTxns / timeDelta) * 1000.0;
+ }
+
+ return 0.0;
+ }
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/config/ElasticSearchEndpointConfig.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/config/ElasticSearchEndpointConfig.java
new file mode 100644
index 0000000..0197b9b
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/config/ElasticSearchEndpointConfig.java
@@ -0,0 +1,72 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.sync.config;
+
+public class ElasticSearchEndpointConfig {
+
+ private String esIpAddress;
+ private String esServerPort;
+ private int scrollContextTimeToLiveInMinutes;
+ private int scrollContextBatchRequestSize;
+
+ public ElasticSearchEndpointConfig() {
+
+ }
+
+ public String getEsIpAddress() {
+ return esIpAddress;
+ }
+
+ public void setEsIpAddress(String esIpAddress) {
+ this.esIpAddress = esIpAddress;
+ }
+
+ public String getEsServerPort() {
+ return esServerPort;
+ }
+
+ public void setEsServerPort(String esServerPort) {
+ this.esServerPort = esServerPort;
+ }
+
+ public int getScrollContextTimeToLiveInMinutes() {
+ return scrollContextTimeToLiveInMinutes;
+ }
+
+ public void setScrollContextTimeToLiveInMinutes(int scrollContextTimeToLiveInMinutes) {
+ this.scrollContextTimeToLiveInMinutes = scrollContextTimeToLiveInMinutes;
+ }
+
+ public int getScrollContextBatchRequestSize() {
+ return scrollContextBatchRequestSize;
+ }
+
+ public void setScrollContextBatchRequestSize(int scrollContextBatchRequestSize) {
+ this.scrollContextBatchRequestSize = scrollContextBatchRequestSize;
+ }
+
+
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/config/ElasticSearchSchemaConfig.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/config/ElasticSearchSchemaConfig.java
new file mode 100644
index 0000000..4f134c3
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/config/ElasticSearchSchemaConfig.java
@@ -0,0 +1,77 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.sync.config;
+
+public class ElasticSearchSchemaConfig {
+
+ private String indexName;
+ private String indexDocType;
+ private String indexSettingsFileName;
+ private String indexMappingsFileName;
+
+ public String getIndexName() {
+ return indexName;
+ }
+
+ public void setIndexName(String indexName) {
+ this.indexName = indexName;
+ }
+
+ public String getIndexDocType() {
+ return indexDocType;
+ }
+
+ public void setIndexDocType(String indexDocType) {
+ this.indexDocType = indexDocType;
+ }
+
+ public String getIndexSettingsFileName() {
+ return indexSettingsFileName;
+ }
+
+ public void setIndexSettingsFileName(String indexSettingsFileName) {
+ this.indexSettingsFileName = indexSettingsFileName;
+ }
+
+ public String getIndexMappingsFileName() {
+ return indexMappingsFileName;
+ }
+
+ public void setIndexMappingsFileName(String indexMappingsFileName) {
+ this.indexMappingsFileName = indexMappingsFileName;
+ }
+
+ @Override
+ public String toString() {
+ return "ElasticSearchSchemaConfig ["
+ + (indexName != null ? "indexName=" + indexName + ", " : "")
+ + (indexDocType != null ? "indexDocType=" + indexDocType + ", " : "")
+ + (indexSettingsFileName != null ? "indexSettingsFileName=" + indexSettingsFileName + ", "
+ : "")
+ + (indexMappingsFileName != null ? "indexMappingsFileName=" + indexMappingsFileName : "")
+ + "]";
+ }
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/config/NetworkStatisticsConfig.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/config/NetworkStatisticsConfig.java
new file mode 100644
index 0000000..0d089a4
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/config/NetworkStatisticsConfig.java
@@ -0,0 +1,239 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.sync.config;
+
+public class NetworkStatisticsConfig {
+
+ private int numSamplesPerThreadForRunningAverage;
+
+ private String bytesHistogramLabel;
+
+ private long bytesHistogramMaxYAxis;
+
+ private int bytesHistogramNumBins;
+
+ private int bytesHistogramNumDecimalPoints;
+
+ private String queueLengthHistogramLabel;
+
+ private long queueLengthHistogramMaxYAxis;
+
+ private int queueLengthHistogramNumBins;
+
+ private int queueLengthHistogramNumDecimalPoints;
+
+ private String taskAgeHistogramLabel;
+
+ private long taskAgeHistogramMaxYAxis;
+
+ private int taskAgeHistogramNumBins;
+
+ private int taskAgeHistogramNumDecimalPoints;
+
+ private String responseTimeHistogramLabel;
+
+ private long responseTimeHistogramMaxYAxis;
+
+ private int responseTimeHistogramNumBins;
+
+ private int responseTimeHistogramNumDecimalPoints;
+
+ private String tpsHistogramLabel;
+
+ private long tpsHistogramMaxYAxis;
+
+ private int tpsHistogramNumBins;
+
+ private int tpsHistogramNumDecimalPoints;
+
+ public int getNumSamplesPerThreadForRunningAverage() {
+ return numSamplesPerThreadForRunningAverage;
+ }
+
+ public void setNumSamplesPerThreadForRunningAverage(int numSamplesPerThreadForRunningAverage) {
+ this.numSamplesPerThreadForRunningAverage = numSamplesPerThreadForRunningAverage;
+ }
+
+ public String getBytesHistogramLabel() {
+ return bytesHistogramLabel;
+ }
+
+ public void setBytesHistogramLabel(String bytesHistogramLabel) {
+ this.bytesHistogramLabel = bytesHistogramLabel;
+ }
+
+ public long getBytesHistogramMaxYAxis() {
+ return bytesHistogramMaxYAxis;
+ }
+
+ public void setBytesHistogramMaxYAxis(long bytesHistogramMaxYAxis) {
+ this.bytesHistogramMaxYAxis = bytesHistogramMaxYAxis;
+ }
+
+ public int getBytesHistogramNumBins() {
+ return bytesHistogramNumBins;
+ }
+
+ public void setBytesHistogramNumBins(int bytesHistogramNumBins) {
+ this.bytesHistogramNumBins = bytesHistogramNumBins;
+ }
+
+ public int getBytesHistogramNumDecimalPoints() {
+ return bytesHistogramNumDecimalPoints;
+ }
+
+ public void setBytesHistogramNumDecimalPoints(int bytesHistogramNumDecimalPoints) {
+ this.bytesHistogramNumDecimalPoints = bytesHistogramNumDecimalPoints;
+ }
+
+ public String getQueueLengthHistogramLabel() {
+ return queueLengthHistogramLabel;
+ }
+
+ public void setQueueLengthHistogramLabel(String queueLengthHistogramLabel) {
+ this.queueLengthHistogramLabel = queueLengthHistogramLabel;
+ }
+
+ public long getQueueLengthHistogramMaxYAxis() {
+ return queueLengthHistogramMaxYAxis;
+ }
+
+ public void setQueueLengthHistogramMaxYAxis(long queueLengthHistogramMaxYAxis) {
+ this.queueLengthHistogramMaxYAxis = queueLengthHistogramMaxYAxis;
+ }
+
+ public int getQueueLengthHistogramNumBins() {
+ return queueLengthHistogramNumBins;
+ }
+
+ public void setQueueLengthHistogramNumBins(int queueLengthHistogramNumBins) {
+ this.queueLengthHistogramNumBins = queueLengthHistogramNumBins;
+ }
+
+ public int getQueueLengthHistogramNumDecimalPoints() {
+ return queueLengthHistogramNumDecimalPoints;
+ }
+
+ public void setQueueLengthHistogramNumDecimalPoints(int queueLengthHistogramNumDecimalPoints) {
+ this.queueLengthHistogramNumDecimalPoints = queueLengthHistogramNumDecimalPoints;
+ }
+
+ public String getTaskAgeHistogramLabel() {
+ return taskAgeHistogramLabel;
+ }
+
+ public void setTaskAgeHistogramLabel(String taskAgeHistogramLabel) {
+ this.taskAgeHistogramLabel = taskAgeHistogramLabel;
+ }
+
+ public long getTaskAgeHistogramMaxYAxis() {
+ return taskAgeHistogramMaxYAxis;
+ }
+
+ public void setTaskAgeHistogramMaxYAxis(long taskAgeHistogramMaxYAxis) {
+ this.taskAgeHistogramMaxYAxis = taskAgeHistogramMaxYAxis;
+ }
+
+ public int getTaskAgeHistogramNumBins() {
+ return taskAgeHistogramNumBins;
+ }
+
+ public void setTaskAgeHistogramNumBins(int taskAgeHistogramNumBins) {
+ this.taskAgeHistogramNumBins = taskAgeHistogramNumBins;
+ }
+
+ public int getTaskAgeHistogramNumDecimalPoints() {
+ return taskAgeHistogramNumDecimalPoints;
+ }
+
+ public void setTaskAgeHistogramNumDecimalPoints(int taskAgeHistogramNumDecimalPoints) {
+ this.taskAgeHistogramNumDecimalPoints = taskAgeHistogramNumDecimalPoints;
+ }
+
+ public String getResponseTimeHistogramLabel() {
+ return responseTimeHistogramLabel;
+ }
+
+ public void setResponseTimeHistogramLabel(String responseTimeHistogramLabel) {
+ this.responseTimeHistogramLabel = responseTimeHistogramLabel;
+ }
+
+ public long getResponseTimeHistogramMaxYAxis() {
+ return responseTimeHistogramMaxYAxis;
+ }
+
+ public void setResponseTimeHistogramMaxYAxis(long responseTimeHistogramMaxYAxis) {
+ this.responseTimeHistogramMaxYAxis = responseTimeHistogramMaxYAxis;
+ }
+
+ public int getResponseTimeHistogramNumBins() {
+ return responseTimeHistogramNumBins;
+ }
+
+ public void setResponseTimeHistogramNumBins(int responseTimeHistogramNumBins) {
+ this.responseTimeHistogramNumBins = responseTimeHistogramNumBins;
+ }
+
+ public int getResponseTimeHistogramNumDecimalPoints() {
+ return responseTimeHistogramNumDecimalPoints;
+ }
+
+ public void setResponseTimeHistogramNumDecimalPoints(int responseTimeHistogramNumDecimalPoints) {
+ this.responseTimeHistogramNumDecimalPoints = responseTimeHistogramNumDecimalPoints;
+ }
+
+ public String getTpsHistogramLabel() {
+ return tpsHistogramLabel;
+ }
+
+ public void setTpsHistogramLabel(String tpsHistogramLabel) {
+ this.tpsHistogramLabel = tpsHistogramLabel;
+ }
+
+ public long getTpsHistogramMaxYAxis() {
+ return tpsHistogramMaxYAxis;
+ }
+
+ public void setTpsHistogramMaxYAxis(long tpsHistogramMaxYAxis) {
+ this.tpsHistogramMaxYAxis = tpsHistogramMaxYAxis;
+ }
+
+ public int getTpsHistogramNumBins() {
+ return tpsHistogramNumBins;
+ }
+
+ public void setTpsHistogramNumBins(int tpsHistogramNumBins) {
+ this.tpsHistogramNumBins = tpsHistogramNumBins;
+ }
+
+ public int getTpsHistogramNumDecimalPoints() {
+ return tpsHistogramNumDecimalPoints;
+ }
+
+ public void setTpsHistogramNumDecimalPoints(int tpsHistogramNumDecimalPoints) {
+ this.tpsHistogramNumDecimalPoints = tpsHistogramNumDecimalPoints;
+ }
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/config/SyncControllerConfig.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/config/SyncControllerConfig.java
new file mode 100644
index 0000000..566c249
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/config/SyncControllerConfig.java
@@ -0,0 +1,305 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.sync.config;
+
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.List;
+import java.util.TimeZone;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.onap.aai.sparky.sync.SynchronizerConstants;
+
+public class SyncControllerConfig {
+
+ private static final String UNKNOWN_CONTROLLER_NAME = "UnknownControllerName";
+
+ private String controllerName;
+ private boolean enabled;
+ private int syncTaskDelayInMs;
+ private int syncTaskFrequencyInDays;
+
+ private int numSyncControllerWorkers;
+ private boolean runOnceSyncEnabled;
+ private boolean periodicSyncEnabled;
+
+ private String targetSyncStartTimeStamp;
+
+ private int numInternalSyncWorkers;
+ private int numSyncElasticWorkers;
+ private int numSyncActiveInventoryWorkers;
+
+ /*
+ * calculated variables based on incoming config
+ */
+ private String timeZoneOfSyncStartTimeStamp;
+ private int syncTaskStartTimeHr;
+ private int syncTaskStartTimeMin;
+ private int syncTaskStartTimeSec;
+
+
+
+ public SyncControllerConfig() {
+ controllerName = UNKNOWN_CONTROLLER_NAME;
+ enabled = false;
+ syncTaskDelayInMs = 0;
+ syncTaskFrequencyInDays = 365;
+ numSyncControllerWorkers = 1;
+ runOnceSyncEnabled = false;
+ periodicSyncEnabled = false;
+ targetSyncStartTimeStamp = SynchronizerConstants.DEFAULT_START_TIMESTAMP;
+ numInternalSyncWorkers = 2;
+ numSyncElasticWorkers = 5;
+ numSyncActiveInventoryWorkers = 5;
+ }
+
+ protected void initializeSyncTimeParameters() {
+
+ if (syncTaskDelayInMs < 0) {
+ throw new IllegalArgumentException("syncTaskDelayInMs must >= 0");
+ }
+
+ Pattern pattern = Pattern.compile(SynchronizerConstants.TIMESTAMP24HOURS_PATTERN);
+ Matcher matcher = pattern.matcher(targetSyncStartTimeStamp);
+ if (!matcher.matches()) {
+ throw new IllegalArgumentException("Invalid time format for targetSyncStartTimeStamp");
+ }
+
+ List<String> timestampVal = Arrays.asList(targetSyncStartTimeStamp.split(" "));
+
+ if (timestampVal.size() == SynchronizerConstants.COMPONENTS_IN_TIMESTAMP) {
+
+ // Need both time and timezone offset
+ timeZoneOfSyncStartTimeStamp = timestampVal
+ .get(SynchronizerConstants.IDX_TIMEZONE_IN_TIMESTAMP).replaceAll("UTC", "GMT");
+
+ String time = timestampVal.get(SynchronizerConstants.IDX_TIME_IN_TIMESTAMP);
+ DateFormat format = new SimpleDateFormat("HH:mm:ss");
+
+ Date date = null;
+
+ try {
+ date = format.parse(time);
+ } catch (ParseException parseException) {
+ throw new IllegalArgumentException(parseException);
+ }
+
+ Calendar calendar = Calendar.getInstance();
+ calendar.setTime(date);
+
+ syncTaskStartTimeHr = calendar.get(Calendar.HOUR_OF_DAY);
+ syncTaskStartTimeMin = calendar.get(Calendar.MINUTE);
+ syncTaskStartTimeSec = calendar.get(Calendar.SECOND);
+ } else {
+ throw new IllegalArgumentException("Invalid timestamp format from targetSyncStartTimeStamp");
+ }
+
+ }
+
+
+ public int getNumInternalSyncWorkers() {
+ return numInternalSyncWorkers;
+ }
+
+ public void setNumInternalSyncWorkers(int numInternalSyncWorkers) {
+ this.numInternalSyncWorkers = numInternalSyncWorkers;
+ }
+
+ public int getNumSyncElasticWorkers() {
+ return numSyncElasticWorkers;
+ }
+
+ public void setNumSyncElasticWorkers(int numSyncElasticWorkers) {
+ this.numSyncElasticWorkers = numSyncElasticWorkers;
+ }
+
+ public int getNumSyncActiveInventoryWorkers() {
+ return numSyncActiveInventoryWorkers;
+ }
+
+ public void setNumSyncActiveInventoryWorkers(int numSyncActiveInventoryWorkers) {
+ this.numSyncActiveInventoryWorkers = numSyncActiveInventoryWorkers;
+ }
+
+ public String getTargetSyncStartTimeStamp() {
+ return targetSyncStartTimeStamp;
+ }
+
+ public void setTargetSyncStartTimeStamp(String targetSyncStartTimeStamp) {
+ this.targetSyncStartTimeStamp = targetSyncStartTimeStamp;
+ initializeSyncTimeParameters();
+ }
+
+ public String getControllerName() {
+ return controllerName;
+ }
+
+ public void setControllerName(String controllerName) {
+ this.controllerName = controllerName;
+ }
+
+ public boolean isEnabled() {
+ return enabled;
+ }
+
+ public void setEnabled(boolean enabled) {
+ this.enabled = enabled;
+ }
+
+ public int getSyncTaskDelayInMs() {
+ return syncTaskDelayInMs;
+ }
+
+ public void setSyncTaskDelayInMs(int syncTaskDelayInMs) {
+ this.syncTaskDelayInMs = syncTaskDelayInMs;
+ }
+
+ public int getSyncTaskFrequencyInDays() {
+ return syncTaskFrequencyInDays;
+ }
+
+ public void setSyncTaskFrequencyInDays(int syncTaskFrequencyInDays) {
+ this.syncTaskFrequencyInDays = syncTaskFrequencyInDays;
+ }
+
+ public int getNumSyncControllerWorkers() {
+ return numSyncControllerWorkers;
+ }
+
+ public void setNumSyncControllerWorkers(int numSyncControllerWorkers) {
+ this.numSyncControllerWorkers = numSyncControllerWorkers;
+ }
+
+ public boolean isRunOnceSyncEnabled() {
+ return runOnceSyncEnabled;
+ }
+
+ public void setRunOnceSyncEnabled(boolean runOnceSyncEnabled) {
+ this.runOnceSyncEnabled = runOnceSyncEnabled;
+ }
+
+ public boolean isPeriodicSyncEnabled() {
+ return periodicSyncEnabled;
+ }
+
+ public void setPeriodicSyncEnabled(boolean periodicSyncEnabled) {
+ this.periodicSyncEnabled = periodicSyncEnabled;
+ }
+
+ public long getSyncFrequencyInMs() {
+
+ return (syncTaskFrequencyInDays * SynchronizerConstants.MILLISEC_IN_A_DAY);
+
+ }
+
+ public Calendar getTargetSyncTime() {
+
+ TimeZone tz = TimeZone.getTimeZone(timeZoneOfSyncStartTimeStamp);
+ Calendar targetSyncTime = Calendar.getInstance(tz);
+
+ targetSyncTime.set(Calendar.HOUR_OF_DAY, syncTaskStartTimeHr);
+ targetSyncTime.set(Calendar.MINUTE, syncTaskStartTimeMin);
+ targetSyncTime.set(Calendar.SECOND, syncTaskStartTimeSec);
+
+ return targetSyncTime;
+
+ }
+
+
+ public String getNextSyncTime() {
+
+ int taskFrequencyInSeconds = 0;
+ if (getSyncFrequencyInMs() > 0) {
+ taskFrequencyInSeconds = (int) (getSyncFrequencyInMs() / 1000);
+ }
+
+ if (taskFrequencyInSeconds < 86400) {
+
+ TimeZone tz = TimeZone.getTimeZone(timeZoneOfSyncStartTimeStamp);
+ Calendar targetSyncTime = Calendar.getInstance(tz);
+ targetSyncTime.add(Calendar.SECOND, taskFrequencyInSeconds);
+
+ return SynchronizerConstants.SIMPLE_DATE_FORMAT.format(targetSyncTime.getTimeInMillis())
+ .replaceAll(SynchronizerConstants.TIME_STD, SynchronizerConstants.TIME_CONFIG_STD);
+
+ } else {
+
+ return SynchronizerConstants.SIMPLE_DATE_FORMAT
+ .format(getNextSyncTime(getTargetSyncTime(), taskFrequencyInSeconds))
+ .replaceAll(SynchronizerConstants.TIME_STD, SynchronizerConstants.TIME_CONFIG_STD);
+
+ }
+
+ }
+
+ public long getNextSyncTime(Calendar syncTime, int taskFrequencyInSeconds) {
+
+ TimeZone tz = TimeZone.getTimeZone(timeZoneOfSyncStartTimeStamp);
+ Calendar timeNow = Calendar.getInstance(tz);
+
+ return getNextSyncTime(syncTime, timeNow.getTimeInMillis(), taskFrequencyInSeconds);
+ }
+
+ /**
+ * Gets the first sync time.
+ *
+ * @param calendar the calendar
+ * @param timeNow the time now in ms
+ * @param taskFrequencyInMs task period in ms
+ * @return the first sync time
+ */
+
+ public long getNextSyncTime(Calendar syncTime, long timeNowInMs, int taskFrequencyInSeconds) {
+ if (taskFrequencyInSeconds == 0) {
+ return 0;
+ } else if (timeNowInMs > syncTime.getTimeInMillis()) {
+
+ /*
+ * If current time is after the scheduled sync start time, then we'll skip ahead to the next
+ * sync time period
+ */
+
+ syncTime.add(Calendar.SECOND, taskFrequencyInSeconds);
+ }
+
+ return syncTime.getTimeInMillis();
+ }
+
+ public String getTimeZoneOfSyncStartTimeStamp() {
+ return timeZoneOfSyncStartTimeStamp;
+ }
+
+ public void setTimeZoneOfSyncStartTimeStamp(String timeZoneOfSyncStartTimeStamp) {
+ this.timeZoneOfSyncStartTimeStamp = timeZoneOfSyncStartTimeStamp;
+ }
+
+
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/entity/AggregationEntity.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/entity/AggregationEntity.java
new file mode 100644
index 0000000..30d4e71
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/entity/AggregationEntity.java
@@ -0,0 +1,99 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.sync.entity;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.onap.aai.sparky.util.NodeUtils;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+/**
+ * The Class AggregationEntity.
+ */
+public class AggregationEntity extends IndexableEntity implements IndexDocument {
+ private Map<String, String> attributes = new HashMap<String, String>();
+ protected ObjectMapper mapper = new ObjectMapper();
+
+ /**
+ * Instantiates a new aggregation entity.
+ */
+ public AggregationEntity() {
+ super();
+ }
+
+ /* (non-Javadoc)
+ * @see org.openecomp.sparky.synchronizer.entity.IndexDocument#deriveFields()
+ */
+ @Override
+ public void deriveFields() {
+
+ /*
+ * We'll try and create a unique identity key that we can use for differencing the previously
+ * imported record sets as we won't have granular control of what is created/removed and when.
+ * The best we can hope for is identification of resources by generated Id until the
+ * Identity-Service UUID is tagged against all resources, then we can use that instead.
+ */
+ this.id =
+ NodeUtils.generateUniqueShaDigest(link);
+ }
+
+ public void copyAttributeKeyValuePair(Map<String, Object> map){
+ for(String key: map.keySet()){
+ if (!key.equalsIgnoreCase("relationship-list")){ // ignore relationship data which is not required in aggregation
+ this.attributes.put(key, map.get(key).toString()); // not sure if entity attribute can contain an object as value
+ }
+ }
+ }
+
+ public void addAttributeKeyValuePair(String key, String value){
+ this.attributes.put(key, value);
+ }
+
+ @Override
+ public String getAsJson() {
+ ObjectNode rootNode = mapper.createObjectNode();
+ rootNode.put("link", this.getLink());
+ rootNode.put("lastmodTimestamp", this.getEntityTimeStamp());
+ for (String key: this.attributes.keySet()){
+ rootNode.put(key, this.attributes.get(key));
+ }
+ return rootNode.toString();
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ return "IndexDocument [" + (entityType != null ? "entityType=" + entityType + ", " : "")
+ + (entityPrimaryKeyValue != null ? "entityPrimaryKeyValue=" + entityPrimaryKeyValue + ", "
+ : "")
+ + (mapper != null ? "mapper=" + mapper + ", " : "") + (id != null ? "id=" + id + ", " : "")
+ + (lastmodTimestamp != null ? "lastmodTimestamp=" + lastmodTimestamp + ", " : "") + "]";
+ }
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/entity/AggregationSuggestionEntity.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/entity/AggregationSuggestionEntity.java
new file mode 100644
index 0000000..06f60b3
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/entity/AggregationSuggestionEntity.java
@@ -0,0 +1,111 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.sync.entity;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.json.JSONArray;
+import org.json.JSONObject;
+import org.onap.aai.sparky.search.filters.config.FiltersConfig;
+import org.onap.aai.sparky.search.filters.config.UiFilterListItemConfig;
+import org.onap.aai.sparky.search.filters.config.UiViewListItemConfig;
+import org.onap.aai.sparky.util.NodeUtils;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+public class AggregationSuggestionEntity extends IndexableEntity implements IndexDocument {
+
+ private static final String FILTER_ID = "filterId";
+ private static final String FILTER_LIST = "filterList";
+
+ private List<String> inputs = new ArrayList<>();
+ private final String outputString = "VNFs";
+ protected ObjectMapper mapper = new ObjectMapper();
+ List<String> filterIds = new ArrayList<>();
+
+ @JsonIgnore
+ private FiltersConfig filtersConfig;
+
+ public AggregationSuggestionEntity(FiltersConfig filtersConfig) {
+ super();
+ this.filtersConfig = filtersConfig;
+ inputs.add("VNFs");
+ inputs.add("generic-vnfs");
+ }
+
+ @Override
+ public void deriveFields() {
+ this.id = NodeUtils.generateUniqueShaDigest(this.outputString);
+ }
+
+ @Override
+ public String getAsJson() {
+ JSONArray inputArray = new JSONArray();
+ for (String input: inputs) {
+ input = input.replace(",","" );
+ input = input.replace("[","" );
+ input = input.replace("]","" );
+ inputArray.put(input);
+ }
+
+ JSONObject entitySuggest = new JSONObject();
+ entitySuggest.put("input", inputArray);
+ entitySuggest.put("output", this.outputString);
+ entitySuggest.put("weight", 100);
+
+ JSONArray payloadFilters = new JSONArray();
+
+ for (String filterId : filterIds) {
+ JSONObject filterPayload = new JSONObject();
+ filterPayload.put(FILTER_ID, filterId);
+ payloadFilters.put(filterPayload);
+ }
+
+ JSONObject payloadNode = new JSONObject();
+ payloadNode.put(FILTER_LIST, payloadFilters);
+ entitySuggest.put("payload", payloadNode);
+
+ JSONObject rootNode = new JSONObject();
+ rootNode.put("entity_suggest", entitySuggest);
+
+ return rootNode.toString();
+ }
+
+ public void initializeFilters() {
+ for (UiViewListItemConfig view : filtersConfig.getViewsConfig().getViews()) {
+ if (view.getViewName().equals("vnfSearch")) {
+ for (UiFilterListItemConfig currentViewFilter : view.getFilters()) {
+ filterIds.add(currentViewFilter.getFilterId());
+ }
+ }
+ }
+ }
+
+ public void setFilterIds(List<String> filterIds) {
+ this.filterIds = filterIds;
+ }
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/entity/IndexDocument.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/entity/IndexDocument.java
new file mode 100644
index 0000000..6ee3351
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/entity/IndexDocument.java
@@ -0,0 +1,41 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.sync.entity;
+
+/**
+ * The Interface IndexDocument.
+ */
+public interface IndexDocument {
+
+ /**
+ * Derive fields.
+ */
+ public void deriveFields();
+
+ public String getId();
+
+ public String getAsJson() throws Exception;
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/entity/IndexableCrossEntityReference.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/entity/IndexableCrossEntityReference.java
new file mode 100644
index 0000000..0c94227
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/entity/IndexableCrossEntityReference.java
@@ -0,0 +1,97 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.sync.entity;
+
+import java.util.ArrayList;
+
+import org.onap.aai.sparky.util.NodeUtils;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.core.JsonProcessingException;
+
+
+/**
+ * The Class IndexableCrossEntityReference.
+ */
+
+public class IndexableCrossEntityReference extends IndexableEntity implements IndexDocument {
+
+ protected String crossReferenceEntityValues;
+ protected ArrayList<String> crossEntityReferenceCollection = new ArrayList<String>();
+
+ /**
+ * Instantiates a new indexable cross entity reference.
+ */
+ public IndexableCrossEntityReference() {
+ super();
+ }
+
+ /**
+ * Adds the cross entity reference value.
+ *
+ * @param crossEntityReferenceValue the cross entity reference value
+ */
+ public void addCrossEntityReferenceValue(String crossEntityReferenceValue) {
+ if (!crossEntityReferenceCollection.contains(crossEntityReferenceValue)) {
+ crossEntityReferenceCollection.add(crossEntityReferenceValue);
+ }
+ }
+
+ public String getCrossReferenceEntityValues() {
+ return crossReferenceEntityValues;
+ }
+
+ public void setCrossReferenceEntityValues(String crossReferenceEntityValues) {
+ this.crossReferenceEntityValues = crossReferenceEntityValues;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.openecomp.sparky.synchronizer.entity.IndexDocument#deriveFields()
+ */
+ @Override
+ public void deriveFields() {
+ this.id = NodeUtils.generateUniqueShaDigest(link);
+ this.crossReferenceEntityValues = NodeUtils.concatArray(crossEntityReferenceCollection, ";");
+ }
+
+ @JsonIgnore // Since this is a "get" we need to JSON ignore otherwise it will be called when converting to JSON
+ @Override
+ public String getAsJson() throws JsonProcessingException {
+
+ return NodeUtils.convertObjectToJson(this, false);
+
+ }
+
+ @Override
+ public String toString() {
+ return "IndexableCrossEntityReference ["
+ + (crossReferenceEntityValues != null
+ ? "crossReferenceEntityValues=" + crossReferenceEntityValues + ", " : "")
+ + (crossEntityReferenceCollection != null
+ ? "crossEntityReferenceCollection=" + crossEntityReferenceCollection + ", " : "");
+ }
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/entity/IndexableEntity.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/entity/IndexableEntity.java
new file mode 100644
index 0000000..9a7f865
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/entity/IndexableEntity.java
@@ -0,0 +1,100 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.sync.entity;
+
+import java.sql.Timestamp;
+import java.text.SimpleDateFormat;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+/**
+ * The Class IndexableEntity.
+ */
+public abstract class IndexableEntity {
+ protected String id; // generated, SHA-256 digest
+ protected String entityType;
+ protected String entityPrimaryKeyValue;
+ protected String lastmodTimestamp;
+ protected String link;
+
+ private static final String TIMESTAMP_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSSZ";
+
+ /**
+ * Instantiates a new indexable entity.
+ */
+ public IndexableEntity() {
+ SimpleDateFormat dateFormat = new SimpleDateFormat(TIMESTAMP_FORMAT);
+ Timestamp timestamp = new Timestamp(System.currentTimeMillis());
+ String currentFormattedTimeStamp = dateFormat.format(timestamp);
+ this.setEntityTimeStamp(currentFormattedTimeStamp);
+ }
+
+ @JsonIgnore
+ public String getId() {
+ return id;
+ }
+
+ @JsonProperty("entityType")
+ public String getEntityType() {
+ return entityType;
+ }
+
+ @JsonProperty("entityPrimaryKeyValue")
+ public String getEntityPrimaryKeyValue() {
+ return entityPrimaryKeyValue;
+ }
+
+ @JsonProperty("lastmodTimestamp")
+ public String getEntityTimeStamp() {
+ return lastmodTimestamp;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public void setEntityType(String entityType) {
+ this.entityType = entityType;
+ }
+
+ public void setEntityPrimaryKeyValue(String fieldValue) {
+ this.entityPrimaryKeyValue = fieldValue;
+ }
+
+ public void setEntityTimeStamp(String lastmodTimestamp) {
+ this.lastmodTimestamp = lastmodTimestamp;
+ }
+
+ @JsonProperty("link")
+ public String getLink() {
+ return link;
+ }
+
+ public void setLink(String link) {
+ this.link = link;
+ }
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/entity/MergableEntity.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/entity/MergableEntity.java
new file mode 100644
index 0000000..82c874a
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/entity/MergableEntity.java
@@ -0,0 +1,59 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.sync.entity;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import com.fasterxml.jackson.annotation.JsonAnyGetter;
+import com.fasterxml.jackson.annotation.JsonAnySetter;
+
+/**
+ * The Class MergableEntity.
+ */
+public class MergableEntity {
+ private Map<String, String> other = new HashMap<String, String>();
+
+ /**
+ * Any.
+ *
+ * @return the map
+ */
+ @JsonAnyGetter
+ public Map<String, String> any() {
+ return other;
+ }
+
+ /**
+ * Sets the.
+ *
+ * @param name the name
+ * @param value the value
+ */
+ @JsonAnySetter
+ public void set(String name, String value) {
+ other.put(name, value);
+ }
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/entity/ObjectIdCollection.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/entity/ObjectIdCollection.java
new file mode 100644
index 0000000..8462bc9
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/entity/ObjectIdCollection.java
@@ -0,0 +1,78 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.sync.entity;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * The Class ObjectIdCollection.
+ */
+public class ObjectIdCollection {
+
+ protected ConcurrentHashMap<String, String> importedObjectIds =
+ new ConcurrentHashMap<String, String>();
+
+ public Collection<String> getImportedObjectIds() {
+ return importedObjectIds.values();
+ }
+
+ /**
+ * Adds the object id.
+ *
+ * @param id the id
+ */
+ public void addObjectId(String id) {
+ importedObjectIds.putIfAbsent(id, id);
+ }
+
+ public int getSize() {
+ return importedObjectIds.values().size();
+ }
+
+ /**
+ * Adds the all.
+ *
+ * @param items the items
+ */
+ public void addAll(List<String> items) {
+ if (items == null) {
+ return;
+ }
+
+ items.stream().forEach((item) -> {
+ importedObjectIds.putIfAbsent(item, item);
+ });
+
+ }
+
+ /**
+ * Clear.
+ */
+ public void clear() {
+ importedObjectIds.clear();
+ }
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/entity/SearchableEntity.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/entity/SearchableEntity.java
new file mode 100644
index 0000000..84fc093
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/entity/SearchableEntity.java
@@ -0,0 +1,142 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.sync.entity;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.onap.aai.sparky.util.NodeUtils;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+/**
+ * The Class SearchableEntity.
+ */
+public class SearchableEntity extends IndexableEntity implements IndexDocument {
+
+ @JsonIgnore
+ protected List<String> searchTagCollection = new ArrayList<String>();
+
+ @JsonIgnore
+ protected List<String> searchTagIdCollection = new ArrayList<String>();
+
+ @JsonIgnore
+ protected ObjectMapper mapper = new ObjectMapper();
+
+ /**
+ * Instantiates a new searchable entity.
+ */
+ public SearchableEntity() {
+ super();
+ }
+
+ /*
+ * Generated fields, leave the settings for junit overrides
+ */
+
+ protected String searchTags; // generated based on searchTagCollection values
+
+ protected String searchTagIDs;
+
+ /**
+ * Generates the sha based id.
+ */
+ public void generateId() {
+ this.id = NodeUtils.generateUniqueShaDigest(link);
+ }
+
+ /* (non-Javadoc)
+ * @see org.openecomp.sparky.synchronizer.entity.IndexDocument#deriveFields()
+ */
+ @Override
+ public void deriveFields() {
+
+ /*
+ * We'll try and create a unique identity key that we can use for differencing the previously
+ * imported record sets as we won't have granular control of what is created/removed and when.
+ * The best we can hope for is identification of resources by generated Id until the
+ * Identity-Service UUID is tagged against all resources, then we can use that instead.
+ */
+ generateId();
+ this.searchTags = NodeUtils.concatArray(searchTagCollection, ";");
+ this.searchTagIDs = NodeUtils.concatArray(this.searchTagIdCollection, ";");
+ }
+
+ /**
+ * Adds the search tag with key.
+ *
+ * @param searchTag the search tag
+ * @param searchTagKey the key associated with the search tag (key:value)
+ */
+ public void addSearchTagWithKey(String searchTag, String searchTagKey) {
+ searchTagIdCollection.add(searchTagKey);
+ searchTagCollection.add(searchTag);
+ }
+
+ public List<String> getSearchTagCollection() {
+ return searchTagCollection;
+ }
+
+ @JsonProperty("searchTags")
+ public String getSearchTags() {
+ return searchTags;
+ }
+
+ @JsonProperty("searchTagIDs")
+ public String getSearchTagIDs() {
+ return searchTagIDs;
+ }
+
+ @JsonIgnore
+ public List<String> getSearchTagIdCollection() {
+ return searchTagIdCollection;
+ }
+
+ @Override
+ @JsonIgnore
+ public String getAsJson() throws JsonProcessingException {
+ return NodeUtils.convertObjectToJson(this, false);
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ return "IndexDocument [" + (entityType != null ? "entityType=" + entityType + ", " : "")
+ + (entityPrimaryKeyValue != null ? "entityPrimaryKeyValue=" + entityPrimaryKeyValue + ", "
+ : "")
+ + (searchTagCollection != null ? "searchTagCollection=" + searchTagCollection + ", " : "")
+ + (searchTagIdCollection != null ? "searchTagIDCollection=" + searchTagIdCollection + ", "
+ : "")
+ + (mapper != null ? "mapper=" + mapper + ", " : "") + (id != null ? "id=" + id + ", " : "")
+ + (lastmodTimestamp != null ? "lastmodTimestamp=" + lastmodTimestamp + ", " : "")
+ + (searchTags != null ? "searchTags=" + searchTags + ", " : "")
+ + (searchTagIDs != null ? "searchTagIDs=" + searchTagIDs : "") + "]";
+ }
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/entity/SelfLinkDescriptor.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/entity/SelfLinkDescriptor.java
new file mode 100644
index 0000000..2b3f858
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/entity/SelfLinkDescriptor.java
@@ -0,0 +1,90 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.sync.entity;
+
+/**
+ * The Class SelfLinkDescriptor.
+ */
+public class SelfLinkDescriptor {
+ private String selfLink;
+ private String entityType;
+ private String depthModifier;
+
+ public String getDepthModifier() {
+ return depthModifier;
+ }
+
+ public void setDepthModifier(String depthModifier) {
+ this.depthModifier = depthModifier;
+ }
+
+ public String getSelfLink() {
+ return selfLink;
+ }
+
+ public void setSelfLink(String selfLink) {
+ this.selfLink = selfLink;
+ }
+
+ public String getEntityType() {
+ return entityType;
+ }
+
+ public void setEntityType(String entityType) {
+ this.entityType = entityType;
+ }
+
+ public SelfLinkDescriptor(String selfLink) {
+ this(selfLink, null, null);
+ }
+
+ /**
+ * Instantiates a new self link descriptor.
+ *
+ * @param selfLink the self link
+ * @param entityType the entity type
+ */
+ public SelfLinkDescriptor(String selfLink, String entityType) {
+ this(selfLink, null, entityType);
+ }
+
+ public SelfLinkDescriptor(String selfLink, String depthModifier, String entityType) {
+ this.selfLink = selfLink;
+ this.entityType = entityType;
+ this.depthModifier = depthModifier;
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ return "SelfLinkDescriptor [" + (selfLink != null ? "selfLink=" + selfLink + ", " : "")
+ + (entityType != null ? "entityType=" + entityType + ", " : "")
+ + (depthModifier != null ? "depthModifier=" + depthModifier : "") + "]";
+ }
+
+}
+
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/entity/SuggestionSearchEntity.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/entity/SuggestionSearchEntity.java
new file mode 100644
index 0000000..3648b53
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/entity/SuggestionSearchEntity.java
@@ -0,0 +1,327 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.sync.entity;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.json.JSONArray;
+import org.json.JSONObject;
+import org.onap.aai.sparky.config.oxm.SuggestionEntityLookup;
+import org.onap.aai.sparky.search.filters.config.FiltersConfig;
+import org.onap.aai.sparky.search.filters.config.FiltersDetailsConfig;
+import org.onap.aai.sparky.search.filters.config.UiFilterConfig;
+import org.onap.aai.sparky.util.NodeUtils;
+import org.onap.aai.sparky.util.SuggestionsPermutation;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+public class SuggestionSearchEntity extends IndexableEntity implements IndexDocument {
+ private static final String FILTER_ID = "filterId";
+ private static final String FILTER_VALUE = "filterValue";
+ private static final String FILTER_LIST = "filterList";
+
+ private String entityType;
+ private List<String> suggestionConnectorWords = new ArrayList<String>();
+ private List<String> suggestionAttributeTypes = new ArrayList<String>();
+ private List<String> suggestionAttributeValues = new ArrayList<String>();
+ private List<String> suggestionTypeAliases = new ArrayList<String>();
+ private List<String> suggestionInputPermutations = new ArrayList<String>();
+ private List<String> suggestableAttr = new ArrayList<String>();
+
+ private Map<String, String> inputOutputData = new HashMap<String, String>();
+ Map<String, UiFilterConfig> filters = new HashMap<String, UiFilterConfig>();
+ private JSONObject payload = new JSONObject();
+ private JSONArray payloadFilters = new JSONArray();
+ private StringBuffer outputString = new StringBuffer();
+ private String aliasToUse;
+
+ private SuggestionEntityLookup entityLookup;
+
+ public JSONObject getPayload() {
+ return payload;
+ }
+
+ public void setPayload(JSONObject payload) {
+ this.payload = payload;
+ }
+
+ protected ObjectMapper mapper = new ObjectMapper();
+
+ public SuggestionSearchEntity(FiltersConfig filtersConfig) {
+ super();
+
+ FiltersDetailsConfig filterConfigList = filtersConfig.getFiltersConfig();
+ // Populate the map with keys that will match the suggestableAttr values
+ for(UiFilterConfig filter : filterConfigList.getFilters()) {
+ if(filter.getDataSource() != null) {
+ filters.put(filter.getDataSource().getFieldName(), filter);
+ }
+ }
+ }
+
+ public SuggestionSearchEntity(FiltersConfig filtersConfig, SuggestionEntityLookup entityLookup) {
+
+ this.entityLookup = entityLookup;
+
+ FiltersDetailsConfig filterConfigList = filtersConfig.getFiltersConfig();
+ // Populate the map with keys that will match the suggestableAttr values
+ for(UiFilterConfig filter : filterConfigList.getFilters()) {
+ if(filter.getDataSource() != null) {
+ filters.put(filter.getDataSource().getFieldName(), filter);
+ }
+ }
+ }
+
+ public SuggestionSearchEntity(SuggestionEntityLookup entityLookup, FiltersConfig config) {
+
+ FiltersDetailsConfig filterConfigList = config.getFiltersConfig();
+ // Populate the map with keys that will match the suggestableAttr values
+ for(UiFilterConfig filter : filterConfigList.getFilters()) {
+ if(filter.getDataSource() != null) {
+ filters.put(filter.getDataSource().getFieldName(), filter);
+ }
+ }
+ }
+
+ public void setSuggestableAttr(ArrayList<String> attributes) {
+ for (String attribute : attributes) {
+ this.suggestableAttr.add(attribute);
+ }
+ }
+
+ public void setPayloadFromResponse(JsonNode node) {
+ if (suggestableAttr != null) {
+ JSONObject nodePayload = new JSONObject();
+ for (String attribute : suggestableAttr) {
+ if (node.get(attribute) != null) {
+ inputOutputData.put(attribute, node.get(attribute).asText());
+ this.payload.put(attribute, node.get(attribute).asText());
+ }
+ }
+ }
+ }
+
+ public void setFilterBasedPayloadFromResponse(JsonNode node, String entityName, ArrayList<String> uniqueList) {
+
+ HashMap<String, String> desc = entityLookup.getSuggestionSearchEntityOxmModel().get(entityName);
+
+ if ( desc == null ) {
+ return;
+ }
+
+ String attr = desc.get("suggestibleAttributes");
+
+ if ( attr == null ) {
+ return;
+ }
+
+ List<String> suggestableAttrOxm = Arrays.asList(attr.split(","));
+
+ /*
+ * Note:
+ * (1) 'uniqueList' is one item within the power set of the suggestable attributes.
+ * (2) 'inputeOutputData' is used to generate permutations of strings
+ */
+ for (String selectiveAttr: uniqueList) {
+ if (node.get(selectiveAttr) != null) {
+ inputOutputData.put(selectiveAttr, node.get(selectiveAttr).asText());
+ }
+ }
+
+ if (suggestableAttrOxm != null) {
+ for (String attribute : suggestableAttrOxm) {
+ if (node.get(attribute) != null && uniqueList.contains(attribute)) {
+ UiFilterConfig filterConfig = filters.get(attribute);
+ if(filterConfig != null) {
+ JSONObject filterPayload = new JSONObject();
+ filterPayload.put(FILTER_ID, filterConfig.getFilterId());
+ filterPayload.put(FILTER_VALUE, node.get(attribute).asText());
+ this.payloadFilters.put(filterPayload);
+ } else {
+ this.payload.put(attribute, node.get(attribute).asText());
+ }
+ } else {
+ UiFilterConfig emptyValueFilterConfig = filters.get(attribute);
+ if(emptyValueFilterConfig != null) {
+ JSONObject emptyValueFilterPayload = new JSONObject();
+ emptyValueFilterPayload.put(FILTER_ID, emptyValueFilterConfig.getFilterId());
+ this.payloadFilters.put(emptyValueFilterPayload);
+ }
+ }
+ }
+ this.payload.put(FILTER_LIST, this.payloadFilters);
+ }
+ }
+
+ @Override
+ public String getEntityType() {
+ return entityType;
+ }
+
+ @Override
+ public void setEntityType(String entityType) {
+ this.entityType = entityType;
+ }
+
+ public List<String> getSuggestionConnectorWords() {
+ return suggestionConnectorWords;
+ }
+
+ public void setSuggestionConnectorWords(List<String> suggestionConnectorWords) {
+ this.suggestionConnectorWords = suggestionConnectorWords;
+ }
+
+ public List<String> getSuggestionPropertyTypes() {
+ return this.suggestionAttributeTypes;
+ }
+
+ public void setSuggestionPropertyTypes(List<String> suggestionPropertyTypes) {
+ this.suggestionAttributeTypes = suggestionPropertyTypes;
+ }
+
+ public List<String> getSuggestionAttributeValues() {
+ return this.suggestionAttributeValues;
+ }
+
+ public void setSuggestionAttributeValues(List<String> suggestionAttributeValues) {
+ this.suggestionAttributeValues = suggestionAttributeValues;
+ }
+
+ public List<String> getSuggestionAliases() {
+ return this.suggestionTypeAliases;
+ }
+
+ public void setSuggestionAliases(List<String> suggestionAliases) {
+ this.suggestionTypeAliases = suggestionAliases;
+ }
+
+ public List<String> getSuggestionInputPermutations() {
+ return this.suggestionInputPermutations;
+ }
+
+ public void setSuggestionInputPermutations(List<String> permutations) {
+ this.suggestionInputPermutations = permutations;
+ }
+
+ public void generateSuggestionInputPermutations() {
+
+ List<String> entityNames = new ArrayList<>();
+ entityNames.add(entityType);
+ HashMap<String, String> desc = entityLookup.getSuggestionSearchEntityOxmModel().get(this.entityType);
+ String attr = desc.get("suggestionAliases");
+ String[] suggestionAliasesArray = attr.split(",");
+ suggestionTypeAliases = Arrays.asList(suggestionAliasesArray);
+ this.setAliasToUse(suggestionAliasesArray[suggestionAliasesArray.length - 1]);
+ for (String alias : suggestionTypeAliases) {
+ entityNames.add(alias);
+ }
+
+ ArrayList<String> listToPermutate = new ArrayList<>(inputOutputData.values());
+
+ for (String entity : entityNames){
+ listToPermutate.add(entity); // add entity-name or alias in list to permutate
+ List<List<String>> lists = SuggestionsPermutation.getListPermutations(listToPermutate);
+ for (List<String> li : lists){
+ suggestionInputPermutations.add(String.join(" ", li));
+ }
+ // prepare for the next pass: remove the entity-name or alias from the list
+ listToPermutate.remove(entity);
+ }
+ }
+
+ public boolean isSuggestableDoc() {
+ return this.getPayload().length() != 0;
+ }
+
+
+ @Override
+ public void deriveFields() {
+
+ int entryCounter = 1;
+ for (Map.Entry<String, String> outputValue : inputOutputData.entrySet()) {
+ if (outputValue.getValue() != null && outputValue.getValue().length() > 0) {
+ this.outputString.append(outputValue.getValue());
+ if (entryCounter < inputOutputData.entrySet().size()) {
+ this.outputString.append(" and ");
+ } else{
+ this.outputString.append(" ");
+ }
+ }
+ entryCounter++;
+ }
+
+ this.outputString.append(this.getAliasToUse());
+ this.id = NodeUtils.generateUniqueShaDigest(outputString.toString());
+ }
+
+ @Override
+ public String getAsJson() {
+ // TODO Auto-generated method stub
+ JSONObject rootNode = new JSONObject();
+
+ JSONArray suggestionsArray = new JSONArray();
+ for (String suggestion : suggestionInputPermutations) {
+ suggestionsArray.put(suggestion);
+ }
+
+ JSONObject entitySuggest = new JSONObject();
+
+ entitySuggest.put("input", suggestionsArray);
+ entitySuggest.put("output", this.outputString);
+ entitySuggest.put("payload", this.payload);
+ rootNode.put("entity_suggest", entitySuggest);
+
+ return rootNode.toString();
+ }
+
+ public String getAliasToUse() {
+ return aliasToUse;
+ }
+
+ public void setAliasToUse(String aliasToUse) {
+ this.aliasToUse = aliasToUse;
+ }
+
+ public Map<String, String> getInputOutputData() {
+ return inputOutputData;
+ }
+
+ public void setInputOutputData(Map<String, String> inputOutputData) {
+ this.inputOutputData = inputOutputData;
+ }
+
+ @Override
+ public String toString() {
+ return "SuggestionSearchEntity [entityType=" + entityType + ", suggestionConnectorWords="
+ + suggestionConnectorWords + ", suggestionAttributeTypes=" + suggestionAttributeTypes
+ + ", suggestionAttributeValues=" + suggestionAttributeValues + ", suggestionTypeAliases="
+ + suggestionTypeAliases + ", mapper=" + mapper + "]";
+ }
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/entity/TransactionStorageType.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/entity/TransactionStorageType.java
new file mode 100644
index 0000000..52ea891
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/entity/TransactionStorageType.java
@@ -0,0 +1,56 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.sync.entity;
+
+/**
+ * The Enum TransactionStorageType.
+ */
+public enum TransactionStorageType {
+ EDGE_TAG_QUERY(0, "aaiOffline/edge-tag-query"), ACTIVE_INVENTORY_QUERY(1,
+ "aaiOffline/active-inventory-query");
+
+ private Integer index;
+ private String outputFolder;
+
+ /**
+ * Instantiates a new transaction storage type.
+ *
+ * @param index the index
+ * @param outputFolder the output folder
+ */
+ TransactionStorageType(Integer index, String outputFolder) {
+ this.index = index;
+ this.outputFolder = outputFolder;
+ }
+
+ public Integer getIndex() {
+ return index;
+ }
+
+ public String getOutputFolder() {
+ return outputFolder;
+ }
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/enumeration/OperationState.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/enumeration/OperationState.java
new file mode 100644
index 0000000..b8c12c9
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/enumeration/OperationState.java
@@ -0,0 +1,32 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.sync.enumeration;
+
+/**
+ * The Enum OperationState.
+ */
+public enum OperationState {
+ INIT, OK, ERROR, ABORT, PENDING, IGNORED_SYNC_NOT_IDLE
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/enumeration/SynchronizerState.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/enumeration/SynchronizerState.java
new file mode 100644
index 0000000..01b28e0
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/enumeration/SynchronizerState.java
@@ -0,0 +1,32 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.sync.enumeration;
+
+/**
+ * The Enum SynchronizerState.
+ */
+public enum SynchronizerState {
+ IDLE, PERFORMING_SYNCHRONIZATION, ABORTED
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/task/PerformActiveInventoryRetrieval.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/task/PerformActiveInventoryRetrieval.java
new file mode 100644
index 0000000..a986dfc
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/task/PerformActiveInventoryRetrieval.java
@@ -0,0 +1,97 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.sync.task;
+
+import java.util.Map;
+import java.util.function.Supplier;
+
+import org.onap.aai.cl.api.Logger;
+import org.onap.aai.cl.eelf.LoggerFactory;
+import org.onap.aai.restclient.client.OperationResult;
+import org.onap.aai.sparky.dal.ActiveInventoryAdapter;
+import org.onap.aai.sparky.dal.NetworkTransaction;
+import org.onap.aai.sparky.logging.AaiUiMsgs;
+import org.slf4j.MDC;
+
+/*
+ * Consider abstraction the tasks into common elemnts, because most of them repeat a generic call
+ * flow pattern
+ */
+
+/**
+ * The Class PerformActiveInventoryRetrieval.
+ */
+public class PerformActiveInventoryRetrieval implements Supplier<NetworkTransaction> {
+
+ private static Logger logger = LoggerFactory.getInstance().getLogger(PerformActiveInventoryRetrieval.class);
+
+ private NetworkTransaction txn;
+ private ActiveInventoryAdapter aaiAdapter;
+ private Map<String, String> contextMap;
+
+ /**
+ * Instantiates a new perform active inventory retrieval.
+ *
+ * @param txn the txn
+ * @param aaiProvider the aai provider
+ */
+ public PerformActiveInventoryRetrieval(NetworkTransaction txn,
+ ActiveInventoryAdapter aaiAdapter) {
+ this.txn = txn;
+ this.aaiAdapter = aaiAdapter;
+ this.contextMap = MDC.getCopyOfContextMap();
+ }
+
+ /* (non-Javadoc)
+ * @see java.util.function.Supplier#get()
+ */
+ @Override
+ public NetworkTransaction get() {
+
+ txn.setTaskAgeInMs();
+
+ long startTimeInMs = System.currentTimeMillis();
+ MDC.setContextMap(contextMap);
+ OperationResult result = null;
+ try {
+
+ final String absoluteSelfLink = aaiAdapter.repairSelfLink(txn.getLink(), txn.getQueryParameters());
+ result = aaiAdapter.queryActiveInventoryWithRetries(absoluteSelfLink, "application/json", 5);
+ } catch (Exception exc) {
+ logger.error(AaiUiMsgs.ERROR_GENERIC,"Failure to resolve self link from AAI. Error = " + exc.getMessage());
+ result = new OperationResult(500,
+ "Caught an exception while trying to resolve link = " + exc.getMessage());
+ } finally {
+ txn.setOperationResult(result);
+ txn.setOpTimeInMs(System.currentTimeMillis() - startTimeInMs);
+ }
+
+ return txn;
+ }
+
+ protected void setContextMap(Map<String, String> contextMap) {
+ this.contextMap = contextMap;
+ }
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/task/PerformElasticSearchPut.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/task/PerformElasticSearchPut.java
new file mode 100644
index 0000000..cbc9ccb
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/task/PerformElasticSearchPut.java
@@ -0,0 +1,90 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.sync.task;
+
+import java.util.Map;
+import java.util.function.Supplier;
+
+import javax.ws.rs.core.MediaType;
+
+import org.onap.aai.restclient.client.OperationResult;
+import org.onap.aai.sparky.dal.ElasticSearchAdapter;
+import org.onap.aai.sparky.dal.NetworkTransaction;
+import org.slf4j.MDC;
+
+/**
+ * The Class PerformElasticSearchPut.
+ */
+public class PerformElasticSearchPut implements Supplier<NetworkTransaction> {
+
+ private ElasticSearchAdapter esAdapter;
+ private String jsonPayload;
+ private NetworkTransaction txn;
+ private Map<String, String> contextMap;
+
+ /**
+ * Instantiates a new perform elastic search put.
+ *
+ * @param jsonPayload the json payload
+ * @param txn the txn
+ * @param restDataProvider the rest data provider
+ */
+ public PerformElasticSearchPut(String jsonPayload, NetworkTransaction txn,
+ ElasticSearchAdapter esAdapter) {
+ this.jsonPayload = jsonPayload;
+ this.txn = txn;
+ this.esAdapter = esAdapter;
+ this.contextMap = MDC.getCopyOfContextMap();
+ }
+
+ public PerformElasticSearchPut(String jsonPayload, NetworkTransaction txn,
+ ElasticSearchAdapter esAdapter, Map<String, String> contextMap) {
+ this.jsonPayload = jsonPayload;
+ this.txn = txn;
+ this.esAdapter = esAdapter;
+ this.contextMap = contextMap;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.util.function.Supplier#get()
+ */
+ @Override
+ public NetworkTransaction get() {
+ txn.setTaskAgeInMs();
+ MDC.setContextMap(contextMap);
+
+ long startTimeInMs = System.currentTimeMillis();
+
+ OperationResult or =
+ esAdapter.doPut(txn.getLink(), jsonPayload, MediaType.APPLICATION_JSON_TYPE);
+
+ txn.setOperationResult(or);
+ txn.setOpTimeInMs(System.currentTimeMillis() - startTimeInMs);
+
+ return txn;
+ }
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/task/PerformElasticSearchRetrieval.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/task/PerformElasticSearchRetrieval.java
new file mode 100644
index 0000000..048d19e
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/task/PerformElasticSearchRetrieval.java
@@ -0,0 +1,72 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.sync.task;
+
+import java.util.Map;
+import java.util.function.Supplier;
+
+import javax.ws.rs.core.MediaType;
+
+import org.onap.aai.restclient.client.OperationResult;
+import org.onap.aai.sparky.dal.ElasticSearchAdapter;
+import org.onap.aai.sparky.dal.NetworkTransaction;
+import org.slf4j.MDC;
+
+/**
+ * The Class PerformElasticSearchRetrieval.
+ */
+public class PerformElasticSearchRetrieval implements Supplier<NetworkTransaction> {
+
+ private NetworkTransaction txn;
+ private ElasticSearchAdapter esAdapter;
+ private Map<String, String> contextMap;
+
+ /**
+ * Instantiates a new perform elastic search retrieval.
+ *
+ * @param elasticSearchTxn the elastic search txn
+ * @param restDataProvider the rest data provider
+ */
+ public PerformElasticSearchRetrieval(NetworkTransaction elasticSearchTxn,
+ ElasticSearchAdapter esAdapter) {
+ this.txn = elasticSearchTxn;
+ this.esAdapter = esAdapter;
+ this.contextMap = MDC.getCopyOfContextMap();
+ }
+
+ /* (non-Javadoc)
+ * @see java.util.function.Supplier#get()
+ */
+ @Override
+ public NetworkTransaction get() {
+ MDC.setContextMap(contextMap);
+ long startTimeInMs = System.currentTimeMillis();
+ OperationResult or = esAdapter.doGet(txn.getLink(), MediaType.APPLICATION_JSON_TYPE);
+ txn.setOperationResult(or);
+ txn.setOpTimeInMs(System.currentTimeMillis() - startTimeInMs);
+ return txn;
+ }
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/task/PerformElasticSearchUpdate.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/task/PerformElasticSearchUpdate.java
new file mode 100644
index 0000000..2e329e5
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/task/PerformElasticSearchUpdate.java
@@ -0,0 +1,82 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.sync.task;
+
+import java.util.Map;
+import java.util.function.Supplier;
+
+import org.onap.aai.restclient.client.OperationResult;
+import org.onap.aai.sparky.dal.ElasticSearchAdapter;
+import org.onap.aai.sparky.dal.NetworkTransaction;
+import org.slf4j.MDC;
+
+/**
+ * The Class PerformElasticSearchUpdate.
+ */
+public class PerformElasticSearchUpdate implements Supplier<NetworkTransaction> {
+
+ private ElasticSearchAdapter esAdapter;
+ private NetworkTransaction operationTracker;
+ private String updatePayload;
+ private String updateUrl;
+ private Map<String, String> contextMap;
+
+ /**
+ * Instantiates a new perform elastic search update.
+ *
+ * @param updateUrl the update url
+ * @param updatePayload the update payload
+ * @param esDataProvider the es data provider
+ * @param transactionTracker the transaction tracker
+ */
+ public PerformElasticSearchUpdate(String updateUrl, String updatePayload,
+ ElasticSearchAdapter esAdapter, NetworkTransaction transactionTracker) {
+ this.updateUrl = updateUrl;
+ this.updatePayload = updatePayload;
+ this.esAdapter = esAdapter;
+ this.contextMap = MDC.getCopyOfContextMap();
+ this.operationTracker = new NetworkTransaction();
+ operationTracker.setEntityType(transactionTracker.getEntityType());
+ operationTracker.setDescriptor(transactionTracker.getDescriptor());
+ operationTracker.setOperationType(transactionTracker.getOperationType());
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.util.function.Supplier#get()
+ */
+ @Override
+ public NetworkTransaction get() {
+ operationTracker.setTaskAgeInMs();
+ MDC.setContextMap(contextMap);
+ long startTimeInMs = System.currentTimeMillis();
+ OperationResult or = esAdapter.doBulkOperation(updateUrl, updatePayload);
+ operationTracker.setOperationResult(or);
+ operationTracker.setOpTimeInMs(System.currentTimeMillis() - startTimeInMs);
+ return operationTracker;
+ }
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/task/PerformGizmoRetrieval.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/task/PerformGizmoRetrieval.java
new file mode 100644
index 0000000..972b049
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/task/PerformGizmoRetrieval.java
@@ -0,0 +1,95 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.sync.task;
+
+import java.util.Map;
+import java.util.function.Supplier;
+
+import org.onap.aai.cl.api.Logger;
+import org.onap.aai.cl.eelf.LoggerFactory;
+import org.onap.aai.restclient.client.OperationResult;
+import org.onap.aai.sparky.dal.GizmoAdapter;
+import org.onap.aai.sparky.dal.NetworkTransaction;
+import org.onap.aai.sparky.logging.AaiUiMsgs;
+import org.slf4j.MDC;
+
+/*
+ * Consider abstraction the tasks into common elemnts, because most of them repeat a generic call
+ * flow pattern
+ */
+
+/**
+ * The Class PerformActiveInventoryRetrieval.
+ */
+public class PerformGizmoRetrieval implements Supplier<NetworkTransaction> {
+
+ private static Logger logger = LoggerFactory.getInstance().getLogger(PerformGizmoRetrieval.class);
+
+ private NetworkTransaction txn;
+ private GizmoAdapter gizmoAdapter;
+ private Map<String, String> contextMap;
+
+ /**
+ * Instantiates a new perform active inventory retrieval.
+ *
+ * @param txn the txn
+ * @param aaiProvider the aai provider
+ */
+ public PerformGizmoRetrieval(NetworkTransaction txn,
+ GizmoAdapter gizmoAdapter) {
+ this.txn = txn;
+ this.gizmoAdapter = gizmoAdapter;
+ this.contextMap = MDC.getCopyOfContextMap();
+ }
+
+ /* (non-Javadoc)
+ * @see java.util.function.Supplier#get()
+ */
+ @Override
+ public NetworkTransaction get() {
+
+ txn.setTaskAgeInMs();
+
+ long startTimeInMs = System.currentTimeMillis();
+ MDC.setContextMap(contextMap);
+ OperationResult result = null;
+ try {
+ result = gizmoAdapter.queryGizmoWithRetries(txn.getLink(), "application/json", 5);
+ } catch (Exception exc) {
+ logger.error(AaiUiMsgs.ERROR_GENERIC,"Failure to resolve self link from AAI. Error = " + exc.getMessage());
+ result = new OperationResult(500,
+ "Caught an exception while trying to resolve link = " + exc.getMessage());
+ } finally {
+ txn.setOperationResult(result);
+ txn.setOpTimeInMs(System.currentTimeMillis() - startTimeInMs);
+ }
+
+ return txn;
+ }
+
+ protected void setContextMap(Map<String, String> contextMap) {
+ this.contextMap = contextMap;
+ }
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/task/StoreDocumentTask.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/task/StoreDocumentTask.java
new file mode 100644
index 0000000..f92ccd3
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/task/StoreDocumentTask.java
@@ -0,0 +1,90 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.sync.task;
+
+import java.util.Map;
+import java.util.function.Supplier;
+
+import javax.ws.rs.core.MediaType;
+
+import org.onap.aai.restclient.client.OperationResult;
+import org.onap.aai.sparky.dal.ElasticSearchAdapter;
+import org.onap.aai.sparky.dal.NetworkTransaction;
+import org.onap.aai.sparky.sync.entity.IndexDocument;
+import org.slf4j.MDC;
+
+/**
+ * The Class StoreDocumentTask.
+ */
+public class StoreDocumentTask implements Supplier<NetworkTransaction> {
+
+ private IndexDocument doc;
+
+ private NetworkTransaction txn;
+
+ private ElasticSearchAdapter esAdapter;
+ private Map<String, String> contextMap;
+
+ /**
+ * Instantiates a new store document task.
+ *
+ * @param doc the doc
+ * @param txn the txn
+ * @param esDataProvider the es data provider
+ */
+ public StoreDocumentTask(IndexDocument doc, NetworkTransaction txn,
+ ElasticSearchAdapter esAdapter) {
+ this.doc = doc;
+ this.txn = txn;
+ this.esAdapter = esAdapter;
+ this.contextMap = MDC.getCopyOfContextMap();
+ }
+
+ /* (non-Javadoc)
+ * @see java.util.function.Supplier#get()
+ */
+ @Override
+ public NetworkTransaction get() {
+ txn.setTaskAgeInMs();
+
+ long startTimeInMs = System.currentTimeMillis();
+ MDC.setContextMap(contextMap);
+ OperationResult operationResult = null;
+
+ try {
+
+ operationResult =
+ esAdapter.doPut(txn.getLink(), doc.getAsJson(), MediaType.APPLICATION_JSON_TYPE);
+ txn.setOpTimeInMs(System.currentTimeMillis() - startTimeInMs);
+ } catch (Exception exception) {
+ operationResult.setResult(500, exception.getMessage());
+ }
+
+ txn.setOperationResult(operationResult);
+
+ return txn;
+ }
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/task/SyncControllerTask.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/task/SyncControllerTask.java
new file mode 100644
index 0000000..92f3683
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/task/SyncControllerTask.java
@@ -0,0 +1,55 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.sync.task;
+
+import org.onap.aai.sparky.sync.SyncController;
+import org.onap.aai.sparky.sync.SyncControllerImpl.SyncActions;
+import org.onap.aai.sparky.sync.enumeration.SynchronizerState;
+
+public class SyncControllerTask implements Runnable {
+
+ private SyncController controller;
+
+ public SyncControllerTask(SyncController controller) {
+ this.controller = controller;
+ }
+
+ @Override
+ public void run() {
+
+ controller.performAction(SyncActions.SYNCHRONIZE);
+
+ while (controller.getState() == SynchronizerState.PERFORMING_SYNCHRONIZATION) {
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ // exit out of the sync-wait-loop
+ break;
+ }
+ }
+
+ }
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/topology/sync/GeoSyncController.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/topology/sync/GeoSyncController.java
new file mode 100644
index 0000000..93b6eb4
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/topology/sync/GeoSyncController.java
@@ -0,0 +1,101 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.topology.sync;
+
+import org.onap.aai.sparky.config.oxm.GeoEntityLookup;
+import org.onap.aai.sparky.config.oxm.OxmEntityLookup;
+import org.onap.aai.sparky.dal.ActiveInventoryAdapter;
+import org.onap.aai.sparky.dal.ElasticSearchAdapter;
+import org.onap.aai.sparky.sync.ElasticSearchIndexCleaner;
+import org.onap.aai.sparky.sync.ElasticSearchSchemaFactory;
+import org.onap.aai.sparky.sync.IndexCleaner;
+import org.onap.aai.sparky.sync.IndexIntegrityValidator;
+import org.onap.aai.sparky.sync.SyncControllerImpl;
+import org.onap.aai.sparky.sync.SyncControllerRegistrar;
+import org.onap.aai.sparky.sync.SyncControllerRegistry;
+import org.onap.aai.sparky.sync.config.ElasticSearchEndpointConfig;
+import org.onap.aai.sparky.sync.config.ElasticSearchSchemaConfig;
+import org.onap.aai.sparky.sync.config.NetworkStatisticsConfig;
+import org.onap.aai.sparky.sync.config.SyncControllerConfig;
+
+public class GeoSyncController extends SyncControllerImpl implements SyncControllerRegistrar {
+
+ private SyncControllerRegistry syncControllerRegistry;
+
+ public GeoSyncController(SyncControllerConfig syncControllerConfig,
+ ActiveInventoryAdapter aaiAdapter, ElasticSearchAdapter esAdapter,
+ ElasticSearchSchemaConfig schemaConfig, ElasticSearchEndpointConfig endpointConfig,
+ NetworkStatisticsConfig aaiStatConfig, NetworkStatisticsConfig esStatConfig,
+ GeoEntityLookup geoEntityLookup, OxmEntityLookup oxmEntityLookup,
+ ElasticSearchSchemaFactory elasticSearchSchemaFactory) throws Exception {
+ super(syncControllerConfig);
+
+ // final String controllerName = "Inventory Geo Synchronizer";
+
+ IndexIntegrityValidator indexValidator = new IndexIntegrityValidator(esAdapter, schemaConfig,
+ endpointConfig, elasticSearchSchemaFactory.getIndexSchema(schemaConfig));
+
+ registerIndexValidator(indexValidator);
+
+ GeoSynchronizer synchronizer =
+ new GeoSynchronizer(schemaConfig, syncControllerConfig.getNumInternalSyncWorkers(),
+ syncControllerConfig.getNumSyncActiveInventoryWorkers(),
+ syncControllerConfig.getNumSyncElasticWorkers(), aaiStatConfig, esStatConfig,
+ geoEntityLookup, oxmEntityLookup);
+
+ synchronizer.setAaiAdapter(aaiAdapter);
+ synchronizer.setElasticSearchAdapter(esAdapter);
+
+ registerEntitySynchronizer(synchronizer);
+
+
+ IndexCleaner indexCleaner =
+ new ElasticSearchIndexCleaner(esAdapter, endpointConfig, schemaConfig);
+
+ registerIndexCleaner(indexCleaner);
+
+ }
+
+ public SyncControllerRegistry getSyncControllerRegistry() {
+ return syncControllerRegistry;
+ }
+
+ public void setSyncControllerRegistry(SyncControllerRegistry syncControllerRegistry) {
+ this.syncControllerRegistry = syncControllerRegistry;
+ }
+
+ @Override
+ public void registerController() {
+
+ if ( syncControllerRegistry != null ) {
+ if ( syncControllerConfig.isEnabled()) {
+ syncControllerRegistry.registerSyncController(this);
+ }
+ }
+ }
+
+
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/topology/sync/GeoSynchronizer.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/topology/sync/GeoSynchronizer.java
new file mode 100644
index 0000000..fcc8a7a
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/topology/sync/GeoSynchronizer.java
@@ -0,0 +1,487 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.topology.sync;
+
+import static java.util.concurrent.CompletableFuture.supplyAsync;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Deque;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentLinkedDeque;
+import java.util.function.Supplier;
+
+import org.onap.aai.cl.api.Logger;
+import org.onap.aai.cl.eelf.LoggerFactory;
+import org.onap.aai.cl.mdc.MdcContext;
+import org.onap.aai.restclient.client.OperationResult;
+import org.onap.aai.sparky.config.oxm.GeoEntityLookup;
+import org.onap.aai.sparky.config.oxm.GeoOxmEntityDescriptor;
+import org.onap.aai.sparky.config.oxm.OxmEntityDescriptor;
+import org.onap.aai.sparky.config.oxm.OxmEntityLookup;
+import org.onap.aai.sparky.dal.NetworkTransaction;
+import org.onap.aai.sparky.dal.rest.HttpMethod;
+import org.onap.aai.sparky.inventory.entity.GeoIndexDocument;
+import org.onap.aai.sparky.logging.AaiUiMsgs;
+import org.onap.aai.sparky.sync.AbstractEntitySynchronizer;
+import org.onap.aai.sparky.sync.IndexSynchronizer;
+import org.onap.aai.sparky.sync.config.ElasticSearchSchemaConfig;
+import org.onap.aai.sparky.sync.config.NetworkStatisticsConfig;
+import org.onap.aai.sparky.sync.entity.SelfLinkDescriptor;
+import org.onap.aai.sparky.sync.enumeration.OperationState;
+import org.onap.aai.sparky.sync.enumeration.SynchronizerState;
+import org.onap.aai.sparky.sync.task.PerformActiveInventoryRetrieval;
+import org.onap.aai.sparky.sync.task.StoreDocumentTask;
+import org.onap.aai.sparky.util.NodeUtils;
+import org.slf4j.MDC;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+
+
+/**
+ * The Class GeoSynchronizer.
+ */
+public class GeoSynchronizer extends AbstractEntitySynchronizer implements IndexSynchronizer {
+
+ private static final Logger LOG = LoggerFactory.getInstance().getLogger(GeoSynchronizer.class);
+
+ private boolean allWorkEnumerated;
+ private Deque<SelfLinkDescriptor> selflinks;
+ private GeoEntityLookup geoEntityLookup;
+ private OxmEntityLookup oxmEntityLookup;
+
+ private Map<String, GeoOxmEntityDescriptor> geoDescriptorMap = null;
+
+ /**
+ * Instantiates a new geo synchronizer.
+ *
+ * @param indexName the index name
+ * @throws Exception the exception
+ */
+ public GeoSynchronizer(ElasticSearchSchemaConfig schemaConfig, int internalSyncWorkers,
+ int aaiWorkers, int esWorkers, NetworkStatisticsConfig aaiStatConfig,
+ NetworkStatisticsConfig esStatConfig, GeoEntityLookup geoEntityLookup,
+ OxmEntityLookup oxmEntityLookup) throws Exception {
+
+ super(LOG, "GEO", internalSyncWorkers, aaiWorkers, esWorkers, schemaConfig.getIndexName(),aaiStatConfig, esStatConfig);
+ this.geoEntityLookup = geoEntityLookup;
+ this.oxmEntityLookup = oxmEntityLookup;
+ this.allWorkEnumerated = false;
+ this.selflinks = new ConcurrentLinkedDeque<SelfLinkDescriptor>();
+ this.synchronizerName = "Geo Synchronizer";
+ this.geoDescriptorMap = geoEntityLookup.getGeoEntityDescriptors();
+ this.aaiEntityStats.intializeEntityCounters(geoDescriptorMap.keySet());
+ this.esEntityStats.intializeEntityCounters(geoDescriptorMap.keySet());
+ this.syncDurationInMs = -1;
+ }
+
+
+ /* (non-Javadoc)
+ * @see org.openecomp.sparky.synchronizer.IndexSynchronizer#doSync()
+ */
+ @Override
+ public OperationState doSync() {
+ this.syncDurationInMs = -1;
+ resetCounters();
+ setShouldSkipSync(false);
+ allWorkEnumerated = false;
+ syncStartedTimeStampInMs = System.currentTimeMillis();
+ String txnID = NodeUtils.getRandomTxnId();
+ MdcContext.initialize(txnID, "GeoSynchronizer", "", "Sync", "");
+
+ collectAllTheWork();
+ return OperationState.OK;
+ }
+
+
+ /**
+ * Collect all the work.
+ *
+ * @return the operation state
+ */
+ public OperationState collectAllTheWork() {
+ final Map<String,String> contextMap = MDC.getCopyOfContextMap();
+
+ if (geoDescriptorMap.isEmpty()) {
+ setShouldSkipSync(true);
+ LOG.error(AaiUiMsgs.OXM_FAILED_RETRIEVAL, "geo entities");
+ return OperationState.ERROR;
+ }
+
+ Collection<String> syncTypes = geoDescriptorMap.keySet();
+
+ try {
+
+ /*
+ * launch a parallel async thread to process the documents for each entity-type (to max the of
+ * the configured executor anyway)
+ */
+
+ aaiWorkOnHand.set(syncTypes.size());
+
+ for (String key : syncTypes) {
+
+ supplyAsync(new Supplier<Void>() {
+
+ @Override
+ public Void get() {
+ MDC.setContextMap(contextMap);
+ OperationResult typeLinksResult = null;
+ try {
+ typeLinksResult = aaiAdapter.getSelfLinksByEntityType(key);
+ aaiWorkOnHand.decrementAndGet();
+ processEntityTypeSelfLinks(typeLinksResult);
+ } catch (Exception exc) {
+ LOG.error(AaiUiMsgs.ERROR_GETTING_DATA_FROM_AAI, exc);
+ }
+
+ return null;
+ }
+
+ }, aaiExecutor).whenComplete((result, error) -> {
+
+ if (error != null) {
+ LOG.error(AaiUiMsgs.ERROR_GETTING_DATA_FROM_AAI, error.getMessage());
+ }
+ });
+
+ }
+
+ while (aaiWorkOnHand.get() != 0) {
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug(AaiUiMsgs.WAIT_FOR_ALL_SELFLINKS_TO_BE_COLLECTED);
+ }
+
+ Thread.sleep(1000);
+ }
+
+ aaiWorkOnHand.set(selflinks.size());
+ allWorkEnumerated = true;
+ syncEntityTypes();
+
+ } catch (Exception exc) {
+ LOG.error(AaiUiMsgs.ERROR_GETTING_DATA_FROM_AAI, exc);
+ }
+ return OperationState.OK;
+ }
+
+ /**
+ * Sync entity types.
+ */
+ private void syncEntityTypes() {
+
+ while (selflinks.peek() != null) {
+
+ SelfLinkDescriptor linkDescriptor = selflinks.poll();
+ aaiWorkOnHand.decrementAndGet();
+
+ OxmEntityDescriptor descriptor = null;
+
+ if (linkDescriptor.getSelfLink() != null && linkDescriptor.getEntityType() != null) {
+
+ descriptor = oxmEntityLookup.getEntityDescriptors().get(linkDescriptor.getEntityType());
+
+ if (descriptor == null) {
+ LOG.error(AaiUiMsgs.MISSING_ENTITY_DESCRIPTOR, linkDescriptor.getEntityType());
+ // go to next element in iterator
+ continue;
+ }
+
+ NetworkTransaction txn = new NetworkTransaction();
+ txn.setDescriptor(descriptor);
+ txn.setLink(linkDescriptor.getSelfLink());
+ txn.setOperationType(HttpMethod.GET);
+ txn.setEntityType(linkDescriptor.getEntityType());
+
+ aaiWorkOnHand.incrementAndGet();
+
+ supplyAsync(new PerformActiveInventoryRetrieval(txn, aaiAdapter), aaiExecutor)
+ .whenComplete((result, error) -> {
+
+ aaiWorkOnHand.decrementAndGet();
+
+ if (error != null) {
+ LOG.error(AaiUiMsgs.ERROR_GETTING_DATA_FROM_AAI, error.getMessage());
+ } else {
+ if (result == null) {
+ LOG.error(AaiUiMsgs.SELF_LINK_GET_NO_RESPONSE, linkDescriptor.getSelfLink());
+ } else {
+ processEntityTypeSelfLinkResult(result);
+ }
+ }
+ });
+ }
+ }
+ }
+
+ /**
+ * Process entity type self links.
+ *
+ * @param operationResult the operation result
+ */
+ private void processEntityTypeSelfLinks(OperationResult operationResult) {
+
+ JsonNode rootNode = null;
+
+ final String jsonResult = operationResult.getResult();
+
+ if (jsonResult != null && jsonResult.length() > 0 && operationResult.wasSuccessful()) {
+
+ try {
+ rootNode = mapper.readTree(jsonResult);
+ } catch (IOException exc) {
+ LOG.error(AaiUiMsgs.ERROR_GENERIC, exc);
+ }
+
+ JsonNode resultData = rootNode.get("result-data");
+ ArrayNode resultDataArrayNode = null;
+
+ if (resultData.isArray()) {
+ resultDataArrayNode = (ArrayNode) resultData;
+
+ Iterator<JsonNode> elementIterator = resultDataArrayNode.elements();
+ JsonNode element = null;
+
+ while (elementIterator.hasNext()) {
+ element = elementIterator.next();
+
+ final String resourceType = NodeUtils.getNodeFieldAsText(element, "resource-type");
+ final String resourceLink = NodeUtils.getNodeFieldAsText(element, "resource-link");
+
+ if (resourceType != null && resourceLink != null) {
+
+ if (geoDescriptorMap.containsKey(resourceType)) {
+ selflinks.add(new SelfLinkDescriptor(resourceLink + "?nodes-only", resourceType));
+ } else {
+ LOG.error(AaiUiMsgs.MISSING_ENTITY_DESCRIPTOR, resourceType);
+ // go to next element in iterator
+ continue;
+ }
+
+ }
+ }
+ }
+ }
+
+ }
+
+ /**
+ * Process entity type self link result.
+ *
+ * @param txn the txn
+ */
+ private void processEntityTypeSelfLinkResult(NetworkTransaction txn) {
+
+ updateActiveInventoryCounters(txn);
+
+ if (!txn.getOperationResult().wasSuccessful()) {
+ return;
+ }
+
+ GeoOxmEntityDescriptor descriptor = geoDescriptorMap.get(txn.getEntityType());
+
+ if ( descriptor == null ) {
+ return;
+ }
+
+ try {
+ if (descriptor.hasGeoEntity()) {
+
+ GeoIndexDocument geoDoc = new GeoIndexDocument();
+
+ final String jsonResult = txn.getOperationResult().getResult();
+
+ if (jsonResult != null && jsonResult.length() > 0) {
+
+ populateGeoDocument(geoDoc, jsonResult, txn.getDescriptor(), txn.getLink());
+
+ if (!geoDoc.isValidGeoDocument()) {
+
+ LOG.info(AaiUiMsgs.GEO_SYNC_IGNORING_ENTITY, geoDoc.getEntityType(), geoDoc.toString());
+
+ } else {
+
+ String link = null;
+ try {
+ link = elasticSearchAdapter.buildElasticSearchGetDocUrl(getIndexName(), geoDoc.getId());
+ } catch (Exception exc) {
+ LOG.error(AaiUiMsgs.ES_FAILED_TO_CONSTRUCT_URI, exc);
+ }
+
+ if (link != null) {
+
+ NetworkTransaction n2 = new NetworkTransaction();
+ n2.setLink(link);
+ n2.setEntityType(txn.getEntityType());
+ n2.setDescriptor(txn.getDescriptor());
+ n2.setOperationType(HttpMethod.PUT);
+
+ esWorkOnHand.incrementAndGet();
+
+ supplyAsync(new StoreDocumentTask(geoDoc, n2, elasticSearchAdapter), esExecutor)
+ .whenComplete((result, error) -> {
+
+ esWorkOnHand.decrementAndGet();
+
+ if (error != null) {
+ LOG.error(AaiUiMsgs.ES_STORE_FAILURE, error.getMessage());
+ } else {
+ updateElasticSearchCounters(result);
+ processStoreDocumentResult(result);
+ }
+ });
+ }
+ }
+ }
+ }
+ } catch (JsonProcessingException exc) {
+ LOG.error(AaiUiMsgs.JSON_PROCESSING_ERROR, exc);
+ } catch (IOException exc) {
+ LOG.error(AaiUiMsgs.JSON_PROCESSING_ERROR, exc);
+ }
+
+ return;
+ }
+
+
+ /**
+ * Process store document result.
+ *
+ * @param txn the txn
+ */
+ private void processStoreDocumentResult(NetworkTransaction txn) {
+
+ OperationResult or = txn.getOperationResult();
+
+ if (!or.wasSuccessful()) {
+ LOG.error(AaiUiMsgs.ES_STORE_FAILURE, or.toString());
+ /*
+ * if(or.getResultCode() != 404 || (or.getResultCode() == 404 &&
+ * !synchronizerConfig.isResourceNotFoundErrorsSupressed())) { logger.error(
+ * "Skipping failed resource = " + "link" + " RC=[" + or.getResultCode() + "]. Message: " +
+ * or.getResult()); }
+ */
+
+ }
+
+ }
+
+
+ @Override
+ public SynchronizerState getState() {
+
+ if (!isSyncDone()) {
+ return SynchronizerState.PERFORMING_SYNCHRONIZATION;
+ }
+
+ return SynchronizerState.IDLE;
+
+ }
+
+ /* (non-Javadoc)
+ * @see org.openecomp.sparky.synchronizer.IndexSynchronizer#getStatReport(boolean)
+ */
+ @Override
+ public String getStatReport(boolean showFinalReport) {
+ syncDurationInMs = System.currentTimeMillis() - syncStartedTimeStampInMs;
+ return this.getStatReport(syncDurationInMs, showFinalReport);
+ }
+
+ /* (non-Javadoc)
+ * @see org.openecomp.sparky.synchronizer.IndexSynchronizer#shutdown()
+ */
+ @Override
+ public void shutdown() {
+ this.shutdownExecutors();
+ }
+
+ /**
+ * Populate geo document.
+ *
+ * @param doc the doc
+ * @param result the result
+ * @param resultDescriptor the result descriptor
+ * @param entityLink the entity link
+ * @throws JsonProcessingException the json processing exception
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ protected void populateGeoDocument(GeoIndexDocument doc, String result,
+ OxmEntityDescriptor resultDescriptor, String entityLink)
+ throws JsonProcessingException, IOException {
+
+ doc.setSelfLink(entityLink);
+ doc.setEntityType(resultDescriptor.getEntityName());
+
+ JsonNode entityNode = mapper.readTree(result);
+
+ List<String> primaryKeyValues = new ArrayList<String>();
+ String pkeyValue = null;
+
+ for (String keyName : resultDescriptor.getPrimaryKeyAttributeNames()) {
+ pkeyValue = NodeUtils.getNodeFieldAsText(entityNode, keyName);
+ if (pkeyValue != null) {
+ primaryKeyValues.add(pkeyValue);
+ } else {
+ LOG.warn(AaiUiMsgs.ES_PKEYVALUE_NULL, resultDescriptor.getEntityName());
+ }
+ }
+
+ final String primaryCompositeKeyValue = NodeUtils.concatArray(primaryKeyValues, "/");
+ doc.setEntityPrimaryKeyValue(primaryCompositeKeyValue);
+
+ GeoOxmEntityDescriptor descriptor = geoDescriptorMap.get(resultDescriptor.getEntityName());
+
+ String geoLatKey = descriptor.getGeoLatName();
+ String geoLongKey = descriptor.getGeoLongName();
+
+ doc.setLatitude(NodeUtils.getNodeFieldAsText(entityNode, geoLatKey));
+ doc.setLongitude(NodeUtils.getNodeFieldAsText(entityNode, geoLongKey));
+ doc.deriveFields();
+
+ }
+
+ @Override
+ protected boolean isSyncDone() {
+ if (shouldSkipSync()) {
+ syncDurationInMs = System.currentTimeMillis() - syncStartedTimeStampInMs;
+ return true;
+ }
+
+ int totalWorkOnHand = aaiWorkOnHand.get() + esWorkOnHand.get();
+
+ if (totalWorkOnHand > 0 || !allWorkEnumerated) {
+ return false;
+ }
+
+ return true;
+ }
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/util/ConfigHelper.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/util/ConfigHelper.java
new file mode 100644
index 0000000..cb6cc53
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/util/ConfigHelper.java
@@ -0,0 +1,193 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.util;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Properties;
+import java.util.Set;
+
+import org.onap.aai.cl.api.Logger;
+import org.onap.aai.cl.eelf.LoggerFactory;
+import org.onap.aai.sparky.logging.AaiUiMsgs;
+
+/**
+ * The Class ConfigHelper.
+ */
+public class ConfigHelper {
+
+ private static final Logger LOG = LoggerFactory.getInstance().getLogger(ConfigHelper.class);
+
+ /**
+ * Gets the config with prefix.
+ *
+ * @param configPrefix the config prefix
+ * @param properties the properties
+ * @return the config with prefix
+ */
+ public static Properties getConfigWithPrefix(String configPrefix, Properties properties) {
+
+ /*
+ * The idea here is collect properties groups prefixed with the same origin
+ */
+
+ Set<Object> set = properties.keySet();
+ Properties newProps = new Properties();
+
+ for (Object k : set) {
+ String ks = (String) k;
+ if (ks.startsWith(configPrefix)) {
+
+ String temp = ks.replaceFirst(configPrefix + ".", "");
+ newProps.setProperty(temp, properties.getProperty(ks));
+ }
+ }
+
+ return newProps;
+ }
+
+ /**
+ * Load config.
+ *
+ * @param fileName the file name
+ * @return the properties
+ * @throws Exception the exception
+ */
+ public static Properties loadConfig(String fileName) throws Exception {
+
+ String basePath = System.getProperty("user.dir");
+ InputStream fileInputStream = new FileInputStream(basePath + "//" + fileName);
+
+ Properties props = new Properties();
+ props.load(fileInputStream);
+
+ return props;
+ }
+
+ /**
+ * Load config from explicit path.
+ *
+ * @param fileName the file name
+ * @return the properties
+ */
+ public static Properties loadConfigFromExplicitPath(String fileName) {
+
+ Properties props = new Properties();
+
+ try {
+ InputStream fileInputStream = new FileInputStream(fileName);
+ props.load(fileInputStream);
+ } catch (Exception exc) {
+ LOG.warn(AaiUiMsgs.CONFIG_NOT_FOUND_VERBOSE, fileName, exc.getLocalizedMessage());
+ }
+
+ return props;
+ }
+
+ /**
+ * Property fetch.
+ *
+ * @param config the config
+ * @param propName the prop name
+ * @param defaultValue the default value
+ * @return the string
+ */
+ public static String propertyFetch(Properties config, String propName, String defaultValue) {
+ return config.getProperty(propName, defaultValue);
+ }
+
+ public static boolean isEssDevModeEnabled() {
+ return Boolean.parseBoolean(System.getProperty("isEssDevMode", "false"));
+ }
+
+ /**
+ * Gets the filepath.
+ *
+ * @param fileName the file name
+ * @param isRelativePath the is relative path
+ * @return the filepath
+ */
+ public static String getFilepath(String fileName, boolean isRelativePath) {
+
+ String filepath = null;
+
+ if (isRelativePath) {
+ filepath = System.getProperty("user.dir") + "/" + fileName;
+
+ } else {
+ filepath = fileName;
+ }
+
+ return filepath;
+
+ }
+
+ /**
+ * Gets the file contents.
+ *
+ * @param fileName the file name
+ * @return the file contents
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public static String getFileContents(String fileName) throws IOException {
+
+ LOG.debug(AaiUiMsgs.FILE_READ_IN_PROGRESS, fileName);
+
+ File file = new File(fileName);
+
+ if (!file.exists()) {
+ throw new FileNotFoundException("Failed to load file = " + fileName);
+ }
+
+ if (file.exists() && !file.isDirectory()) {
+ BufferedReader br = new BufferedReader(new FileReader(file));
+ try {
+ StringBuilder sb = new StringBuilder();
+ String line = br.readLine();
+
+ while (line != null) {
+ sb.append(line);
+ sb.append(System.lineSeparator());
+ line = br.readLine();
+ }
+
+ return sb.toString();
+ } finally {
+ br.close();
+ }
+ } else {
+ LOG.warn(AaiUiMsgs.FILE_NOT_FOUND, fileName);
+ }
+
+ return null;
+
+ }
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/util/EncryptConvertor.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/util/EncryptConvertor.java
new file mode 100644
index 0000000..623ce38
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/util/EncryptConvertor.java
@@ -0,0 +1,149 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.util;
+
+/**
+ * The Class EncryptConvertor.
+ */
+public class EncryptConvertor {
+
+ private static final char[] HEX_CHARS = "0123456789abcdef".toCharArray();
+
+ /**
+ * toHexString(String) - convert a string into its hex equivalent.
+ *
+ * @param buf the buf
+ * @return the string
+ */
+ public static final String toHexString(String buf) {
+ if (buf == null) {
+ return "";
+ }
+ return toHexString(buf.getBytes());
+ }
+
+ /**
+ * toHexString(byte[]) - convert a byte-string into its hex equivalent.
+ *
+ * @param buf the buf
+ * @return the string
+ */
+ public static final String toHexString(byte[] buf) {
+
+ if (buf == null) {
+ return "";
+ }
+ char[] chars = new char[2 * buf.length];
+ for (int i = 0; i < buf.length; ++i) {
+ chars[2 * i] = HEX_CHARS[(buf[i] & 0xF0) >>> 4];
+ chars[2 * i + 1] = HEX_CHARS[buf[i] & 0x0F];
+ }
+ return new String(chars);
+ }
+
+ /**
+ * Convert a hex string to its equivalent value.
+ *
+ * @param hexString the hex string
+ * @return the string
+ * @throws Exception the exception
+ */
+ public static final String stringFromHex(String hexString) throws Exception {
+ if (hexString == null) {
+ return "";
+ }
+ return stringFromHex(hexString.toCharArray());
+ }
+
+ /**
+ * String from hex.
+ *
+ * @param hexCharArray the hex char array
+ * @return the string
+ * @throws Exception the exception
+ */
+ public static final String stringFromHex(char[] hexCharArray) throws Exception {
+ if (hexCharArray == null) {
+ return "";
+ }
+ return new String(bytesFromHex(hexCharArray));
+ }
+
+ /**
+ * Bytes from hex.
+ *
+ * @param hexString the hex string
+ * @return the byte[]
+ * @throws Exception the exception
+ */
+ public static final byte[] bytesFromHex(String hexString) throws Exception {
+ if (hexString == null) {
+ return new byte[0];
+ }
+ return bytesFromHex(hexString.toCharArray());
+ }
+
+ /**
+ * Bytes from hex.
+ *
+ * @param hexCharArray the hex char array
+ * @return the byte[]
+ * @throws Exception the exception
+ */
+ public static final byte[] bytesFromHex(char[] hexCharArray) throws Exception {
+ if (hexCharArray == null) {
+ return new byte[0];
+ }
+ int len = hexCharArray.length;
+ if ((len % 2) != 0) {
+ throw new Exception("Odd number of characters: '" + String.valueOf(hexCharArray) + "'");
+ }
+ byte[] txtInByte = new byte[len / 2];
+ int counter = 0;
+ for (int i = 0; i < len; i += 2) {
+ txtInByte[counter++] =
+ (byte) (((fromHexDigit(hexCharArray[i], i) << 4) | fromHexDigit(hexCharArray[i + 1], i))
+ & 0xFF);
+ }
+ return txtInByte;
+ }
+
+ /**
+ * From hex digit.
+ *
+ * @param ch the ch
+ * @param index the index
+ * @return the int
+ * @throws Exception the exception
+ */
+ protected static final int fromHexDigit(char ch, int index) throws Exception {
+ int digit = Character.digit(ch, 16);
+ if (digit == -1) {
+ throw new Exception("Illegal hex character '" + ch + "' at index " + index);
+ }
+ return digit;
+ }
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/util/Encryptor.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/util/Encryptor.java
new file mode 100644
index 0000000..948df51
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/util/Encryptor.java
@@ -0,0 +1,155 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.util;
+
+import org.apache.commons.cli.BasicParser;
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.CommandLineParser;
+import org.apache.commons.cli.Options;
+import org.apache.commons.cli.ParseException;
+import org.eclipse.jetty.util.security.Password;
+import org.onap.aai.cl.api.Logger;
+import org.onap.aai.cl.eelf.LoggerFactory;
+import org.onap.aai.sparky.logging.AaiUiMsgs;
+
+/**
+ * The Class Encryptor.
+ */
+public class Encryptor {
+
+ private static final Logger LOG = LoggerFactory.getInstance().getLogger(Encryptor.class);
+ /**
+ * Instantiates a new encryptor.
+ */
+ public Encryptor() {
+ }
+
+ /**
+ * Encrypt value.
+ *
+ * @param value to encrypt
+ * @return the encrypted string
+ */
+ public String encryptValue(String value) {
+ String encyptedValue = "";
+ try {
+ encyptedValue = Password.obfuscate(value);
+ } catch (Exception exc) {
+ LOG.error(AaiUiMsgs.ENCRYPTION_ERROR, value, exc.toString());
+ }
+ return encyptedValue;
+ }
+
+ /**
+ * Decrypt value.
+ *
+ * @param value the value
+ * @return the string
+ */
+ public String decryptValue(String value) {
+ String decyptedValue = "";
+ try {
+ decyptedValue = Password.deobfuscate(value);
+ } catch (Exception exc) {
+ LOG.error(AaiUiMsgs.DECRYPTION_ERROR, value, exc.toString());
+ }
+
+ return decyptedValue;
+ }
+
+ /**
+ * Usage.
+ */
+ public static void usage() {
+ usage(null);
+ }
+
+ /**
+ * Usage.
+ *
+ * @param msg the msg
+ */
+ public static void usage(String msg) {
+ if (msg != null) {
+ System.err.println(msg);
+ }
+ System.err.println("Usage: java Encryptor -e value");
+ System.err.println("\tEncrypt the given value");
+ System.err.println("Usage: java Encryptor -d value");
+ System.err.println("\tDecrypt the given value");
+ System.exit(1);
+ }
+
+ /**
+ * The main method.
+ *
+ * @param args the arguments
+ */
+ public static void main(String[] args) {
+
+ Options options = new Options();
+ options.addOption("d", true, "value to decrypt");
+ options.addOption("h", false, "show help");
+ options.addOption("?", false, "show help");
+
+ String value = null;
+ boolean encrypt = false;
+ boolean decrypt = false;
+
+ CommandLineParser parser = new BasicParser();
+ CommandLine cmd = null;
+
+ try {
+ cmd = parser.parse(options, args);
+
+ if (cmd.hasOption("d")) {
+ value = cmd.getOptionValue("d");
+ decrypt = true;
+ }
+
+ if (cmd.hasOption("?") || cmd.hasOption("h")) {
+ usage();
+ System.exit(0);
+ }
+
+ if ((encrypt && decrypt) || (!encrypt && !decrypt)) {
+ usage("Must specify one (and only one) of the -e or -d options");
+ }
+
+ Encryptor encryptor = new Encryptor();
+
+ if (decrypt) {
+ String out = encryptor.decryptValue(value);
+ System.out.println(out);
+ }
+ } catch (ParseException exc) {
+ System.out.println("Failed to parse command line properties: " + exc.toString());
+ } catch (Exception exc) {
+ System.out.println("Failure: " + exc.toString());
+ }
+
+ System.exit(0);
+ }
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/util/ErrorUtil.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/util/ErrorUtil.java
new file mode 100644
index 0000000..d2bea64
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/util/ErrorUtil.java
@@ -0,0 +1,61 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.util;
+
+/**
+ * The Class ErrorUtil.
+ */
+public class ErrorUtil {
+
+ /**
+ * Extract stack trace elements.
+ *
+ * @param maxNumberOfElementsToCapture the max number of elements to capture
+ * @param exc the exc
+ * @return the string
+ */
+ public static String extractStackTraceElements(int maxNumberOfElementsToCapture, Exception exc) {
+ StringBuilder sb = new StringBuilder(128);
+
+ StackTraceElement[] stackTraceElements = exc.getStackTrace();
+
+ if (stackTraceElements != null) {
+
+ /*
+ * We want to avoid an index out-of-bounds error, so we will make sure to only extract the
+ * number of frames from the stack trace that actually exist.
+ */
+
+ int numFramesToExtract = Math.min(maxNumberOfElementsToCapture, stackTraceElements.length);
+
+ for (int x = 0; x < numFramesToExtract; x++) {
+ sb.append(stackTraceElements[x]).append("\n");
+ }
+
+ }
+
+ return sb.toString();
+ }
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/util/JsonXmlConverter.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/util/JsonXmlConverter.java
new file mode 100644
index 0000000..af2e8ca
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/util/JsonXmlConverter.java
@@ -0,0 +1,79 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.util;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.json.XML;
+
+/**
+ * The Class JsonXmlConverter.
+ */
+public class JsonXmlConverter {
+
+ /**
+ * Checks if is valid json.
+ *
+ * @param text the text
+ * @return true, if is valid json
+ */
+ public static boolean isValidJson(String text) {
+ try {
+ new JSONObject(text);
+ } catch (JSONException ex) {
+ try {
+ new JSONArray(text);
+ } catch (JSONException ex1) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Convert jsonto xml.
+ *
+ * @param jsonText the json text
+ * @return the string
+ */
+ public static String convertJsontoXml(String jsonText) {
+ JSONObject jsonObj = new JSONObject(jsonText);
+ String xmlText = XML.toString(jsonObj);
+ return xmlText;
+ }
+
+ /**
+ * Convert xmlto json.
+ *
+ * @param xmlText the xml text
+ * @return the string
+ */
+ public static String convertXmltoJson(String xmlText) {
+ JSONObject jsonObj = XML.toJSONObject(xmlText);
+ return jsonObj.toString();
+ }
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/util/NodeUtils.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/util/NodeUtils.java
new file mode 100644
index 0000000..68645e2
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/util/NodeUtils.java
@@ -0,0 +1,896 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.util;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.lang.Thread.UncaughtExceptionHandler;
+import java.net.URI;
+import java.nio.ByteBuffer;
+import java.security.SecureRandom;
+import java.sql.Timestamp;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.TimeZone;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.TimeUnit;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.xml.stream.XMLStreamConstants;
+
+import org.onap.aai.cl.api.Logger;
+import org.onap.aai.sparky.logging.AaiUiMsgs;
+import org.onap.aai.sparky.viewandinspect.config.SparkyConstants;
+import org.restlet.Request;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.ObjectWriter;
+import com.fasterxml.jackson.databind.SerializationFeature;
+import com.fasterxml.jackson.databind.ser.FilterProvider;
+import com.google.common.util.concurrent.ThreadFactoryBuilder;
+
+
+/**
+ * The Class NodeUtils.
+ */
+public class NodeUtils {
+ private static SecureRandom sRandom = new SecureRandom();
+
+ private static final Pattern AAI_VERSION_PREFIX = Pattern.compile("/aai/v[0-9]+/(.*)");
+ private static final Pattern GIZMO_VERSION_PREFIX = Pattern.compile("[/]*services/inventory/v[0-9]+/(.*)");
+ private static final Pattern GIZMO_RELATIONSHIP_VERSION_PREFIX = Pattern.compile("services/inventory/relationships/v[0-9]+/(.*)");
+
+
+ public static synchronized String getRandomTxnId(){
+ byte bytes[] = new byte[6];
+ sRandom.nextBytes(bytes);
+ return Integer.toUnsignedString(ByteBuffer.wrap(bytes).getInt());
+ }
+
+ /**
+ * Builds the depth padding.
+ *
+ * @param depth the depth
+ * @return the string
+ */
+ public static String buildDepthPadding(int depth) {
+ StringBuilder sb = new StringBuilder(32);
+
+ for (int x = 0; x < depth; x++) {
+ sb.append(" ");
+ }
+
+ return sb.toString();
+ }
+
+
+ public static String extractRawPathWithoutVersion(String selfLinkUri) {
+
+ try {
+
+ String rawPath = new URI(selfLinkUri).getRawPath();
+
+ Matcher m = AAI_VERSION_PREFIX.matcher(rawPath);
+
+ if (m.matches()) {
+
+ if ( m.groupCount() >= 1) {
+ return m.group(1);
+ }
+
+ }
+ } catch (Exception e) {
+ }
+
+ return null;
+
+ }
+
+ public static String extractRawGizmoPathWithoutVersion(String resourceLink) {
+
+ try {
+
+ String rawPath = new URI(resourceLink).getRawPath();
+
+ Matcher m = GIZMO_VERSION_PREFIX.matcher(rawPath);
+
+ if (m.matches()) {
+
+ if ( m.groupCount() >= 1) {
+ return m.group(1);
+ }
+
+ }
+ } catch (Exception e) {
+ }
+
+ return null;
+
+ }
+
+ public static String extractRawGizmoRelationshipPathWithoutVersion(String resourceLink) {
+
+ try {
+
+ String rawPath = new URI(resourceLink).getRawPath();
+
+ Matcher m = GIZMO_RELATIONSHIP_VERSION_PREFIX.matcher(rawPath);
+
+ if (m.matches()) {
+
+ if ( m.groupCount() >= 1) {
+ return m.group(1);
+ }
+
+ }
+ } catch (Exception e) {
+ }
+
+ return null;
+
+ }
+
+
+
+
+ /**
+ * Checks if is numeric.
+ *
+ * @param numberStr the number str
+ * @return true, if is numeric
+ */
+ public static boolean isNumeric(String numberStr) {
+
+ try {
+ Double.parseDouble(numberStr);
+ } catch (Exception exc) {
+ return false;
+ }
+
+ return true;
+
+ }
+
+ /**
+ * Creates the named executor.
+ *
+ * @param name the name
+ * @param numWorkers the num workers
+ * @param logger the logger
+ * @return the executor service
+ */
+ public static ExecutorService createNamedExecutor(String name, int numWorkers, final Logger logger) {
+ UncaughtExceptionHandler uncaughtExceptionHandler = new Thread.UncaughtExceptionHandler() {
+
+ @Override
+ public void uncaughtException(Thread thread, Throwable exc) {
+
+ logger.error(AaiUiMsgs.ERROR_GENERIC, thread.getName() + ": " + exc);
+
+ }
+ };
+
+ ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat(name + "-%d")
+ .setUncaughtExceptionHandler(uncaughtExceptionHandler).build();
+
+ return Executors.newScheduledThreadPool(numWorkers + 1, namedThreadFactory);
+ }
+
+
+ public static String calculateEditAttributeUri(String link) {
+ String uri = null;
+
+ if (link != null) {
+
+ Pattern pattern = Pattern.compile(SparkyConstants.URI_VERSION_REGEX_PATTERN);
+ Matcher matcher = pattern.matcher(link);
+ if (matcher.find()) {
+ uri = link.substring(matcher.end());
+ }
+ }
+ return uri;
+ }
+
+
+ /**
+ * Generate unique sha digest.
+ *
+ * @param keys the keys
+ * @return the string
+ */
+ public static String generateUniqueShaDigest(String... keys) {
+
+ if ((keys == null) || keys.length == 0) {
+ return null;
+ }
+
+ final String keysStr = Arrays.asList(keys).toString();
+ final String hashedId = org.apache.commons.codec.digest.DigestUtils.sha256Hex(keysStr);
+
+ return hashedId;
+ }
+
+ /**
+ * Gets the node field as text.
+ *
+ * @param node the node
+ * @param fieldName the field name
+ * @return the node field as text
+ */
+ public static String getNodeFieldAsText(JsonNode node, String fieldName) {
+
+ String fieldValue = null;
+
+ JsonNode valueNode = node.get(fieldName);
+
+ if (valueNode != null) {
+ fieldValue = valueNode.asText();
+ }
+
+ return fieldValue;
+ }
+
+ private static final String ENTITY_RESOURCE_KEY_FORMAT = "%s.%s";
+
+ /**
+ * Convert a millisecond duration to a string format
+ *
+ * @param millis A duration to convert to a string form
+ * @return A string of the form "X Days Y Hours Z Minutes A Seconds".
+ */
+
+ private static final String TIME_BREAK_DOWN_FORMAT =
+ "[ %d days, %d hours, %d minutes, %d seconds ]";
+
+ /**
+ * Gets the duration breakdown.
+ *
+ * @param millis the millis
+ * @return the duration breakdown
+ */
+ public static String getDurationBreakdown(long millis) {
+
+ if (millis < 0) {
+ return String.format(TIME_BREAK_DOWN_FORMAT, 0, 0, 0, 0);
+ }
+
+ long days = TimeUnit.MILLISECONDS.toDays(millis);
+ millis -= TimeUnit.DAYS.toMillis(days);
+ long hours = TimeUnit.MILLISECONDS.toHours(millis);
+ millis -= TimeUnit.HOURS.toMillis(hours);
+ long minutes = TimeUnit.MILLISECONDS.toMinutes(millis);
+ millis -= TimeUnit.MINUTES.toMillis(minutes);
+ long seconds = TimeUnit.MILLISECONDS.toSeconds(millis);
+
+ return String.format(TIME_BREAK_DOWN_FORMAT, days, hours, minutes, seconds);
+
+ }
+
+ /**
+ * Checks if is equal.
+ *
+ * @param n1 the n 1
+ * @param n2 the n 2
+ * @return true, if is equal
+ */
+ public static boolean isEqual(JsonNode n1, JsonNode n2) {
+
+ /*
+ * due to the inherent nature of json being unordered, comparing object representations of the
+ * same keys and values but different order makes comparison challenging. Let's try an
+ * experiment where we compare the structure of the json, and then simply compare the sorted
+ * order of that structure which should be good enough for what we are trying to accomplish.
+ */
+
+ TreeWalker walker = new TreeWalker();
+ List<String> n1Paths = new ArrayList<String>();
+ List<String> n2Paths = new ArrayList<String>();
+
+ walker.walkTree(n1Paths, n1);
+ walker.walkTree(n2Paths, n2);
+
+ Collections.sort(n1Paths);
+ Collections.sort(n2Paths);
+
+ return n1Paths.equals(n2Paths);
+
+ }
+
+ /**
+ * Concat array.
+ *
+ * @param list the list
+ * @return the string
+ */
+ public static String concatArray(List<String> list) {
+ return concatArray(list, " ");
+ }
+
+ private static final String TIMESTAMP_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSSZ";
+
+ public static String getCurrentTimeStamp() {
+ SimpleDateFormat dateFormat = new SimpleDateFormat(TIMESTAMP_FORMAT);
+ Timestamp timestamp = new Timestamp(System.currentTimeMillis());
+ return dateFormat.format(timestamp);
+ }
+
+ /**
+ * Concat array.
+ *
+ * @param list the list
+ * @param delimiter the delimiter
+ * @return the string
+ */
+ public static String concatArray(List<String> list, String delimiter) {
+
+ if (list == null || list.size() == 0) {
+ return "";
+ }
+
+ StringBuilder result = new StringBuilder(64);
+
+ boolean firstValue = true;
+
+ for (String item : list) {
+
+ if (firstValue) {
+ result.append(item);
+ firstValue = false;
+ } else {
+ result.append(delimiter).append(item);
+ }
+
+ }
+
+ return result.toString();
+
+ }
+
+ /**
+ * Concat array.
+ *
+ * @param values the values
+ * @return the string
+ */
+ public static String concatArray(String[] values) {
+
+ if (values == null || values.length == 0) {
+ return "";
+ }
+
+ StringBuilder result = new StringBuilder(64);
+
+ boolean firstValue = true;
+
+ for (String item : values) {
+
+ if (firstValue) {
+ result.append(item);
+ firstValue = false;
+ } else {
+ result.append(".").append(item);
+ }
+
+ }
+
+ return result.toString();
+
+ }
+
+ /**
+ * Builds the entity resource key.
+ *
+ * @param entityType the entity type
+ * @param resourceId the resource id
+ * @return the string
+ */
+ public static String buildEntityResourceKey(String entityType, String resourceId) {
+ return String.format(ENTITY_RESOURCE_KEY_FORMAT, entityType, resourceId);
+ }
+
+ /**
+ * Extract resource id from link.
+ *
+ * @param link the link
+ * @return the string
+ */
+ public static String extractResourceIdFromLink(String link) {
+
+ if (link == null) {
+ return null;
+ }
+
+ int linkLength = link.length();
+ if (linkLength == 0) {
+ return null;
+ }
+
+ /*
+ * if the last character != / then we need to change the lastIndex position
+ */
+
+ int startIndex = 0;
+ String resourceId = null;
+ if ("/".equals(link.substring(linkLength - 1))) {
+ // Use-case:
+ // https://ext1.test.onap.com:9292/aai/v7/business/customers/customer/customer-1/service-subscriptions/service-subscription/service-subscription-1/
+ startIndex = link.lastIndexOf("/", linkLength - 2);
+ resourceId = link.substring(startIndex + 1, linkLength - 1);
+ } else {
+ // Use-case:
+ // https://ext1.test.onap.com:9292/aai/v7/business/customers/customer/customer-1/service-subscriptions/service-subscription/service-subscription-1
+ startIndex = link.lastIndexOf("/");
+ resourceId = link.substring(startIndex + 1, linkLength);
+ }
+
+ String result = null;
+
+ if (resourceId != null) {
+ try {
+ result = java.net.URLDecoder.decode(resourceId, "UTF-8");
+ } catch (Exception exc) {
+ /*
+ * if there is a failure decoding the parameter we will just return the original value.
+ */
+ result = resourceId;
+ }
+ }
+
+ return result;
+
+ }
+
+ /**
+ * Gets the xml stream constant as str.
+ *
+ * @param value the value
+ * @return the xml stream constant as str
+ */
+ public static String getXmlStreamConstantAsStr(int value) {
+ switch (value) {
+ case XMLStreamConstants.ATTRIBUTE:
+ return "ATTRIBUTE";
+ case XMLStreamConstants.CDATA:
+ return "CDATA";
+ case XMLStreamConstants.CHARACTERS:
+ return "CHARACTERS";
+ case XMLStreamConstants.COMMENT:
+ return "COMMENT";
+ case XMLStreamConstants.DTD:
+ return "DTD";
+ case XMLStreamConstants.END_DOCUMENT:
+ return "END_DOCUMENT";
+ case XMLStreamConstants.END_ELEMENT:
+ return "END_ELEMENT";
+ case XMLStreamConstants.ENTITY_DECLARATION:
+ return "ENTITY_DECLARATION";
+ case XMLStreamConstants.ENTITY_REFERENCE:
+ return "ENTITY_REFERENCE";
+ case XMLStreamConstants.NAMESPACE:
+ return "NAMESPACE";
+ case XMLStreamConstants.NOTATION_DECLARATION:
+ return "NOTATION_DECLARATION";
+ case XMLStreamConstants.PROCESSING_INSTRUCTION:
+ return "PROCESSING_INSTRUCTION";
+ case XMLStreamConstants.SPACE:
+ return "SPACE";
+ case XMLStreamConstants.START_DOCUMENT:
+ return "START_DOCUMENT";
+ case XMLStreamConstants.START_ELEMENT:
+ return "START_ELEMENT";
+
+ default:
+ return "Unknown(" + value + ")";
+ }
+ }
+
+ /**
+ * Convert object to json.
+ *
+ * @param object the object
+ * @param pretty the pretty
+ * @return the string
+ * @throws JsonProcessingException the json processing exception
+ */
+ public static String convertObjectToJson(Object object, boolean pretty)
+ throws JsonProcessingException {
+ ObjectWriter ow = null;
+
+ ObjectMapper mapper = new ObjectMapper();
+ mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
+
+ if (pretty) {
+ ow = mapper.writer().withDefaultPrettyPrinter();
+
+ } else {
+ ow = mapper.writer();
+ }
+
+ return ow.writeValueAsString(object);
+ }
+
+ /**
+ * Convert object to json by selectively choosing certain fields thru filters.
+ * Example use case:
+ * based on request type we might need to send different serialization of the UiViewFilterEntity
+ *
+ * @param object the object
+ * @param pretty the pretty
+ * @return the string
+ * @throws JsonProcessingException the json processing exception
+ */
+ public static String convertObjectToJson(Object object, boolean pretty, FilterProvider filters)
+ throws JsonProcessingException {
+ ObjectWriter ow = null;
+
+ ObjectMapper mapper = new ObjectMapper();
+ mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
+
+ if (pretty) {
+ ow = mapper.writer(filters).withDefaultPrettyPrinter();
+
+ } else {
+ ow = mapper.writer(filters);
+ }
+
+ return ow.writeValueAsString(object);
+ }
+
+
+ /**
+ * Convert json str to json node.
+ *
+ * @param jsonStr the json str
+ * @return the json node
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public static JsonNode convertJsonStrToJsonNode(String jsonStr) throws IOException {
+ ObjectMapper mapper = new ObjectMapper();
+ if (jsonStr == null || jsonStr.length() == 0) {
+ return null;
+ }
+
+ return mapper.readTree(jsonStr);
+ }
+
+ /**
+ * Convert object to xml.
+ *
+ * @param object the object
+ * @return the string
+ * @throws JsonProcessingException the json processing exception
+ */
+ public static String convertObjectToXml(Object object) throws JsonProcessingException {
+ ObjectWriter ow = new ObjectMapper().writer().withDefaultPrettyPrinter();
+ String jsonOutput = ow.writeValueAsString(object);
+
+ if (jsonOutput == null) {
+ return null;
+ }
+
+ return JsonXmlConverter.convertJsontoXml(jsonOutput);
+
+ }
+
+ /**
+ * Extract objects by key.
+ *
+ * @param node the node
+ * @param searchKey the search key
+ * @param foundObjects the found objects
+ */
+ public static void extractObjectsByKey(JsonNode node, String searchKey,
+ Collection<JsonNode> foundObjects) {
+
+ if ( node == null ) {
+ return;
+ }
+
+ if (node.isObject()) {
+ Iterator<Map.Entry<String, JsonNode>> nodeIterator = node.fields();
+
+ while (nodeIterator.hasNext()) {
+ Map.Entry<String, JsonNode> entry = nodeIterator.next();
+ if (!entry.getValue().isValueNode()) {
+ extractObjectsByKey(entry.getValue(), searchKey, foundObjects);
+ }
+
+ String name = entry.getKey();
+ if (name.equalsIgnoreCase(searchKey)) {
+
+ JsonNode entryNode = entry.getValue();
+
+ if (entryNode.isArray()) {
+
+ Iterator<JsonNode> arrayItemsIterator = entryNode.elements();
+ while (arrayItemsIterator.hasNext()) {
+ foundObjects.add(arrayItemsIterator.next());
+ }
+
+ } else {
+ foundObjects.add(entry.getValue());
+ }
+
+
+ }
+ }
+ } else if (node.isArray()) {
+ Iterator<JsonNode> arrayItemsIterator = node.elements();
+ while (arrayItemsIterator.hasNext()) {
+ extractObjectsByKey(arrayItemsIterator.next(), searchKey, foundObjects);
+ }
+
+ }
+ }
+
+ public static String extractObjectValueByKey(JsonNode node, String searchKey) {
+
+ if (node == null) {
+ return null;
+ }
+
+ if (node.isObject()) {
+ Iterator<Map.Entry<String, JsonNode>> nodeIterator = node.fields();
+
+ while (nodeIterator.hasNext()) {
+ Map.Entry<String, JsonNode> entry = nodeIterator.next();
+ if (!entry.getValue().isValueNode()) {
+ return extractObjectValueByKey(entry.getValue(), searchKey);
+ }
+
+ String name = entry.getKey();
+ if (name.equalsIgnoreCase(searchKey)) {
+
+ JsonNode entryNode = entry.getValue();
+
+ if (entryNode.isArray()) {
+
+ Iterator<JsonNode> arrayItemsIterator = entryNode.elements();
+ while (arrayItemsIterator.hasNext()) {
+ return arrayItemsIterator.next().asText();
+ }
+
+ } else {
+ return entry.getValue().asText();
+ }
+
+
+ }
+ }
+ } else if (node.isArray()) {
+ Iterator<JsonNode> arrayItemsIterator = node.elements();
+ while (arrayItemsIterator.hasNext()) {
+ return extractObjectValueByKey(arrayItemsIterator.next(), searchKey);
+ }
+
+ }
+
+ return null;
+
+ }
+
+ /**
+ * Convert array into list.
+ *
+ * @param node the node
+ * @param instances the instances
+ */
+ public static void convertArrayIntoList(JsonNode node, Collection<JsonNode> instances) {
+
+ if (node.isArray()) {
+ Iterator<JsonNode> arrayItemsIterator = node.elements();
+ while (arrayItemsIterator.hasNext()) {
+ instances.add(arrayItemsIterator.next());
+ }
+
+ } else {
+ instances.add(node);
+ }
+
+ }
+
+ /**
+ * Extract field values from object.
+ *
+ * @param node the node
+ * @param attributesToExtract the attributes to extract
+ * @param fieldValues the field values
+ */
+ public static void extractFieldValuesFromObject(JsonNode node,
+ Collection<String> attributesToExtract, Collection<String> fieldValues) {
+
+ if (node == null) {
+ return;
+ }
+
+ if (node.isObject()) {
+
+ JsonNode valueNode = null;
+
+ for (String attrToExtract : attributesToExtract) {
+
+ valueNode = node.get(attrToExtract);
+
+ if (valueNode != null) {
+
+ if (valueNode.isValueNode()) {
+ fieldValues.add(valueNode.asText());
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Extract field value from object.
+ *
+ * @param node the node
+ * @param fieldName the field name
+ * @return the string
+ */
+ public static String extractFieldValueFromObject(JsonNode node, String fieldName) {
+
+ if (node == null) {
+ return null;
+ }
+
+ if (node.isObject()) {
+
+ JsonNode valueNode = node.get(fieldName);
+
+ if (valueNode != null) {
+
+ if (valueNode.isValueNode()) {
+ return valueNode.asText();
+ }
+ }
+
+ }
+ return null;
+
+ }
+
+ /**
+ * Format timestamp.
+ *
+ * @param timestamp the timestamp
+ * @return the string
+ */
+ public static String formatTimestamp(String timestamp) {
+ try {
+ SimpleDateFormat originalFormat = new SimpleDateFormat("yyyyMMdd'T'HHmmss'Z'");
+ originalFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
+ Date toDate = originalFormat.parse(timestamp);
+ SimpleDateFormat newFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
+ newFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
+ return newFormat.format(toDate);
+
+ } catch (ParseException pe) {
+ return timestamp;
+ }
+ }
+
+ /**
+ * Gets the HttpRequest payload.
+ *
+ * @param request the request
+ * @return the body
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public static String getBody(HttpServletRequest request) throws IOException {
+ InputStream inputStream = request.getInputStream();
+ return getBodyFromStream(inputStream);
+ }
+
+
+
+ /**
+ * Gets the Restlet Request payload.
+ *
+ * @param request the request
+ * @return the body
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public static String getBody(Request request) throws IOException {
+ InputStream inputStream = request.getEntity().getStream();
+ return getBodyFromStream(inputStream);
+ }
+
+
+ /**
+ * Gets the payload from the input stream of a request.
+ *
+ * @param request the request
+ * @return the body
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public static String getBodyFromStream(InputStream inputStream) throws IOException {
+
+ String body = null;
+ StringBuilder stringBuilder = new StringBuilder();
+ BufferedReader bufferedReader = null;
+
+ try {
+ if (inputStream != null) {
+ bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
+ char[] charBuffer = new char[128];
+ int bytesRead = -1;
+ while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
+ stringBuilder.append(charBuffer, 0, bytesRead);
+ }
+ } else {
+ stringBuilder.append("");
+ }
+ } catch (IOException ex) {
+ throw ex;
+ } finally {
+ if (bufferedReader != null) {
+ try {
+ bufferedReader.close();
+ } catch (IOException ex) {
+ throw ex;
+ }
+ }
+ }
+
+ body = stringBuilder.toString();
+ return body;
+ }
+
+
+ /**
+ * The main method.
+ *
+ * @param args the arguments
+ * @throws ParseException the parse exception
+ */
+ public static void main(String[] args) throws ParseException {
+ String date = "20170110T112312Z";
+ SimpleDateFormat originalFormat = new SimpleDateFormat("yyyyMMdd'T'hhmmss'Z'");
+ Date toDate = originalFormat.parse(date);
+ SimpleDateFormat newFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss'Z'");
+ System.out.println(newFormat.format(toDate));
+
+ }
+
+
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/util/RawByteHelper.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/util/RawByteHelper.java
new file mode 100644
index 0000000..99166ca
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/util/RawByteHelper.java
@@ -0,0 +1,176 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.util;
+
+/**
+ * The Class RawByteHelper.
+ */
+public class RawByteHelper {
+ private static final byte[] HEX_CHAR =
+ new byte[] {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
+
+ /**
+ * Dump bytes.
+ *
+ * @param buffer the buffer
+ * @return the string
+ */
+ /*
+ * TODO -> DOCUMENT ME!
+ *
+ * @param buffer DOCUMENT ME!
+ *
+ * @return DOCUMENT ME!
+ */
+ public static String dumpBytes(byte[] buffer) {
+ if (buffer == null) {
+ return "";
+ }
+ String newLine = System.getProperty("line.separator");
+ StringBuffer sb = new StringBuffer();
+
+ for (int i = 0; i < buffer.length; i++) {
+ if (i != 0 && i % 16 == 0) {
+ sb.append(newLine);
+ }
+ // sb.append("0x").append((char) (HEX_CHAR[(buffer[i] & 0x00F0) >> 4])).append((char)
+ // (HEX_CHAR[buffer[i] & 0x000F])).append(" ");
+ sb.append((char) (HEX_CHAR[(buffer[i] & 0x00F0) >> 4]))
+ .append((char) (HEX_CHAR[buffer[i] & 0x000F])).append(" ");
+ }
+
+ return sb.toString();
+ }
+
+ // if you're trying to figure out why or's w/ FF's see:
+ /**
+ * Bytes to int.
+ *
+ * @param one the one
+ * @param two the two
+ * @param three the three
+ * @param four the four
+ * @return the int
+ */
+ // http://www.darksleep.com/player/JavaAndUnsignedTypes.html
+ public static int bytesToInt(byte one, byte two, byte three, byte four) {
+ return (((0xFF & one) << 24) | ((0xFF & two) << 16) | ((0xFF & three) << 8) | ((0xFF & four)));
+ }
+
+ /**
+ * Bytes to short.
+ *
+ * @param one the one
+ * @param two the two
+ * @return the short
+ */
+ public static short bytesToShort(byte one, byte two) {
+ return (short) (((0xFF & one) << 8) | (0xFF & two));
+ }
+
+ /**
+ * First byte.
+ *
+ * @param num the num
+ * @return the byte
+ */
+ // short helper functions
+ static byte firstByte(short num) {
+ return (byte) ((num >> 8) & 0xFF);
+ }
+
+ /**
+ * First byte.
+ *
+ * @param num the num
+ * @return the byte
+ */
+ // Int helper functions
+ static byte firstByte(int num) {
+ return (byte) ((num >> 24) & 0xFF);
+ }
+
+ /**
+ * Second byte.
+ *
+ * @param num the num
+ * @return the byte
+ */
+ static byte secondByte(short num) {
+ return (byte) (num & 0xFF);
+ }
+
+ /**
+ * Second byte.
+ *
+ * @param num the num
+ * @return the byte
+ */
+ static byte secondByte(int num) {
+ return (byte) ((num >> 16) & 0xFF);
+ }
+
+ /**
+ * Third byte.
+ *
+ * @param num the num
+ * @return the byte
+ */
+ static byte thirdByte(int num) {
+ return (byte) ((num >> 8) & 0xFF);
+ }
+
+ /**
+ * Fourth byte.
+ *
+ * @param num the num
+ * @return the byte
+ */
+ static byte fourthByte(int num) {
+ return (byte) (num & 0xFF);
+ }
+
+ /**
+ * Int to byte.
+ *
+ * @param value the value
+ * @return the byte
+ */
+ public static byte intToByte(int value) {
+ return fourthByte(value);
+ }
+
+ /**
+ * Int to short.
+ *
+ * @param value the value
+ * @return the short
+ */
+ public static short intToShort(int value) {
+ return (short) ((value & 0xFF00) | (value & 0xFF));
+ }
+
+}
+
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/util/RestletUtils.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/util/RestletUtils.java
new file mode 100644
index 0000000..26dbf62
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/util/RestletUtils.java
@@ -0,0 +1,119 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.util;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.onap.aai.cl.api.Logger;
+import org.onap.aai.restclient.client.OperationResult;
+import org.onap.aai.sparky.logging.AaiUiMsgs;
+import org.onap.aai.sparky.search.SearchServiceAdapter;
+import org.restlet.Response;
+import org.restlet.data.MediaType;
+import org.restlet.data.Status;
+
+public class RestletUtils {
+ /**
+ * Returns an HttpServletResponse based on values from a Restlet Response
+ *
+ * @param restletResponse Restlet Response to be converted to an HttpServletResponse
+ * @return An HttpServletResponse object built from the values of a Restlet Response
+ */
+ public HttpServletResponse convertRestletResponseToHttpServletResponse(Response restletResponse) {
+ return org.restlet.ext.servlet.ServletUtils.getResponse(restletResponse);
+ }
+
+ /**
+ * Execute post query
+ *
+ * @param logger The logger
+ * @param search The searchAdapter
+ * @param response The response
+ * @param requestUrl The request URL
+ * @param requestJsonPayload The request JSON payload
+ * @return The operation result
+ */
+ public OperationResult executePostQuery(Logger logger, SearchServiceAdapter search,
+ Response response, String requestUrl, String requestJsonPayload) {
+
+ OperationResult opResult = search.doPost(requestUrl, requestJsonPayload, "application/json");
+
+ if (opResult.getResultCode() > 300) {
+ setRestletResponse(logger, true, opResult.getResultCode(), response, opResult.getResult());
+ } else {
+ response.setStatus(new Status(opResult.getResultCode()));
+ }
+
+ return opResult;
+ }
+
+ /**
+ * Generate JSON error response
+ *
+ * @param message The error message
+ * @return The error message formatted as a JSON string
+ */
+ public String generateJsonErrorResponse(String message) {
+ return String.format("{ \"errorMessage\" : \"%s\" }", message);
+ }
+
+ /**
+ * Log Restlet exceptions/errors & prepare Response object with exception/errors info
+ *
+ * @param logger The logger
+ * @param errorMsg The error message
+ * @param exc The exception
+ * @param response The response
+ */
+ public void handleRestletErrors(Logger logger, String errorMsg, Exception exc,
+ Response response) {
+ String errorLogMsg = (exc == null ? errorMsg : errorMsg + ". Error:" + exc.getLocalizedMessage());
+ logger.error(AaiUiMsgs.ERROR_GENERIC, errorLogMsg);
+ response.setEntity(generateJsonErrorResponse(errorMsg), MediaType.APPLICATION_JSON);
+ }
+
+ /**
+ * Sets the Restlet response
+ *
+ * @param logger The logger
+ * @param isError The error
+ * @param responseCode The response code
+ * @param response The response
+ * @param postPayload The post payload
+ */
+ public void setRestletResponse(Logger logger, boolean isError, int responseCode,
+ Response response, String postPayload) {
+
+ if (isError) {
+ logger.error(AaiUiMsgs.ERROR_GENERIC, postPayload);
+ }
+
+ response.setStatus(new Status(responseCode));
+
+ if (postPayload != null) {
+ response.setEntity(postPayload, MediaType.APPLICATION_JSON);
+ }
+ }
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/util/SuggestionsPermutation.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/util/SuggestionsPermutation.java
new file mode 100644
index 0000000..05f6996
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/util/SuggestionsPermutation.java
@@ -0,0 +1,100 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.util;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class SuggestionsPermutation {
+
+ /*
+ * Will return all the unique combinations of the suggestions provided. The order of the
+ * permutation is not taken into account when computing the uniqueness. eg: A list of A,B,C,D will
+ * return [[A], [A, B, C, D], [A, C, D], [A, D], [B], [B, C, D], [B, D], [C], [C, D], [D]]
+ *
+ * @param list The list to create the unique permutations
+ *
+ * @return A Arraylist which contains a array list of all possible combinations
+ */
+ public static ArrayList<ArrayList<String>> getUniqueListForSuggestions(
+ List<String> originalList) {
+ ArrayList<ArrayList<String>> lists = new ArrayList<ArrayList<String>>();
+ if (originalList.isEmpty()) {
+ lists.add(new ArrayList<String>());
+ return lists;
+ }
+ List<String> list = new ArrayList<String>(originalList);
+ String head = list.get(0);
+ ArrayList<String> rest = new ArrayList<String>(list.subList(1, list.size()));
+
+ for (ArrayList<String> activeList : getUniqueListForSuggestions(rest)) {
+ ArrayList<String> newList = new ArrayList<String>();
+ newList.add(head);
+ newList.addAll(activeList);
+ lists.add(newList);
+ lists.add(activeList);
+ }
+ return lists;
+ }
+
+ public static ArrayList<ArrayList<String>> getNonEmptyUniqueLists(List<String> list){
+ ArrayList<ArrayList<String>> lists = getUniqueListForSuggestions(list);
+ // remove empty list from the power set
+ for (ArrayList<String> emptyList : lists ){
+ if ( emptyList.isEmpty() ) {
+ lists.remove(emptyList);
+ break;
+ }
+ }
+ return lists;
+ }
+
+ public static List<List<String>> getListPermutations(List<String> list) {
+ List<String> inputList = new ArrayList<String>();
+ inputList.addAll(list);
+ if (inputList.size() == 0) {
+ List<List<String>> result = new ArrayList<List<String>>();
+ result.add(new ArrayList<String>());
+ return result;
+ }
+
+ List<List<String>> listOfLists = new ArrayList<List<String>>();
+
+ String firstElement = inputList.remove(0);
+
+ List<List<String>> recursiveReturn = getListPermutations(inputList);
+ for (List<String> li : recursiveReturn) {
+
+ for (int index = 0; index <= li.size(); index++) {
+ List<String> temp = new ArrayList<String>(li);
+ temp.add(index, firstElement);
+ listOfLists.add(temp);
+ }
+
+ }
+ return listOfLists;
+ }
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/util/TreeWalker.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/util/TreeWalker.java
new file mode 100644
index 0000000..d8bb7b9
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/util/TreeWalker.java
@@ -0,0 +1,136 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.util;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.common.collect.Lists;
+
+/**
+ * The Class TreeWalker.
+ */
+public class TreeWalker {
+
+ /**
+ * Convert json to node.
+ *
+ * @param json the json
+ * @return the json node
+ * @throws JsonProcessingException the json processing exception
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public JsonNode convertJsonToNode(String json) throws JsonProcessingException, IOException {
+ ObjectMapper mapper = new ObjectMapper();
+
+ if (json == null) {
+ return null;
+ }
+
+ return mapper.readTree(json);
+
+ }
+
+ /**
+ * Walk tree.
+ *
+ * @param paths the paths
+ * @param root the root
+ */
+ public void walkTree(List<String> paths, JsonNode root) {
+ walker(paths, null, root);
+ }
+
+ /**
+ * Walker.
+ *
+ * @param paths the paths
+ * @param nodename the nodename
+ * @param node the node
+ */
+ private void walker(List<String> paths, String nodename, JsonNode node) {
+
+ if (node == null) {
+ return;
+ }
+
+ /*
+ * if ( nodename != null ) { paths.add(nodename); }
+ */
+
+ // System.out.println("path: " + nameToPrint);
+ if (node.isObject()) {
+ Iterator<Map.Entry<String, JsonNode>> iterator = node.fields();
+
+ ArrayList<Map.Entry<String, JsonNode>> nodesList = Lists.newArrayList(iterator);
+ // System.out.println("Walk Tree - root:" + node + ", elements
+ // keys:" + nodesList);
+
+ if (nodesList.isEmpty()) {
+
+ if (nodename != null) {
+ paths.add(nodename);
+ }
+
+ } else {
+
+ for (Map.Entry<String, JsonNode> nodEntry : nodesList) {
+ String name = nodEntry.getKey();
+ JsonNode newNode = nodEntry.getValue();
+
+ if (newNode.isValueNode()) {
+ if (nodename == null) {
+ paths.add(name + "=" + newNode.asText());
+ } else {
+ paths.add(nodename + "." + name + "=" + newNode.asText());
+ }
+ } else {
+
+ if (nodename == null) {
+ walker(paths, name, newNode);
+ } else {
+ walker(paths, nodename + "." + name, newNode);
+ }
+ }
+
+ }
+ }
+ } else if (node.isArray()) {
+ Iterator<JsonNode> arrayItemsIterator = node.elements();
+ ArrayList<JsonNode> arrayItemsList = Lists.newArrayList(arrayItemsIterator);
+ for (JsonNode arrayNode : arrayItemsList) {
+ walker(paths, nodename, arrayNode);
+ }
+ } else if (node.isValueNode()) {
+ paths.add(nodename + "=" + node.asText());
+ }
+ }
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/EntityTypeAggregation.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/EntityTypeAggregation.java
new file mode 100644
index 0000000..c6d4666
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/EntityTypeAggregation.java
@@ -0,0 +1,61 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.viewandinspect;
+
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicInteger;
+
+
+
+
+/**
+ * The Class EntityTypeAggregation.
+ */
+public class EntityTypeAggregation {
+
+ private ConcurrentHashMap<String, AtomicInteger> counters;
+
+ /**
+ * Instantiates a new entity type aggregation.
+ */
+ public EntityTypeAggregation() {
+ counters = new ConcurrentHashMap<String, AtomicInteger>();
+ }
+
+ /**
+ * Peg counter.
+ *
+ * @param counterName the counter name
+ */
+ public void pegCounter(String counterName) {
+ counters.putIfAbsent(counterName, new AtomicInteger(0));
+ counters.get(counterName).incrementAndGet();
+ }
+
+ public ConcurrentHashMap<String, AtomicInteger> getCounters() {
+ return counters;
+ }
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/SchemaVisualizationProcessor.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/SchemaVisualizationProcessor.java
new file mode 100644
index 0000000..0133c9d
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/SchemaVisualizationProcessor.java
@@ -0,0 +1,99 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.viewandinspect;
+
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.camel.Exchange;
+import org.onap.aai.cl.api.Logger;
+import org.onap.aai.cl.eelf.LoggerFactory;
+import org.onap.aai.restclient.client.OperationResult;
+import org.onap.aai.sparky.logging.AaiUiMsgs;
+import org.onap.aai.sparky.logging.util.ServletUtils;
+import org.onap.aai.sparky.viewandinspect.entity.QueryRequest;
+import org.onap.aai.sparky.viewandinspect.services.VisualizationService;
+import org.restlet.data.Status;
+
+public class SchemaVisualizationProcessor {
+
+
+ private static final Logger LOG =
+ LoggerFactory.getInstance().getLogger(SchemaVisualizationProcessor.class);
+
+ private VisualizationService visualizationService;
+
+ public SchemaVisualizationProcessor()throws Exception{}
+
+ protected String generateJsonErrorResponse(String message) {
+ return String.format("{ \"errorMessage\" : %s }", message);
+ }
+
+ public void setVisualizationService(VisualizationService visualizationService){
+ this.visualizationService = visualizationService;
+ }
+ public VisualizationService getVisualizationService(){
+ return visualizationService;
+ }
+
+ public void processVisualizationRequest(Exchange exchange) {
+
+ HttpServletRequest request = exchange.getIn().getBody(HttpServletRequest.class);
+ ServletUtils.setUpMdcContext(exchange, request);
+
+ QueryRequest hashId = null;
+ OperationResult operationResult = null;
+
+ String visualizationPayload = exchange.getIn().getBody(String.class);
+ hashId = this.getVisualizationService().analyzeQueryRequestBody(visualizationPayload);
+
+ if (hashId != null) {
+
+ operationResult = this.getVisualizationService().buildVisualizationUsingGenericQuery(hashId);
+
+ if (operationResult.getResultCode() != Status.SUCCESS_OK.getCode()) {
+ exchange.getOut().setHeader(Exchange.HTTP_RESPONSE_CODE, operationResult.getResultCode());
+ LOG.error(AaiUiMsgs.FAILURE_TO_PROCESS_REQUEST, String
+ .format("Failed to process Visualization Schema Payload = '%s'", visualizationPayload));
+ return;
+ }
+
+ } else {
+ operationResult = new OperationResult();
+ operationResult.setResult(String
+ .format("Failed to analyze Visualization Schema Payload = '%s'", visualizationPayload));
+ exchange.getOut().setHeader(Exchange.HTTP_RESPONSE_CODE, operationResult.getResultCode());
+ LOG.error(AaiUiMsgs.FAILED_TO_ANALYZE, String
+ .format("Failed to analyze Visualization Schema Payload = '%s'", visualizationPayload));
+ return;
+
+ }
+
+ exchange.getOut().setHeader(Exchange.HTTP_RESPONSE_CODE, operationResult.getResultCode());
+ exchange.getOut().setBody(operationResult.getResult());
+
+ }
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/config/SparkyConstants.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/config/SparkyConstants.java
new file mode 100644
index 0000000..5624b20
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/config/SparkyConstants.java
@@ -0,0 +1,102 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.viewandinspect.config;
+
+/**
+ * The Class TierSupportUiConstants.
+ */
+public class SparkyConstants {
+
+ public static String APP_NAME = "AAIUI";
+
+ /** Default to unix file separator if system property file.separator is null */
+ public static final String FILESEP =
+ (System.getProperty("file.separator") == null) ? "/" : System.getProperty("file.separator");
+
+ public static String CONFIG_HOME = System.getProperty("CONFIG_HOME") + FILESEP;
+ public static String DYNAMIC_CONFIG_APP_LOCATION = CONFIG_HOME;
+
+ public static String CONFIG_OXM_LOCATION = CONFIG_HOME + "model" + FILESEP;
+ public static String CONFIG_FILTERS_BASE_LOCATION = CONFIG_HOME + FILESEP;
+ //public static String CONFIG_AUTH_LOCATION = CONFIG_HOME + "auth" + FILESEP;
+
+ public static String HOST = "host";
+ public static String IP_ADDRESS = "ipAddress";
+ public static String PORT = "port";
+ public static String HTTP_PORT = "httpPort";
+ public static String RETRIES = "numRequestRetries";
+ public static String RESOURCE_VERSION = "resource-version";
+ public static String URI = "URI";
+
+ public static String AUTHORIZED_USERS_FILE_LOCATION = DYNAMIC_CONFIG_APP_LOCATION + "authorized-users.config";
+ public static String USERS_FILE_LOCATION = DYNAMIC_CONFIG_APP_LOCATION + "users.config";
+ public static String ROLES_FILE_LOCATION = DYNAMIC_CONFIG_APP_LOCATION + "roles.config";
+ public static String PORTAL_AUTHENTICATION_FILE_LOCATION = DYNAMIC_CONFIG_APP_LOCATION + "portal" + FILESEP + "portal-authentication.properties";
+
+ // Related to data-router properties
+ public static String DR_URI_SUFFIX = "uriSuffix";
+ public static String DR_CERT_NAME = "cert-name";
+ public static String DR_KEYSTORE_PASSWORD = "keystore-password";
+ public static String DR_KEYSTORE = "keystore";
+ public static String DR_CONNECT_TIMEOUT = "connectTimeoutMs";
+ public static String DR_READ_TIMEOUT = "readTimeoutMs";
+
+ public static final String APP_JSON = "application/json";
+
+ public static final String ES_SUGGEST_API = "_suggest";
+ public static final String ES_COUNT_API = "_count";
+ public static final String ES_SEARCH_API = "_search";
+
+ public static final String UI_FILTER_VIEW_NAME_PARAMETER = "viewName";
+ public static final String UI_FILTER_ID_LIST_PARAMETER = "filterIdList";
+
+ public static final String ENTITY_AUTO_SUGGEST_INDEX_NAME_DEFAULT =
+ "entityautosuggestindex-localhost";
+ public static final String ENTITY_AUTO_SUGGEST_SETTINGS_FILE_DEFAULT =
+ "/etc/autoSuggestSettings.json";
+ public static final String ENTITY_AUTO_SUGGEST_MAPPINGS_FILE_DEFAULT =
+ "/etc/autoSuggestMappings.json";
+ public static final String ENTITY_DYNAMIC_MAPPINGS_FILE_DEFAULT =
+ "/etc/dynamicMappings.json";
+ /*public static final String FILTER_LIST_FILE_DEFAULT =
+ CONFIG_FILTERS_BASE_LOCATION + "filters" + FILESEP + "aaiui_filters.json";
+ public static final String FILTER_MAPPING_FILE_DEFAULT =
+ CONFIG_FILTERS_BASE_LOCATION + "filters" + FILESEP + "aaiui_views.json";*/
+
+ public static final String SUBSCRIPTION_OI_MAPPING =
+ CONFIG_FILTERS_BASE_LOCATION + "subscription_object_inspector_mapping.json";
+
+ public static final String SUGGESTION_TEXT_SEPARATOR = " -- ";
+
+ // Injected Attributes
+ public static String URI_ATTR_NAME = "uri";
+
+ public static final String URI_VERSION_REGEX_PATTERN = "aai/v[\\d]+/";
+
+ public static final String getConfigPath(String configFile){
+ return CONFIG_HOME + FILESEP + configFile;
+ }
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/config/TierSupportUiConstants.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/config/TierSupportUiConstants.java
new file mode 100644
index 0000000..e0cc9c6
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/config/TierSupportUiConstants.java
@@ -0,0 +1,102 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.viewandinspect.config;
+
+/**
+ * The Class TierSupportUiConstants.
+ */
+public class TierSupportUiConstants {
+
+ public static String APP_NAME = "AAIUI";
+
+ /** Default to unix file separator if system property file.separator is null */
+ public static final String FILESEP =
+ (System.getProperty("file.separator") == null) ? "/" : System.getProperty("file.separator");
+
+ public static String CONFIG_HOME = System.getProperty("CONFIG_HOME") + FILESEP;
+ public static String AJSC_HOME = System.getProperty("AJSC_HOME") + FILESEP;
+ public static String CONFIG_ROOT_LOCATION =
+ AJSC_HOME + "bundleconfig" + FILESEP + "etc" + FILESEP;
+ public static String STATIC_CONFIG_APP_LOCATION = CONFIG_ROOT_LOCATION + "appprops" + FILESEP;
+ public static String DYNAMIC_CONFIG_APP_LOCATION = CONFIG_HOME;
+
+ public static String CONFIG_OXM_LOCATION = CONFIG_HOME + "model" + FILESEP;
+ public static String CONFIG_FILTERS_BASE_LOCATION = CONFIG_HOME + FILESEP;
+ public static String CONFIG_AUTH_LOCATION = CONFIG_HOME + "auth" + FILESEP;
+
+ public static String HOST = "host";
+ public static String IP_ADDRESS = "ipAddress";
+ public static String PORT = "port";
+ public static String HTTP_PORT = "httpPort";
+ public static String RETRIES = "numRequestRetries";
+ public static String RESOURCE_VERSION = "resource-version";
+ public static String URI = "URI";
+
+ public static String AUTHORIZED_USERS_FILE_LOCATION =
+ DYNAMIC_CONFIG_APP_LOCATION + "authorized-users.config";
+ public static String USERS_FILE_LOCATION = DYNAMIC_CONFIG_APP_LOCATION + "users.config";
+ public static String ROLES_FILE_LOCATION = DYNAMIC_CONFIG_APP_LOCATION + "roles.config";
+ public static String PORTAL_AUTHENTICATION_FILE_LOCATION =
+ DYNAMIC_CONFIG_APP_LOCATION + "portal" + FILESEP + "portal-authentication.properties";
+
+ // Related to data-router properties
+ public static String DR_URI_SUFFIX = "uriSuffix";
+ public static String DR_CERT_NAME = "cert-name";
+ public static String DR_KEYSTORE_PASSWORD = "keystore-password";
+ public static String DR_KEYSTORE = "keystore";
+ public static String DR_CONNECT_TIMEOUT = "connectTimeoutMs";
+ public static String DR_READ_TIMEOUT = "readTimeoutMs";
+
+ public static final String ES_SUGGEST_API = "_suggest";
+ public static final String ES_COUNT_API = "_count";
+ public static final String ES_SEARCH_API = "_search";
+
+ public static final String UI_FILTER_VIEW_NAME_PARAMETER = "viewName";
+ public static final String UI_FILTER_ID_LIST_PARAMETER = "filterIdList";
+
+ public static final String ENTITY_AUTO_SUGGEST_INDEX_NAME_DEFAULT =
+ "entityautosuggestindex-localhost";
+ public static final String ENTITY_AUTO_SUGGEST_SETTINGS_FILE_DEFAULT =
+ "/etc/autoSuggestSettings.json";
+ public static final String ENTITY_AUTO_SUGGEST_MAPPINGS_FILE_DEFAULT =
+ "/etc/autoSuggestMappings.json";
+ public static final String ENTITY_DYNAMIC_MAPPINGS_FILE_DEFAULT = "/etc/dynamicMappings.json";
+ public static final String FILTER_LIST_FILE_DEFAULT =
+ CONFIG_FILTERS_BASE_LOCATION + "filters" + FILESEP + "aaiui_filters.json";
+ public static final String FILTER_MAPPING_FILE_DEFAULT =
+ CONFIG_FILTERS_BASE_LOCATION + "filters" + FILESEP + "aaiui_views.json";
+
+ public static final String SUGGESTION_TEXT_SEPARATOR = " -- ";
+
+ // Injected Attributes
+ public static String URI_ATTR_NAME = "uri";
+
+ public static final String URI_VERSION_REGEX_PATTERN = "aai/v[\\d]+/";
+
+ public static final String getConfigPath(String configFile) {
+ return AJSC_HOME + FILESEP + configFile;
+ }
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/config/VisualizationConfigs.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/config/VisualizationConfigs.java
new file mode 100644
index 0000000..169dbc6
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/config/VisualizationConfigs.java
@@ -0,0 +1,174 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.viewandinspect.config;
+
+import java.util.ArrayList;
+
+import org.onap.aai.sparky.config.SparkyResourceLoader;
+
+/**
+ * The Class VisualizationConfig.
+ */
+public class VisualizationConfigs {
+
+ private int maxSelfLinkTraversalDepth;
+
+ private boolean visualizationDebugEnabled;
+
+ private String aaiEntityNodeDescriptors;
+
+ private String generalNodeClassName;
+
+ private String searchNodeClassName;
+
+ private String selectedSearchedNodeClassName;
+
+ private int numOfThreadsToFetchNodeIntegrity;
+
+ private boolean makeAllNeighborsBidirectional;
+
+ private ArrayList<String> shallowEntities;
+
+ private boolean gizmoEnabled;
+
+ private SparkyResourceLoader resourceLoader;
+
+ /**
+ * Instantiates a new visualization config.
+ */
+ public VisualizationConfigs() {
+ this.gizmoEnabled = false;
+ }
+
+ public ArrayList<String> getShallowEntities() {
+ return shallowEntities;
+ }
+
+ public void setShallowEntities(ArrayList<String> shallowEntities) {
+ this.shallowEntities = shallowEntities;
+ }
+
+ /**
+ * Make all neighbors bidirectional.
+ *
+ * @return true, if successful
+ */
+ public boolean makeAllNeighborsBidirectional() {
+ return makeAllNeighborsBidirectional;
+ }
+
+ public void setMakeAllNeighborsBidirectional(boolean makeAllNeighborsBidirectional) {
+ this.makeAllNeighborsBidirectional = makeAllNeighborsBidirectional;
+ }
+
+ public String getSelectedSearchedNodeClassName() {
+ return selectedSearchedNodeClassName;
+ }
+
+ public void setSelectedSearchedNodeClassName(String selectedSearchedNodeClassName) {
+ this.selectedSearchedNodeClassName = selectedSearchedNodeClassName;
+ }
+
+ public String getGeneralNodeClassName() {
+ return generalNodeClassName;
+ }
+
+ public void setGeneralNodeClassName(String generalNodeClassName) {
+ this.generalNodeClassName = generalNodeClassName;
+ }
+
+ public String getSearchNodeClassName() {
+ return searchNodeClassName;
+ }
+
+ public void setSearchNodeClassName(String searchNodeClassName) {
+ this.searchNodeClassName = searchNodeClassName;
+ }
+
+ public String getAaiEntityNodeDescriptors() {
+ return aaiEntityNodeDescriptors;
+ }
+
+ public void setAaiEntityNodeDescriptors(String aaiEntityNodeDescriptors) {
+ this.aaiEntityNodeDescriptors = aaiEntityNodeDescriptors;
+ }
+
+ public boolean isVisualizationDebugEnabled() {
+ return visualizationDebugEnabled;
+ }
+
+ public void setVisualizationDebugEnabled(boolean visualizationDebugEnabled) {
+ this.visualizationDebugEnabled = visualizationDebugEnabled;
+ }
+
+ public void setMaxSelfLinkTraversalDepth(int maxSelfLinkTraversalDepth) {
+ this.maxSelfLinkTraversalDepth = maxSelfLinkTraversalDepth;
+ }
+
+ public int getMaxSelfLinkTraversalDepth() {
+ return maxSelfLinkTraversalDepth;
+ }
+
+ public int getNumOfThreadsToFetchNodeIntegrity() {
+ return numOfThreadsToFetchNodeIntegrity;
+ }
+
+ public void setNumOfThreadsToFetchNodeIntegrity(int numOfThreadsToFetchNodeIntegrity) {
+ this.numOfThreadsToFetchNodeIntegrity = numOfThreadsToFetchNodeIntegrity;
+ }
+
+ public boolean isGizmoEnabled() {
+ return gizmoEnabled;
+ }
+
+ public void setGizmoEnabled(boolean gizmoEnabled) {
+ this.gizmoEnabled = gizmoEnabled;
+ }
+
+ public SparkyResourceLoader getResourceLoader() {
+ return resourceLoader;
+ }
+
+ public void setResourceLoader(SparkyResourceLoader resourceLoader) {
+ this.resourceLoader = resourceLoader;
+ }
+
+ @Override
+ public String toString() {
+ return "VisualizationConfigs [maxSelfLinkTraversalDepth=" + maxSelfLinkTraversalDepth
+ + ", visualizationDebugEnabled=" + visualizationDebugEnabled + ", "
+ + (aaiEntityNodeDescriptors != null ? "aaiEntityNodeDescriptors=" + aaiEntityNodeDescriptors + ", "
+ : "")
+ + (generalNodeClassName != null ? "generalNodeClassName=" + generalNodeClassName + ", " : "")
+ + (searchNodeClassName != null ? "searchNodeClassName=" + searchNodeClassName + ", " : "")
+ + (selectedSearchedNodeClassName != null
+ ? "selectedSearchedNodeClassName=" + selectedSearchedNodeClassName + ", " : "")
+ + "numOfThreadsToFetchNodeIntegrity=" + numOfThreadsToFetchNodeIntegrity
+ + ", makeAllNeighborsBidirectional=" + makeAllNeighborsBidirectional + ", "
+ + (shallowEntities != null ? "shallowEntities=" + shallowEntities + ", " : "") + "gizmoEnabled="
+ + gizmoEnabled + "]";
+ }
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/ActiveInventoryNode.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/ActiveInventoryNode.java
new file mode 100644
index 0000000..3981626
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/ActiveInventoryNode.java
@@ -0,0 +1,831 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.viewandinspect.entity;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.concurrent.ConcurrentLinkedDeque;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.onap.aai.cl.api.Logger;
+import org.onap.aai.cl.eelf.LoggerFactory;
+import org.onap.aai.restclient.client.OperationResult;
+import org.onap.aai.sparky.config.oxm.OxmEntityLookup;
+import org.onap.aai.sparky.config.oxm.OxmModelLoader;
+import org.onap.aai.sparky.logging.AaiUiMsgs;
+import org.onap.aai.sparky.viewandinspect.config.VisualizationConfigs;
+import org.onap.aai.sparky.viewandinspect.enumeration.NodeProcessingAction;
+import org.onap.aai.sparky.viewandinspect.enumeration.NodeProcessingState;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+/**
+ * The Class ActiveInventoryNode.
+ */
+public class ActiveInventoryNode {
+
+ private static final Logger LOG = LoggerFactory.getInstance().getLogger(
+ ActiveInventoryNode.class);
+ private static final String URIRegexPattern = "aai/v[\\d]/";
+
+ public static final int DEFAULT_INIT_NODE_DEPTH = 1000;
+
+ private String nodeId;
+ private String selfLink;
+
+ private boolean isRootNode;
+ private ConcurrentLinkedDeque<String> inboundNeighbors;
+ private ConcurrentLinkedDeque<String> outboundNeighbors;
+
+ private ConcurrentLinkedDeque<String> inboundNeighborSelfLinks;
+ private ConcurrentLinkedDeque<String> outboundNeighborSelfLinks;
+
+ private List<JsonNode> complexGroups;
+ private List<RelationshipList> relationshipLists;
+ private int nodeDepth;
+ private OperationResult opResult;
+
+ private boolean processingErrorOccurred;
+ private List<String> errorCauses;
+ private boolean selflinkRetrievalFailure;
+ private NodeProcessingState state;
+
+ private boolean processedNeighbors;
+
+ private boolean selfLinkPendingResolve;
+
+ /*
+ * I think we shouldn't be using this crutch flags. If these things are meant
+ * to represent the current state of the node, then they should be legitimate
+ * state transitions.
+ */
+
+ private boolean selfLinkDeterminationPending;
+
+ private AtomicBoolean selfLinkProcessed;
+ private AtomicBoolean nodeIntegrityProcessed;
+
+ private OxmModelLoader oxmModelLoader;
+ private VisualizationConfigs visualizationConfigs;
+
+ private String entityType;
+ private String primaryKeyName;
+ private String primaryKeyValue;
+
+ private boolean nodeValidated;
+ private boolean nodeIssue;
+ private boolean ignoredByFilter;
+
+ private boolean resolvedSelfLink;
+
+ private Map<String, String> properties;
+ private ArrayList<String> queryParams;
+
+ private ObjectMapper mapper;
+
+ private OxmEntityLookup oxmEntityLookup;
+
+ /**
+ * Instantiates a new active inventory node.
+ *
+ * @param key the key
+ */
+ public ActiveInventoryNode(VisualizationConfigs visualizationConfigs, OxmEntityLookup oxmEntityLookup) {
+ this.oxmEntityLookup = oxmEntityLookup;
+ this.nodeId = null;
+ this.entityType = null;
+ this.selfLink = null;
+ this.properties = new HashMap<String, String>();
+ this.processingErrorOccurred = false;
+ this.errorCauses = new ArrayList<String>();
+ this.selflinkRetrievalFailure = false;
+ this.nodeIssue = false;
+ this.nodeValidated = false;
+ this.state = NodeProcessingState.INIT;
+ this.selfLinkPendingResolve = false;
+ this.selfLinkDeterminationPending = false;
+
+ selfLinkProcessed = new AtomicBoolean(Boolean.FALSE);
+ nodeIntegrityProcessed = new AtomicBoolean(Boolean.FALSE);
+ oxmModelLoader = null;
+ this.visualizationConfigs = visualizationConfigs ;
+
+ isRootNode = false;
+ inboundNeighbors = new ConcurrentLinkedDeque<String>();
+ outboundNeighbors = new ConcurrentLinkedDeque<String>();
+
+ inboundNeighborSelfLinks = new ConcurrentLinkedDeque<String>();
+ outboundNeighborSelfLinks = new ConcurrentLinkedDeque<String>();
+
+ complexGroups = new ArrayList<JsonNode>();
+ relationshipLists = new ArrayList<RelationshipList>();
+ nodeDepth = DEFAULT_INIT_NODE_DEPTH;
+ queryParams = new ArrayList<String>();
+
+ mapper = new ObjectMapper();
+
+ processedNeighbors = false;
+ resolvedSelfLink = false;
+
+
+ }
+
+ public void clearQueryParams() {
+ queryParams.clear();
+ }
+
+ public void addQueryParam(String queryParam) {
+ if ( queryParam!= null) {
+ if( !queryParams.contains(queryParam)) {
+ queryParams.add(queryParam);
+ }
+ }
+ }
+
+ public void addInboundSelfLink(String link) {
+
+ if (link == null) {
+ return;
+ }
+
+ if (!inboundNeighborSelfLinks.contains(link)) {
+ inboundNeighborSelfLinks.add(link);
+ }
+
+ }
+
+ public void addOutboundSelfLink(String link) {
+
+ if (link == null) {
+ return;
+ }
+
+ if (!outboundNeighborSelfLinks.contains(link)) {
+ outboundNeighborSelfLinks.add(link);
+ }
+
+ }
+
+ public Collection<String> getInboundNeighborSelfLinks() {
+ return inboundNeighborSelfLinks;
+ }
+
+ public Collection<String> getOutboundNeighborSelfLinks() {
+ return outboundNeighborSelfLinks;
+ }
+
+ public void addQueryParams(Collection<String> params) {
+
+ if (params != null & params.size() > 0) {
+
+ for (String param : params) {
+ addQueryParam(param);
+ }
+ }
+ }
+
+
+ public List<String> getQueryParams() {
+ return queryParams;
+ }
+
+ public void setSelfLinkDeterminationPending(boolean selfLinkDeterminationPending) {
+ this.selfLinkDeterminationPending = selfLinkDeterminationPending;
+ }
+
+ public boolean isSelfLinkDeterminationPending() {
+ return selfLinkDeterminationPending;
+ }
+
+ public NodeProcessingState getState() {
+ return state;
+ }
+
+ public List<JsonNode> getComplexGroups() {
+ return complexGroups;
+ }
+
+ public List<RelationshipList> getRelationshipLists() {
+ return relationshipLists;
+ }
+
+ public OperationResult getOpResult() {
+ return opResult;
+ }
+
+ public void setOpResult(OperationResult opResult) {
+ this.opResult = opResult;
+ }
+
+ public String getPrimaryKeyName() {
+ return primaryKeyName;
+ }
+
+ /**
+ * Gets the visualization config.
+ *
+ * @return the visualization config
+ */
+ public VisualizationConfigs getvisualizationConfigs() {
+ return visualizationConfigs;
+ }
+
+ public int getNodeDepth() {
+ return nodeDepth;
+ }
+
+ public void setNodeDepth(int nodeDepth) {
+ this.nodeDepth = nodeDepth;
+ }
+
+ /**
+ * Sets the visualization config.
+ *
+ * @param visualizationConfig the new visualization config
+ */
+ public void setvisualizationConfig(VisualizationConfigs visualizationConfigs) {
+ this.visualizationConfigs = visualizationConfigs;
+ }
+
+ public OxmModelLoader getOxmModelLoader() {
+ return oxmModelLoader;
+ }
+
+ public void setPrimaryKeyName(String primaryKeyName) {
+ this.primaryKeyName = primaryKeyName;
+ }
+
+ public String getPrimaryKeyValue() {
+ return primaryKeyValue;
+ }
+
+ public void setPrimaryKeyValue(String primaryKeyValue) {
+ this.primaryKeyValue = primaryKeyValue;
+ }
+
+ public boolean isNodeValidated() {
+ return nodeValidated;
+ }
+
+ public void setNodeValidated(boolean nodeValidated) {
+ this.nodeValidated = nodeValidated;
+ }
+
+ public boolean isNodeIssue() {
+ return nodeIssue;
+ }
+
+ public boolean isIgnoredByFilter() {
+ return ignoredByFilter;
+ }
+
+ public void setIgnoredByFilter(boolean ignoredByFilter) {
+ this.ignoredByFilter = ignoredByFilter;
+ }
+
+ public void setNodeIssue(boolean nodeIssue) {
+ this.nodeIssue = nodeIssue;
+ }
+
+ /**
+ * Checks for processed neighbors.
+ *
+ * @return true, if successful
+ */
+ public boolean hasProcessedNeighbors() {
+ return processedNeighbors;
+ }
+
+ public void setProcessedNeighbors(boolean processedNeighbors) {
+ this.processedNeighbors = processedNeighbors;
+ }
+
+ /**
+ * Checks for resolved self link.
+ *
+ * @return true, if successful
+ */
+ public boolean hasResolvedSelfLink() {
+ return resolvedSelfLink;
+ }
+
+ public void setResolvedSelfLink(boolean resolvedSelfLink) {
+ this.resolvedSelfLink = resolvedSelfLink;
+ }
+
+ /**
+ * Checks for neighbors.
+ *
+ * @return true, if successful
+ */
+ public boolean hasNeighbors() {
+ return (inboundNeighbors.size() > 0 || outboundNeighbors.size() > 0);
+ }
+
+ /**
+ * Adds the inbound neighbor.
+ *
+ * @param nodeId the node id
+ */
+ public void addInboundNeighbor(String nodeId) {
+
+ if (nodeId == null) {
+ return;
+ }
+
+ if (!inboundNeighbors.contains(nodeId)) {
+ inboundNeighbors.add(nodeId);
+ }
+
+ }
+
+ /**
+ * Adds the outbound neighbor.
+ *
+ * @param nodeId the node id
+ */
+ public void addOutboundNeighbor(String nodeId) {
+
+ if (nodeId == null) {
+ return;
+ }
+
+ if (!outboundNeighbors.contains(nodeId)) {
+ outboundNeighbors.add(nodeId);
+ }
+
+ }
+
+ public boolean isAtMaxDepth() {
+ return (nodeDepth >= this.visualizationConfigs.getMaxSelfLinkTraversalDepth());
+ }
+
+ public ConcurrentLinkedDeque<String> getInboundNeighbors() {
+ return inboundNeighbors;
+ }
+
+ public void setInboundNeighbors(ConcurrentLinkedDeque<String> inboundNeighbors) {
+ this.inboundNeighbors = inboundNeighbors;
+ }
+
+ public Collection<String> getOutboundNeighbors() {
+ List<String> result = new ArrayList<String>();
+
+ Iterator<String> neighborIterator = outboundNeighbors.iterator();
+
+ while (neighborIterator.hasNext()) {
+ result.add(neighborIterator.next());
+ }
+
+ return result;
+ }
+
+ /**
+ * Change depth.
+ *
+ * @param newDepth the new depth
+ * @return true, if successful
+ */
+ public boolean changeDepth(int newDepth) {
+
+ boolean nodeDepthWasChanged = false;
+
+ if (newDepth < nodeDepth) {
+ LOG.info(AaiUiMsgs.ACTIVE_INV_NODE_CHANGE_DEPTH, nodeId,
+ String.valueOf(this.nodeDepth), String.valueOf(newDepth));
+ this.nodeDepth = newDepth;
+ nodeDepthWasChanged = true;
+ }
+
+ return nodeDepthWasChanged;
+
+ }
+
+ public void setOutboundNeighbors(ConcurrentLinkedDeque<String> outboundNeighbors) {
+ this.outboundNeighbors = outboundNeighbors;
+ }
+
+ public boolean isRootNode() {
+ return isRootNode;
+ }
+
+ public void setRootNode(boolean isRootNode) {
+ this.isRootNode = isRootNode;
+ }
+
+ /**
+ * Change state.
+ *
+ * @param newState the new state
+ * @param action the action
+ */
+ public void changeState(NodeProcessingState newState, NodeProcessingAction action) {
+ /*
+ * NodeId may be null depending on the current node life-cycle state
+ */
+
+ if (getNodeId() != null) {
+ LOG.info(AaiUiMsgs.ACTIVE_INV_NODE_CHANGE_STATE, state.toString(), newState.toString(), action.toString());
+ } else {
+ LOG.info(AaiUiMsgs.ACTIVE_INV_NODE_CHANGE_STATE_NO_NODE_ID, state.toString(), newState.toString(), action.toString());
+ }
+ this.state = newState;
+ }
+
+ public boolean isSelfLinkPendingResolve() {
+ return selfLinkPendingResolve;
+ }
+
+ public void setSelfLinkPendingResolve(boolean selfLinkPendingResolve) {
+ this.selfLinkPendingResolve = selfLinkPendingResolve;
+ }
+
+ public boolean isSelflinkRetrievalFailure() {
+ return selflinkRetrievalFailure;
+ }
+
+ public void setSelflinkRetrievalFailure(boolean selflinkRetrievalFailure) {
+ this.selflinkRetrievalFailure = selflinkRetrievalFailure;
+ }
+
+ public void setOxmModelLoader(OxmModelLoader loader) {
+ this.oxmModelLoader = loader;
+ }
+
+ public boolean getSelfLinkProcessed() {
+ return selfLinkProcessed.get();
+ }
+
+ public void setSelfLinkProcessed(boolean selfLinkProcessed) {
+ this.selfLinkProcessed.set(selfLinkProcessed);
+ }
+
+ public boolean getNodeIntegrityProcessed() {
+ return nodeIntegrityProcessed.get();
+ }
+
+ public void setNodeIntegrityProcessed(boolean nodeIntegrityProcessed) {
+ this.nodeIntegrityProcessed.set(nodeIntegrityProcessed);
+ }
+
+ public boolean isDirectSelfLink() {
+ return isDirectSelfLink(this.selfLink);
+ }
+
+ /**
+ * Checks if is direct self link.
+ *
+ * @param link the link
+ * @return true, if is direct self link
+ */
+ public static boolean isDirectSelfLink(String link) {
+
+ if (link == null) {
+ return false;
+ }
+
+ return link.contains("/resources/id/");
+
+ }
+
+ public Map<String, String> getProperties() {
+ return properties;
+ }
+
+ /**
+ * Adds the error cause.
+ *
+ * @param error the error
+ */
+ public void addErrorCause(String error) {
+ if (!errorCauses.contains(error)) {
+ errorCauses.add(error);
+ }
+ }
+
+ /**
+ * Adds the property.
+ *
+ * @param key the key
+ * @param value the value
+ */
+ public void addProperty(String key, String value) {
+ properties.put(key, value);
+ }
+
+ public boolean isProcessingErrorOccurred() {
+ return processingErrorOccurred;
+ }
+
+ public void setProcessingErrorOccurred(boolean processingErrorOccurred) {
+ this.processingErrorOccurred = processingErrorOccurred;
+ }
+
+ public String getNodeId() {
+ return nodeId;
+ }
+
+ public void setNodeId(String nodeId) {
+ this.nodeId = nodeId;
+ }
+
+ public String getEntityType() {
+ return entityType;
+ }
+
+ public void setEntityType(String entityType) {
+ this.entityType = entityType;
+ }
+
+ public String getSelfLink() {
+ return selfLink;
+ }
+
+ /**
+ * Calculate edit attribute uri.
+ *
+ * @param link the link
+ * @return the string
+ */
+ public String calculateEditAttributeUri(String link) {
+ String uri = null;
+ Pattern pattern = Pattern.compile(URIRegexPattern);
+ Matcher matcher = pattern.matcher(link);
+ if (matcher.find()) {
+ uri = link.substring(matcher.end());
+ }
+ return uri;
+ }
+
+ /**
+ * Analyze self link relationship list.
+ *
+ * @param jsonResult the json result
+ * @return the relationship list
+ */
+ private RelationshipList analyzeSelfLinkRelationshipList(String jsonResult) {
+
+
+ RelationshipList relationshipList = null;
+
+ try {
+ relationshipList = mapper.readValue(jsonResult, RelationshipList.class);
+ } catch (Exception exc) {
+ LOG.error(AaiUiMsgs.SELF_LINK_RELATIONSHIP_LIST_ERROR, exc.toString());
+ }
+
+ return relationshipList;
+ }
+
+ /**
+ * Adds the relationship list.
+ *
+ * @param relationshipList the relationship list
+ */
+ public void addRelationshipList(RelationshipList relationshipList) {
+
+ if (!relationshipLists.contains(relationshipList)) {
+ relationshipLists.add(relationshipList);
+ }
+
+ }
+
+ /**
+ * Process pathed self link response.
+ *
+ * @param selfLinkJsonResponse the self link json response
+ * @param startNodeType the start node type
+ * @param startNodeResourceKey the start node resource key
+ */
+ public void processPathedSelfLinkResponse(String selfLinkJsonResponse, String startNodeType,
+ String startNodeResourceKey) {
+
+ if (selfLinkJsonResponse == null || selfLinkJsonResponse.length() == 0) {
+ LOG.error(AaiUiMsgs.SELF_LINK_NULL_EMPTY_RESPONSE);
+ return;
+ }
+
+ try {
+ JsonNode jsonNode = mapper.readValue(selfLinkJsonResponse, JsonNode.class);
+
+ Iterator<Entry<String, JsonNode>> fieldNames = jsonNode.fields();
+ Entry<String, JsonNode> field = null;
+
+ while (fieldNames.hasNext()) {
+
+ field = fieldNames.next();
+
+ /*
+ * Is there a way to tell if the field is an aggregate or an atomic value? This is where our
+ * flattening code needs to live
+ */
+
+ String fieldName = field.getKey();
+
+ if ("relationship-list".equals(fieldName)) {
+
+ /*
+ * Parse the relationship list like we were doing before, so we can determine whether or
+ * not to keep it or traverse it after we have performed the evaluative node depth logic.
+ */
+ RelationshipList relationshipList =
+ analyzeSelfLinkRelationshipList(field.getValue().toString());
+
+ if (relationshipList != null) {
+ this.relationshipLists.add(relationshipList);
+ } else {
+ LOG.info(AaiUiMsgs.NO_RELATIONSHIP_DISCOVERED, nodeId);
+ }
+ } else {
+ JsonNode nodeValue = field.getValue();
+
+ if (nodeValue != null && nodeValue.isValueNode()) {
+
+ /*
+ * before we blindly add the fieldName and value to our property set, let's do one more
+ * check to see if the field name is an entity type. If it is, then our complex
+ * attribute processing code will pick it up and process it instead, but this is
+ * probably more likely just for array node types, but we'll see.
+ */
+
+ if (oxmEntityLookup.getEntityDescriptors().get(fieldName) == null) {
+ /*
+ * this is no an entity type as far as we can tell, so we can add it to our property
+ * set.
+ */
+
+ addProperty(fieldName, nodeValue.asText());
+
+ }
+
+ } else {
+
+ if (nodeValue.isArray()) {
+
+ /*
+ * make sure array entity-type collection is not an entityType before adding it to the
+ * property set. The expetation is that it will be added the visualization through a
+ * complex group or relationship.
+ */
+
+ if (oxmEntityLookup.getEntityDescriptors().get(field.getKey()) == null) {
+ /*
+ * this is no an entity type as far as we can tell, so we can add it to our property
+ * set.
+ */
+
+ addProperty(field.getKey(), nodeValue.toString());
+
+ }
+
+ } else {
+
+ complexGroups.add(nodeValue);
+
+ }
+
+ }
+
+ }
+
+ }
+
+ } catch (IOException exc) {
+ LOG.error(AaiUiMsgs.JSON_CONVERSION_ERROR, "POJO", exc.getLocalizedMessage());
+ this.setProcessingErrorOccurred(true);
+ this.addErrorCause(
+ "An error occurred while converting JSON into POJO = " + exc.getLocalizedMessage());
+ }
+
+ }
+
+ public void setSelfLink(String selfLink) {
+ this.selfLink = selfLink;
+ }
+
+ /**
+ * Adds the complex group.
+ *
+ * @param complexGroup the complex group
+ */
+ public void addComplexGroup(JsonNode complexGroup) {
+
+ if (!complexGroups.contains(complexGroup)) {
+ complexGroups.add(complexGroup);
+ }
+
+ }
+
+ /**
+ * Gets the padding.
+ *
+ * @param level the level
+ * @param paddingString the padding string
+ * @return the padding
+ */
+ private static String getPadding(int level, String paddingString) {
+ StringBuilder sb = new StringBuilder(32);
+ for (int x = 0; x < level; x++) {
+ sb.append(paddingString);
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Dump node tree.
+ *
+ * @param showProperties the show properties
+ * @return the string
+ */
+ public String dumpNodeTree(boolean showProperties) {
+ return dumpNodeTree(0, showProperties);
+ }
+
+ /**
+ * Dump node tree.
+ *
+ * @param level the level
+ * @param showProperties the show properties
+ * @return the string
+ */
+ private String dumpNodeTree(int level, boolean showProperties) {
+ StringBuilder sb = new StringBuilder(128);
+ String padding = getPadding(level, " ");
+
+ sb.append(padding + " -> " + getNodeId() + "]").append("\n");
+ sb.append(padding + " -> primaryKeyName = " + primaryKeyName + "]").append("\n");
+ sb.append(padding + " -> primaryKeyValue = " + primaryKeyValue + "]").append("\n");
+ sb.append(padding + " -> entityType = " + entityType + "]").append("\n");
+
+ if (showProperties) {
+ Set<Entry<String, String>> entries = properties.entrySet();
+ for (Entry<String, String> entry : entries) {
+ sb.append(
+ padding + " ----> " + String.format("[ %s => %s ]", entry.getKey(), entry.getValue()))
+ .append("\n");
+ }
+ }
+
+ sb.append(padding + " ----> " + String.format("[ selfLink => %s ]", getSelfLink()))
+ .append("\n");
+
+ sb.append("\n").append(padding + " ----> Inbound Neighbors:").append("\n");
+
+ for (String inboundNeighbor : inboundNeighbors) {
+ sb.append("\n").append(inboundNeighbor.toString());
+ }
+
+ sb.append(padding + " ----> Outbound Neighbors:").append("\n");
+ sb.append("\n").append(padding + " ----> Outbound Neighbors:").append("\n");
+
+ for (String outboundNeighbor : outboundNeighbors) {
+ sb.append("\n").append(outboundNeighbor.toString());
+ }
+
+ return sb.toString();
+
+ }
+
+ public String getProcessingErrorCauses() {
+
+ StringBuilder sb = new StringBuilder(128);
+
+ for (String c : this.errorCauses) {
+ sb.append(c).append("\n");
+ }
+
+ return sb.toString();
+ }
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/D3VisualizationOutput.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/D3VisualizationOutput.java
new file mode 100644
index 0000000..5da9c20
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/D3VisualizationOutput.java
@@ -0,0 +1,93 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.viewandinspect.entity;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * The Class D3VisualizationOutput.
+ */
+public class D3VisualizationOutput {
+
+ public GraphMeta graphMeta;
+ public List<SparkyGraphNode> nodes;
+ public List<SparkyGraphLink> links;
+ public InlineMessage inlineMessage;
+
+ /**
+ * Instantiates a new d 3 visualization output.
+ */
+ public D3VisualizationOutput() {
+ nodes = new ArrayList<SparkyGraphNode>();
+ links = new ArrayList<SparkyGraphLink>();
+ inlineMessage = null;
+ }
+
+ public GraphMeta getGraphMeta() {
+ return graphMeta;
+ }
+
+ /**
+ * Peg counter.
+ *
+ * @param counterName the counter name
+ */
+ public void pegCounter(String counterName) {
+ graphMeta.pegCounter(counterName);
+ }
+
+ public void setGraphMeta(GraphMeta graphMeta) {
+ this.graphMeta = graphMeta;
+ }
+
+ /**
+ * Adds the nodes.
+ *
+ * @param nodes the nodes
+ */
+ public void addNodes(List<SparkyGraphNode> nodes) {
+ this.nodes.addAll(nodes);
+ }
+
+ /**
+ * Adds the links.
+ *
+ * @param links the links
+ */
+ public void addLinks(List<SparkyGraphLink> links) {
+ this.links.addAll(links);
+ }
+
+ public InlineMessage getInlineMessage() {
+ return inlineMessage;
+ }
+
+ public void setInlineMessage(InlineMessage inlineMessage) {
+ this.inlineMessage = inlineMessage;
+ }
+
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/EntityEntry.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/EntityEntry.java
new file mode 100644
index 0000000..91c615e
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/EntityEntry.java
@@ -0,0 +1,81 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.viewandinspect.entity;
+
+/**
+ * The Class EntityEntry.
+ */
+public class EntityEntry {
+
+ private String entityType;
+
+ private String entityPrimaryKeyValue;
+
+ private String searchTags;
+
+ private String entityId;
+
+ public String getEntityId() {
+ return entityId;
+ }
+
+ public void setEntityId(String entityId) {
+ this.entityId = entityId;
+ }
+
+ public String getEntityType() {
+ return entityType;
+ }
+
+ public void setEntityType(String entityType) {
+ this.entityType = entityType;
+ }
+
+ public String getEntityPrimaryKeyValue() {
+ return entityPrimaryKeyValue;
+ }
+
+ public void setEntityPrimaryKeyValue(String entityPrimaryKeyValue) {
+ this.entityPrimaryKeyValue = entityPrimaryKeyValue;
+ }
+
+ public String getSearchTags() {
+ return searchTags;
+ }
+
+ public void setSearchTags(String searchTags) {
+ this.searchTags = searchTags;
+ }
+
+ @Override
+ public String toString() {
+ return "EntityEntry [" + (entityType != null ? "entityType=" + entityType + ", " : "")
+ + (entityPrimaryKeyValue != null ? "entityPrimaryKeyValue=" + entityPrimaryKeyValue + ", "
+ : "")
+ + (searchTags != null ? "searchTags=" + searchTags + ", " : "")
+ + (entityId != null ? "entityId=" + entityId : "") + "]";
+ }
+
+} \ No newline at end of file
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/GizmoEntity.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/GizmoEntity.java
new file mode 100644
index 0000000..39106d2
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/GizmoEntity.java
@@ -0,0 +1,98 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.viewandinspect.entity;
+
+import java.util.Arrays;
+import java.util.Map;
+
+public class GizmoEntity {
+
+ private String id;
+ private String type;
+ private String url;
+ private Map<String, String> properties;
+ private GizmoRelationshipHint[] in;
+ private GizmoRelationshipHint[] out;
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ public String getUrl() {
+ return url;
+ }
+
+ public void setUrl(String url) {
+ this.url = url;
+ }
+
+ public Map<String, String> getProperties() {
+ return properties;
+ }
+
+ public void setProperties(Map<String, String> properties) {
+ this.properties = properties;
+ }
+
+ public GizmoRelationshipHint[] getIn() {
+ return in;
+ }
+
+ public void setIn(GizmoRelationshipHint[] in) {
+ this.in = in;
+ }
+
+ public GizmoRelationshipHint[] getOut() {
+ return out;
+ }
+
+ public void setOut(GizmoRelationshipHint[] out) {
+ this.out = out;
+ }
+
+ @Override
+ public String toString() {
+ return "GizmoEntity [" + (id != null ? "id=" + id + ", " : "")
+ + (type != null ? "type=" + type + ", " : "") + (url != null ? "url=" + url + ", " : "")
+ + (properties != null ? "properties=" + properties + ", " : "")
+ + (in != null ? "in=" + Arrays.toString(in) + ", " : "")
+ + (out != null ? "out=" + Arrays.toString(out) : "") + "]";
+ }
+
+
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/GizmoRelationshipEntity.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/GizmoRelationshipEntity.java
new file mode 100644
index 0000000..31ea78a
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/GizmoRelationshipEntity.java
@@ -0,0 +1,103 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.viewandinspect.entity;
+
+import java.util.Map;
+
+public class GizmoRelationshipEntity {
+
+ /*
+ * {"id":"oe4ur-3a0-27th-fu8","type":"has","url":
+ * "services/inventory/relationships/v8/has/oe4ur-3a0-27th-fu8","source":
+ * "services/inventory/v8/generic-vnf/4248","target":
+ * "services/inventory/v8/vserver/20528",
+ * "properties":{"is-parent":"true","multiplicity":"many","has-del-target":
+ * "true","uses-resource": "true"}}
+ */
+
+ private String id;
+ private String type;
+ private String url;
+ private String source;
+ private String target;
+ private Map<String, String> properties;
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ public String getUrl() {
+ return url;
+ }
+
+ public void setUrl(String url) {
+ this.url = url;
+ }
+
+ public String getSource() {
+ return source;
+ }
+
+ public void setSource(String source) {
+ this.source = source;
+ }
+
+ public String getTarget() {
+ return target;
+ }
+
+ public void setTarget(String target) {
+ this.target = target;
+ }
+
+ public Map<String, String> getProperties() {
+ return properties;
+ }
+
+ public void setProperties(Map<String, String> properties) {
+ this.properties = properties;
+ }
+
+ @Override
+ public String toString() {
+ return "GizmoRelationshipEntity [" + (id != null ? "id=" + id + ", " : "")
+ + (type != null ? "type=" + type + ", " : "") + (url != null ? "url=" + url + ", " : "")
+ + (source != null ? "source=" + source + ", " : "") + (target != null ? "target=" + target + ", " : "")
+ + (properties != null ? "properties=" + properties : "") + "]";
+ }
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/GizmoRelationshipHint.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/GizmoRelationshipHint.java
new file mode 100644
index 0000000..5e22164
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/GizmoRelationshipHint.java
@@ -0,0 +1,77 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.viewandinspect.entity;
+
+public class GizmoRelationshipHint {
+
+ private String id;
+ private String type;
+ private String url;
+ private String source;
+ private String target;
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ public String getUrl() {
+ return url;
+ }
+
+ public void setUrl(String url) {
+ this.url = url;
+ }
+
+ public String getSource() {
+ return source;
+ }
+
+ public void setSource(String source) {
+ this.source = source;
+ }
+
+ public String getTarget() {
+ return target;
+ }
+
+ public void setTarget(String target) {
+ this.target = target;
+ }
+
+
+
+ }
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/GraphMeta.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/GraphMeta.java
new file mode 100644
index 0000000..7e53665
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/GraphMeta.java
@@ -0,0 +1,147 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.viewandinspect.entity;
+
+import org.onap.aai.sparky.viewandinspect.EntityTypeAggregation;
+
+/**
+ * The Class GraphMeta.
+ */
+public class GraphMeta {
+
+ private com.fasterxml.jackson.databind.JsonNode aaiEntityNodeDescriptors;
+
+ private int numNodes;
+
+ private int numLinks;
+
+ private long renderTimeInMs;
+
+ private int numLinksResolvedSuccessfullyFromCache;
+
+ private int numLinksResolvedSuccessfullyFromServer;
+
+ private int numLinkResolveFailed;
+
+ private EntityTypeAggregation entitySummary;
+
+ /**
+ * Instantiates a new graph meta.
+ */
+ public GraphMeta() {
+ entitySummary = new EntityTypeAggregation();
+ }
+
+ public EntityTypeAggregation getEntitySummary() {
+ return entitySummary;
+ }
+
+ public void setEntitySummary(EntityTypeAggregation entitySummary) {
+ this.entitySummary = entitySummary;
+ }
+
+ public com.fasterxml.jackson.databind.JsonNode getAaiEntityNodeDescriptors() {
+ return aaiEntityNodeDescriptors;
+ }
+
+ public void setAaiEntityNodeDescriptors(
+ com.fasterxml.jackson.databind.JsonNode aaiEntityNodeDefinitions) {
+ this.aaiEntityNodeDescriptors = aaiEntityNodeDefinitions;
+ }
+
+ public int getNumLinksResolvedSuccessfullyFromCache() {
+ return numLinksResolvedSuccessfullyFromCache;
+ }
+
+ public void setNumLinksResolvedSuccessfullyFromCache(int numLinksResolvedSuccessfullyFromCache) {
+ this.numLinksResolvedSuccessfullyFromCache = numLinksResolvedSuccessfullyFromCache;
+ }
+
+ public int getNumLinksResolvedSuccessfullyFromServer() {
+ return numLinksResolvedSuccessfullyFromServer;
+ }
+
+ public void setNumLinksResolvedSuccessfullyFromServer(
+ int numLinksResolvedSuccessfullyFromServer) {
+ this.numLinksResolvedSuccessfullyFromServer = numLinksResolvedSuccessfullyFromServer;
+ }
+
+ public int getNumLinkResolveFailed() {
+ return numLinkResolveFailed;
+ }
+
+ public void setNumLinkResolveFailed(int numLinkResolveFailed) {
+ this.numLinkResolveFailed = numLinkResolveFailed;
+ }
+
+ public int getNumNodes() {
+ return numNodes;
+ }
+
+ public void setNumNodes(int numNodes) {
+ this.numNodes = numNodes;
+ }
+
+ public int getNumLinks() {
+ return numLinks;
+ }
+
+ public void setNumLinks(int numLinks) {
+ this.numLinks = numLinks;
+ }
+
+ public long getRenderTimeInMs() {
+ return renderTimeInMs;
+ }
+
+ public void setRenderTimeInMs(long renderTimeInMs) {
+ this.renderTimeInMs = renderTimeInMs;
+ }
+
+ /**
+ * Peg counter.
+ *
+ * @param counterName the counter name
+ */
+ public void pegCounter(String counterName) {
+ entitySummary.pegCounter(counterName);
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ return "GraphMeta ["
+ + (aaiEntityNodeDescriptors != null
+ ? "aaiEntityNodeDescriptors=" + aaiEntityNodeDescriptors + ", " : "")
+ + "numNodes=" + numNodes + ", numLinks=" + numLinks + ", renderTimeInMs=" + renderTimeInMs
+ + ", numLinksResolvedSuccessfullyFromCache=" + numLinksResolvedSuccessfullyFromCache
+ + ", numLinksResolvedSuccessfullyFromServer=" + numLinksResolvedSuccessfullyFromServer
+ + ", numLinkResolveFailed=" + numLinkResolveFailed + ", "
+ + (entitySummary != null ? "entitySummary=" + entitySummary : "") + "]";
+ }
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/GraphRequest.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/GraphRequest.java
new file mode 100644
index 0000000..23e50a9
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/GraphRequest.java
@@ -0,0 +1,58 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.viewandinspect.entity;
+
+public class GraphRequest {
+
+ private String hashId;
+ private boolean includeGraphMeta;
+
+ public GraphRequest() {
+
+ }
+
+ public String getHashId() {
+ return hashId;
+ }
+
+ public void setHashId(String hashId) {
+ this.hashId = hashId;
+ }
+
+ public boolean isIncludeGraphMeta() {
+ return includeGraphMeta;
+ }
+
+ public void setIncludeGraphMeta(boolean includeGraphMeta) {
+ this.includeGraphMeta = includeGraphMeta;
+ }
+
+ @Override
+ public String toString() {
+ return "QueryRequest [" + (hashId != null ? "hashId=" + hashId + ", " : "")
+ + "includeGraphMeta=" + includeGraphMeta + "]";
+ }
+
+} \ No newline at end of file
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/InlineMessage.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/InlineMessage.java
new file mode 100644
index 0000000..f6f85bb
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/InlineMessage.java
@@ -0,0 +1,70 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.viewandinspect.entity;
+
+/**
+ * The Class InlineMessage.
+ */
+public class InlineMessage {
+
+ private String level;
+ private String message;
+
+ /**
+ * Instantiates a new inline message.
+ *
+ * @param level the level
+ * @param message the message
+ */
+ public InlineMessage(String level, String message) {
+ this.level = level;
+ this.message = message;
+ }
+
+ public String getLevel() {
+ return level;
+ }
+
+ public void setLevel(String level) {
+ this.level = level;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public void setMessage(String message) {
+ this.message = message;
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ return level + " : " + message;
+ }
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/JsonNode.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/JsonNode.java
new file mode 100644
index 0000000..09e5956
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/JsonNode.java
@@ -0,0 +1,207 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.viewandinspect.entity;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.log4j.Logger;
+import org.onap.aai.sparky.viewandinspect.config.VisualizationConfigs;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+
+/*
+ * We can use annotations to differentiate between intermediate data we use to build the node, and
+ * the data that we actually want to appear in the exported JSON.
+ */
+
+/*
+ * This is our current ( 14-June-2016 ) working schema that will remain organic until we get it just
+ * right.
+ *
+ * { "item-type": "customer", "item-name-key": "subscriber-name", “item-name-value” :
+ * “subscriber-name-123456789-aai847-data-01”, "item-properties": [{ "property-name":
+ * "subscriber-name", "property-value": "subscriber-name-123456789-aai847-data-01" }, {
+ * "property-name": "global-customer-id", "property-value":
+ * "global-customer-id-123456789-aai847-data-01" } ], "node-meta": { “color” : “#f2d2d2”,
+ * "isSearchTarget" : false, "nodeGroups" : "1,2,3,4" }, }
+ *
+ */
+
+
+/**
+ * The Class JsonNode.
+ */
+public class JsonNode {
+
+ private String id;
+ private String itemType;
+ private String itemNameKey;
+ private String itemNameValue;
+ private Map<String, String> itemProperties;
+ private NodeMeta nodeMeta;
+
+ @JsonIgnore
+ private boolean isRootNode;
+
+
+ @JsonIgnore
+ private String resourceKey;
+ @JsonIgnore
+ private Collection<String> inboundNeighbors;
+
+ @JsonIgnore
+ private Collection<String> outboundNeighbors;
+
+
+ @JsonIgnore
+ private static final Logger LOG = Logger.getLogger(JsonNode.class);
+
+ private VisualizationConfigs visualizationConfigs;
+
+
+ /**
+ * Instantiates a new json node.
+ *
+ * @param ain the ain
+ */
+ public JsonNode(ActiveInventoryNode ain, VisualizationConfigs visualizationConfigs) {
+ this.resourceKey = ain.getNodeId();
+ this.itemProperties = ain.getProperties();
+ this.setItemType(ain.getEntityType());
+ this.setItemNameKey(ain.getPrimaryKeyName());
+ this.setItemNameValue(ain.getPrimaryKeyValue());
+ this.setId(ain.getNodeId());
+ this.isRootNode = ain.isRootNode();
+ this.visualizationConfigs = visualizationConfigs;
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("---");
+ LOG.debug("JsonNode constructor using AIN = " + ain.dumpNodeTree(true));
+ LOG.debug("---");
+ }
+
+ inboundNeighbors = ain.getInboundNeighbors();
+ outboundNeighbors = ain.getOutboundNeighbors();
+
+ nodeMeta = new NodeMeta(this.visualizationConfigs);
+
+ nodeMeta.setNodeIssue(ain.isNodeIssue());
+ nodeMeta.setNodeValidated(ain.isNodeValidated());
+ nodeMeta.setNodeDepth(ain.getNodeDepth());
+
+ nodeMeta.setNumInboundNeighbors(ain.getInboundNeighbors().size());
+ nodeMeta.setNumOutboundNeighbors(ain.getOutboundNeighbors().size());
+
+ nodeMeta.setAtMaxDepth(ain.isAtMaxDepth());
+ nodeMeta.setSelfLinkResolved(!ain.isSelflinkRetrievalFailure());
+ nodeMeta.setProcessingErrorOccurred(ain.isProcessingErrorOccurred());
+ nodeMeta.setHasNeighbors(
+ ain.getOutboundNeighbors().size() > 0 || ain.getInboundNeighbors().size() > 0);
+ nodeMeta.setProcessingState(ain.getState());
+
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public String getItemNameKey() {
+ return itemNameKey;
+ }
+
+ public String getItemNameValue() {
+ return itemNameValue;
+ }
+
+ public Map<String, String> getItemProperties() {
+ return itemProperties;
+ }
+
+ public String getItemType() {
+ return itemType;
+ }
+
+ public String getResourceKey() {
+ return resourceKey;
+ }
+
+ public void setItemNameKey(String itemNameKey) {
+ this.itemNameKey = itemNameKey;
+ }
+
+ public void setItemNameValue(String itemNameValue) {
+ this.itemNameValue = itemNameValue;
+ }
+
+ public void setItemProperties(HashMap<String, String> itemProperties) {
+ this.itemProperties = itemProperties;
+ }
+
+ public void setItemType(String itemType) {
+ this.itemType = itemType;
+ }
+
+ public void setResourceKey(String resourceKey) {
+ this.resourceKey = resourceKey;
+ }
+
+ public NodeMeta getNodeMeta() {
+ return nodeMeta;
+ }
+
+ public void setNodeMeta(NodeMeta nodeMeta) {
+ this.nodeMeta = nodeMeta;
+ }
+
+ public boolean isRootNode() {
+ return isRootNode;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ return "JsonNode [" + (id != null ? "id=" + id + ", " : "")
+ + (itemType != null ? "itemType=" + itemType + ", " : "")
+ + (itemNameKey != null ? "itemNameKey=" + itemNameKey + ", " : "")
+ + (itemNameValue != null ? "itemNameValue=" + itemNameValue + ", " : "")
+ + (itemProperties != null ? "itemProperties=" + itemProperties + ", " : "")
+ + (nodeMeta != null ? "nodeMeta=" + nodeMeta + ", " : "")
+ + (resourceKey != null ? "resourceKey=" + resourceKey + ", " : "")
+ + (inboundNeighbors != null ? "inboundNeighbors=" + inboundNeighbors + ", " : "")
+ + (outboundNeighbors != null ? "outboundNeighbors=" + outboundNeighbors : "") + "]";
+ }
+
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/JsonNodeLink.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/JsonNodeLink.java
new file mode 100644
index 0000000..5891d51
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/JsonNodeLink.java
@@ -0,0 +1,77 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.viewandinspect.entity;
+
+/*
+ * Expected JSON Output:
+ *
+ * { JsonNodeLink : { id : <value>, source : <value>, target : <value> } }
+ *
+ */
+
+/**
+ * The Class JsonNodeLink.
+ */
+public class JsonNodeLink {
+
+ protected String id;
+ protected String source;
+ protected String target;
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public String getSource() {
+ return source;
+ }
+
+ public void setSource(String source) {
+ this.source = source;
+ }
+
+ public String getTarget() {
+ return target;
+ }
+
+ public void setTarget(String target) {
+ this.target = target;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ return "JsonNodeLink [id=" + id + ", source=" + source + ", target=" + target + "]";
+ }
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/NodeDebug.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/NodeDebug.java
new file mode 100644
index 0000000..0cc0746
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/NodeDebug.java
@@ -0,0 +1,59 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.viewandinspect.entity;
+
+/**
+ * The Class NodeDebug.
+ */
+public class NodeDebug {
+ private boolean maxTraversalDepthReached;
+ private boolean processingError;
+ private String processingErrorCauses;
+
+ public boolean isMaxTraversalDepthReached() {
+ return maxTraversalDepthReached;
+ }
+
+ public void setMaxTraversalDepthReached(boolean maxTraversalDepthReached) {
+ this.maxTraversalDepthReached = maxTraversalDepthReached;
+ }
+
+ public boolean isProcessingError() {
+ return processingError;
+ }
+
+ public void setProcessingError(boolean processingError) {
+ this.processingError = processingError;
+ }
+
+ public String getProcessingErrorCauses() {
+ return processingErrorCauses;
+ }
+
+ public void setProcessingErrorCauses(String processingErrorCauses) {
+ this.processingErrorCauses = processingErrorCauses;
+ }
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/NodeMeta.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/NodeMeta.java
new file mode 100644
index 0000000..bc21941
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/NodeMeta.java
@@ -0,0 +1,207 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.viewandinspect.entity;
+
+import org.onap.aai.sparky.viewandinspect.config.VisualizationConfigs;
+import org.onap.aai.sparky.viewandinspect.enumeration.NodeProcessingState;
+
+/**
+ * The Class NodeMeta.
+ */
+public class NodeMeta {
+
+ private String className;
+
+ private boolean isSearchTarget;
+
+ private NodeDebug nodeDebug;
+ private boolean nodeIssue;
+ private boolean nodeValidated;
+ private long selfLinkResponseTimeInMs;
+ private long numInboundNeighbors;
+ private long numOutboundNeighbors;
+
+ private boolean atMaxDepth;
+ private boolean selfLinkResolved;
+ private boolean processingErrorOccurred;
+ private boolean neighborsProcessed;
+ private int nodeDepth;
+ private boolean hasNeighbors;
+
+ private NodeProcessingState processingState;
+
+ private VisualizationConfigs visualizationConfigs;
+
+
+
+ /**
+ * Instantiates a new node meta.
+ */
+ public NodeMeta(VisualizationConfigs visualizationConfigs) {
+ this.isSearchTarget = false;
+ this.visualizationConfigs = visualizationConfigs;
+
+
+ if (this.visualizationConfigs.isVisualizationDebugEnabled()) {
+ nodeDebug = new NodeDebug();
+ }
+ this.numInboundNeighbors = 0;
+ this.numOutboundNeighbors = 0;
+
+ this.selfLinkResponseTimeInMs = 0;
+
+ this.atMaxDepth = false;
+ this.selfLinkResolved = false;
+ this.processingErrorOccurred = false;
+ this.hasNeighbors = false;
+ this.neighborsProcessed = false;
+ this.nodeDepth = ActiveInventoryNode.DEFAULT_INIT_NODE_DEPTH;
+ this.processingState = NodeProcessingState.INIT;
+
+ }
+
+ public boolean isAtMaxDepth() {
+ return atMaxDepth;
+ }
+
+ public void setAtMaxDepth(boolean atMaxDepth) {
+ this.atMaxDepth = atMaxDepth;
+ }
+
+ public boolean isSelfLinkResolved() {
+ return selfLinkResolved;
+ }
+
+
+
+ public NodeProcessingState getProcessingState() {
+ return processingState;
+ }
+
+ public void setProcessingState(NodeProcessingState processingState) {
+ this.processingState = processingState;
+ }
+
+ public void setSelfLinkResolved(boolean selfLinkResolved) {
+ this.selfLinkResolved = selfLinkResolved;
+ }
+
+ public boolean isProcessingErrorOccurred() {
+ return processingErrorOccurred;
+ }
+
+ public void setProcessingErrorOccurred(boolean processingErrorOccurred) {
+ this.processingErrorOccurred = processingErrorOccurred;
+ }
+
+ public boolean isHasNeighbors() {
+ return hasNeighbors;
+ }
+
+ public void setHasNeighbors(boolean hasNeighbors) {
+ this.hasNeighbors = hasNeighbors;
+ }
+
+ public boolean isNeighborsProcessed() {
+ return neighborsProcessed;
+ }
+
+ public void setNeighborsProcessed(boolean neighborsProcessed) {
+ this.neighborsProcessed = neighborsProcessed;
+ }
+
+ public int getNodeDepth() {
+ return nodeDepth;
+ }
+
+ public void setNodeDepth(int nodeDepth) {
+ this.nodeDepth = nodeDepth;
+ }
+
+ public void setNodeDebug(NodeDebug nodeDebug) {
+ this.nodeDebug = nodeDebug;
+ }
+
+ public String getClassName() {
+ return className;
+ }
+
+ public long getNumInboundNeighbors() {
+ return numInboundNeighbors;
+ }
+
+ public void setNumInboundNeighbors(long numInboundNeighbors) {
+ this.numInboundNeighbors = numInboundNeighbors;
+ }
+
+ public long getNumOutboundNeighbors() {
+ return numOutboundNeighbors;
+ }
+
+ public void setNumOutboundNeighbors(long numOutboundNeighbors) {
+ this.numOutboundNeighbors = numOutboundNeighbors;
+ }
+
+ public NodeDebug getNodeDebug() {
+ return nodeDebug;
+ }
+
+ public long getSelfLinkResponseTimeInMs() {
+ return selfLinkResponseTimeInMs;
+ }
+
+ public boolean isNodeIssue() {
+ return nodeIssue;
+ }
+
+ public boolean isNodeValidated() {
+ return nodeValidated;
+ }
+
+ public boolean isSearchTarget() {
+ return isSearchTarget;
+ }
+
+ public void setClassName(String className) {
+ this.className = className;
+ }
+
+ public void setNodeIssue(boolean nodeIssue) {
+ this.nodeIssue = nodeIssue;
+ }
+
+ public void setNodeValidated(boolean nodeValidated) {
+ this.nodeValidated = nodeValidated;
+ }
+
+ public void setSearchTarget(boolean isSearchTarget) {
+ this.isSearchTarget = isSearchTarget;
+ }
+
+ public void setSelfLinkResponseTimeInMs(long selfLinkResponseTimeInMs) {
+ this.selfLinkResponseTimeInMs = selfLinkResponseTimeInMs;
+ }
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/NodeProcessingTransaction.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/NodeProcessingTransaction.java
new file mode 100644
index 0000000..8b1cb8d
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/NodeProcessingTransaction.java
@@ -0,0 +1,109 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.viewandinspect.entity;
+
+import org.onap.aai.restclient.client.OperationResult;
+
+/**
+ * The Class NodeProcessingTransaction.
+ */
+public class NodeProcessingTransaction {
+
+ private ActiveInventoryNode processingNode;
+ private OperationResult opResult;
+ private String selfLinkWithModifiers;
+ private String requestParameters;
+
+ /**
+ * Instantiates a new node processing transaction.
+ */
+ public NodeProcessingTransaction() {}
+
+ public String getRequestParameters() {
+ return requestParameters;
+ }
+
+ public void setRequestParameters(String requestParameters) {
+ this.requestParameters = requestParameters;
+ }
+
+ public String getSelfLink() {
+ if (processingNode == null) {
+ return null;
+ }
+
+ return processingNode.getSelfLink();
+ }
+
+ public String getSelfLinkWithModifiers() {
+ if (processingNode == null) {
+ return null;
+ }
+
+ return processingNode.getSelfLink() + requestParameters;
+ }
+
+ public ActiveInventoryNode getProcessingNode() {
+ return processingNode;
+ }
+
+ public void setProcessingNode(ActiveInventoryNode processingNode) {
+ this.processingNode = processingNode;
+ }
+
+ public OperationResult getOpResult() {
+ return opResult;
+ }
+
+ public void setOpResult(OperationResult opResult) {
+ this.opResult = opResult;
+ }
+
+ /**
+ * Processing error occurred.
+ *
+ * @return true, if successful
+ */
+ public boolean processingErrorOccurred() {
+ if (opResult == null) {
+ return true;
+ }
+
+ return !opResult.wasSuccessful();
+
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ return "NodeProcessingTransaction ["
+ + (processingNode != null ? "processingNode=" + processingNode + ", " : "")
+ + (opResult != null ? "opResult=" + opResult + ", " : "") + "processorErrorOccurred="
+ + processingErrorOccurred() + "]";
+ }
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/QueryParams.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/QueryParams.java
new file mode 100644
index 0000000..f1a8e4e
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/QueryParams.java
@@ -0,0 +1,57 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.viewandinspect.entity;
+
+/**
+ * The Class QueryParams.
+ */
+public class QueryParams {
+
+ private String searchTargetPrimaryKeyValues;
+ private String searchTargetNodeId;
+
+ /**
+ * Instantiates a new query params.
+ */
+ public QueryParams() {
+
+ }
+
+ public String getSearchTargetPrimaryKeyValues() {
+ return searchTargetPrimaryKeyValues;
+ }
+
+ public void setSearchTargetPrimaryKeyValues(String searchTargetPrimaryKeyValues) {
+ this.searchTargetPrimaryKeyValues = searchTargetPrimaryKeyValues;
+ }
+
+ public String getSearchTargetNodeId() {
+ return searchTargetNodeId;
+ }
+
+ public void setSearchTargetNodeId(String searchTargetNodeId) {
+ this.searchTargetNodeId = searchTargetNodeId;
+ }
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/QueryRequest.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/QueryRequest.java
new file mode 100644
index 0000000..a542efd
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/QueryRequest.java
@@ -0,0 +1,47 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.viewandinspect.entity;
+
+/**
+ * The Class QueryRequest.
+ */
+public class QueryRequest {
+
+ private String hashId;
+
+ public String getHashId() {
+ return hashId;
+ }
+
+ public void setHashId(String hashId) {
+ this.hashId = hashId;
+ }
+
+ @Override
+ public String toString() {
+ return "QueryRequest [hashId=" + hashId + "]";
+ }
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/RelatedToProperty.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/RelatedToProperty.java
new file mode 100644
index 0000000..5d0f8c3
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/RelatedToProperty.java
@@ -0,0 +1,64 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.viewandinspect.entity;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+/**
+ * The Class RelatedToProperty.
+ */
+public class RelatedToProperty {
+ protected String propertyKey;
+ protected String propertyValue;
+
+ @JsonProperty("property-key")
+ public String getPropertyKey() {
+ return propertyKey;
+ }
+
+ public void setPropertyKey(String propertyKey) {
+ this.propertyKey = propertyKey;
+ }
+
+ @JsonProperty("property-value")
+ public String getPropertyValue() {
+ return propertyValue;
+ }
+
+ public void setPropertyValue(String propertyValue) {
+ this.propertyValue = propertyValue;
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ return "RelatedToProperty [propertyKey=" + propertyKey + ", propertyValue=" + propertyValue
+ + "]";
+ }
+
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/Relationship.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/Relationship.java
new file mode 100644
index 0000000..813dec6
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/Relationship.java
@@ -0,0 +1,96 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.viewandinspect.entity;
+
+import java.util.Arrays;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+/**
+ * The Class Relationship.
+ */
+public class Relationship {
+
+ protected String relatedTo;
+ protected String relationshipLabel;
+ protected String relatedLink;
+ protected RelationshipData[] relationshipData;
+ protected RelatedToProperty[] relatedToProperty;
+
+ public String getRelatedTo() {
+ return relatedTo;
+ }
+
+ @JsonProperty("related-to")
+ public void setRelatedTo(String relatedTo) {
+ this.relatedTo = relatedTo;
+ }
+
+ public String getRelationshipLabel() {
+ return relationshipLabel;
+ }
+
+ @JsonProperty("relationship-label")
+ public void setRelationshipLabel(String relationshipLabel) {
+ this.relationshipLabel = relationshipLabel;
+ }
+
+ public String getRelatedLink() {
+ return relatedLink;
+ }
+
+ @JsonProperty("related-link")
+ public void setRelatedLink(String relatedLink) {
+ this.relatedLink = relatedLink;
+ }
+
+ public RelationshipData[] getRelationshipData() {
+ return relationshipData;
+ }
+
+ @JsonProperty("relationship-data")
+ public void setRelationshipData(RelationshipData[] relationshipData) {
+ this.relationshipData = relationshipData;
+ }
+
+ public RelatedToProperty[] getRelatedToProperty() {
+ return relatedToProperty;
+ }
+
+ @JsonProperty("related-to-property")
+ public void setRelatedToProperty(RelatedToProperty[] relatedToProperty) {
+ this.relatedToProperty = relatedToProperty;
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ return "Relationship [relatedTo=" + relatedTo + ", relationshipLabel=" + relationshipLabel
+ + ", relatedLink=" + relatedLink + ", relationshipData=" + Arrays.toString(relationshipData)
+ + ", relatedToProperty=" + Arrays.toString(relatedToProperty) + "]";
+ }
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/RelationshipData.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/RelationshipData.java
new file mode 100644
index 0000000..c8dfefe
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/RelationshipData.java
@@ -0,0 +1,63 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.viewandinspect.entity;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+/**
+ * The Class RelationshipData.
+ */
+public class RelationshipData {
+ protected String relationshipKey;
+ protected String relationshipValue;
+
+ @JsonProperty("relationship-key")
+ public String getRelationshipKey() {
+ return relationshipKey;
+ }
+
+ public void setRelationshipKey(String relationshipKey) {
+ this.relationshipKey = relationshipKey;
+ }
+
+ @JsonProperty("relationship-value")
+ public String getRelationshipValue() {
+ return relationshipValue;
+ }
+
+ public void setRelationshipValue(String relationshipValue) {
+ this.relationshipValue = relationshipValue;
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ return "RelationshipData [relationshipKey=" + relationshipKey + ", relationshipValue="
+ + relationshipValue + "]";
+ }
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/RelationshipDirectionality.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/RelationshipDirectionality.java
new file mode 100644
index 0000000..13d0537
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/RelationshipDirectionality.java
@@ -0,0 +1,42 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.viewandinspect.entity;
+
+/**
+ * This enumeration is intended to be used to help us discriminate neighbor relationships for the
+ * purpose of visualization and conceptualization to model in/out relationships between
+ * ActiveInventoryNodes.
+ * Possible visualization behaviors could be the following: - IN ( draw a line with 1 arrow ) - OUT
+ * ( draw a line with 1 arrow ) - BOTH ( draw a line with 2 arrows, or 2 lines with 1 arrow each ) -
+ * UNKNOWN ( draw a line with no arrows )
+ * The UNKNOWN case is what we have at the moment where we have a collection neighbors with no
+ * knowledge of relationship directionality.
+ *
+ * @author davea
+ *
+ */
+public enum RelationshipDirectionality {
+ IN, OUT, BOTH, UNKNOWN
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/RelationshipList.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/RelationshipList.java
new file mode 100644
index 0000000..9c81a3d
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/RelationshipList.java
@@ -0,0 +1,57 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.viewandinspect.entity;
+
+import java.util.Arrays;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+/**
+ * The Class RelationshipList.
+ */
+public class RelationshipList {
+
+ protected Relationship[] relationship;
+
+ public Relationship[] getRelationshipList() {
+ return relationship;
+ }
+
+ @JsonProperty("relationship")
+ public void setRelationshipList(Relationship[] relationship) {
+ this.relationship = relationship;
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ return "RelationshipList [relationshipList=" + Arrays.toString(relationship) + "]";
+ }
+
+
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/SearchableEntityList.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/SearchableEntityList.java
new file mode 100644
index 0000000..d853673
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/SearchableEntityList.java
@@ -0,0 +1,116 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.viewandinspect.entity;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.onap.aai.sparky.sync.entity.SearchableEntity;
+
+import java.util.Set;
+
+public class SearchableEntityList {
+
+ private List<SearchableEntity> entities;
+
+ public SearchableEntityList() {
+ entities = new ArrayList<SearchableEntity>();
+ }
+
+ public List<SearchableEntity> getEntities() {
+ return entities;
+ }
+
+ public void setEntities(List<SearchableEntity> entities) {
+ this.entities = entities;
+ }
+
+ public void addEntity(SearchableEntity entity) {
+
+ if ( !entities.contains(entity)) {
+ entities.add(entity);
+ }
+
+ }
+
+ protected static SearchableEntity buildEntity(String entityType, String pkeyValue, String link, Map<String,String> searchTags ) {
+
+ SearchableEntity se = new SearchableEntity();
+
+ se.setEntityType(entityType);
+ se.setEntityPrimaryKeyValue(pkeyValue);
+ se.setLink(link);
+
+ if ( searchTags != null) {
+
+ Set<Entry<String, String>> entrySet = searchTags.entrySet();
+
+ for ( Entry<String, String> entry : entrySet ) {
+ se.addSearchTagWithKey(entry.getKey(), entry.getValue());
+ }
+ }
+
+ se.deriveFields();
+
+ return se;
+
+ }
+
+ protected static Map<String,String> getSearchTagMap(String... tags) {
+
+ HashMap<String,String> dataMap = new HashMap<String,String>();
+
+ if ( tags != null && tags.length >= 2 ) {
+
+ int numTags = tags.length;
+ int index = 0;
+
+ while ( index < numTags ) {
+
+ if ( index + 1 < numTags ) {
+ // we have enough parameters for the current set
+ dataMap.put(tags[index], tags[index+1]);
+ index += 2;
+ } else {
+ break;
+ }
+ }
+
+ }
+
+ return dataMap;
+
+
+ }
+
+ @Override
+ public String toString() {
+ return "SearchableEntityList [" + (entities != null ? "entities=" + entities : "") + "]";
+ }
+
+} \ No newline at end of file
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/SelfLinkDeterminationTransaction.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/SelfLinkDeterminationTransaction.java
new file mode 100644
index 0000000..d69994b
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/SelfLinkDeterminationTransaction.java
@@ -0,0 +1,80 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.viewandinspect.entity;
+
+import org.onap.aai.restclient.client.OperationResult;
+
+public class SelfLinkDeterminationTransaction {
+
+ private String parentNodeId;
+ private ActiveInventoryNode newNode;
+ private String queryString;
+ private String entityUrl;
+ private OperationResult opResult;
+
+
+ public String getParentNodeId() {
+ return parentNodeId;
+ }
+
+ public void setParentNodeId(String parentNodeId) {
+ this.parentNodeId = parentNodeId;
+ }
+
+ public ActiveInventoryNode getNewNode() {
+ return newNode;
+ }
+
+ public void setNewNode(ActiveInventoryNode newNode) {
+ this.newNode = newNode;
+ }
+
+ public OperationResult getOpResult() {
+ return opResult;
+ }
+
+ public void setOpResult(OperationResult opResult) {
+ this.opResult = opResult;
+ }
+
+ public String getQueryString() {
+ return queryString;
+ }
+
+ public void setQueryString(String queryString) {
+ this.queryString = queryString;
+ }
+
+ public String getEntityUrl() {
+ return entityUrl;
+ }
+
+ public void setEntityUrl(String entityUrl) {
+ this.entityUrl = entityUrl;
+ }
+
+
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/SparkyGraphLink.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/SparkyGraphLink.java
new file mode 100644
index 0000000..9b6e4e9
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/SparkyGraphLink.java
@@ -0,0 +1,75 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.viewandinspect.entity;
+
+/*
+ * Expected JSON Output:
+ *
+ * { JsonNodeLink : { id : <value>, source : <value>, target : <value> } }
+ *
+ */
+
+/**
+ * The Class JsonNodeLink.
+ */
+public class SparkyGraphLink {
+
+ protected String id;
+ protected String source;
+ protected String target;
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public String getSource() {
+ return source;
+ }
+
+ public void setSource(String source) {
+ this.source = source;
+ }
+
+ public String getTarget() {
+ return target;
+ }
+
+ public void setTarget(String target) {
+ this.target = target;
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ return "JsonNodeLink [id=" + id + ", source=" + source + ", target=" + target + "]";
+ }
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/SparkyGraphNode.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/SparkyGraphNode.java
new file mode 100644
index 0000000..5171eaf
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/SparkyGraphNode.java
@@ -0,0 +1,248 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.viewandinspect.entity;
+
+import java.io.IOException;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.onap.aai.cl.api.Logger;
+import org.onap.aai.cl.eelf.LoggerFactory;
+import org.onap.aai.sparky.aggregatevnf.search.AggregateSummaryProcessor;
+import org.onap.aai.sparky.logging.AaiUiMsgs;
+import org.onap.aai.sparky.subscription.config.SubscriptionConfig;
+import org.onap.aai.sparky.subscription.payload.entity.ObjectInspectorPayload;
+import org.onap.aai.sparky.viewandinspect.config.SparkyConstants;
+import org.onap.aai.sparky.viewandinspect.config.VisualizationConfigs;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+
+/*
+ * We can use annotations to differentiate between intermediate data we use to build the node, and
+ * the data that we actually want to appear in the exported JSON.
+ */
+
+/*
+ * This is our current ( 14-June-2016 ) working schema that will remain organic until we get it just
+ * right.
+ *
+ * { "item-type": "customer", "item-name-key": "subscriber-name", “item-name-value” :
+ * “subscriber-name-123456789-aai847-data-01”, "item-properties": [{ "property-name":
+ * "subscriber-name", "property-value": "subscriber-name-123456789-aai847-data-01" }, {
+ * "property-name": "global-customer-id", "property-value":
+ * "global-customer-id-123456789-aai847-data-01" } ], "node-meta": { “color” : “#f2d2d2”,
+ * "isSearchTarget" : false, "nodeGroups" : "1,2,3,4" }, }
+ *
+ */
+
+
+/**
+ * The Class JsonNode.
+ */
+public class SparkyGraphNode {
+
+ private String id;
+ private String itemType;
+ private String itemNameKey;
+ private String itemNameValue;
+ private Map<String, String> itemProperties;
+ private NodeMeta nodeMeta;
+ private ObjectInspectorPayload externalResourcePayload;
+
+ @JsonIgnore
+ private boolean isRootNode;
+
+
+ @JsonIgnore
+ private String resourceKey;
+ @JsonIgnore
+ private Collection<String> inboundNeighbors;
+
+ @JsonIgnore
+ private Collection<String> outboundNeighbors;
+
+
+ @JsonIgnore
+ private static final Logger LOG = LoggerFactory.getInstance().getLogger(SparkyGraphNode.class);
+
+ private VisualizationConfigs visualizationConfigs;
+ private SubscriptionConfig subConfig;
+
+ /**
+ * Instantiates a new SparkyGraphNode.
+ *
+ * @param ain the ain
+ */
+ public SparkyGraphNode(ActiveInventoryNode ain, VisualizationConfigs visualizationConfigs, SubscriptionConfig subConfig) {
+ this.resourceKey = ain.getNodeId();
+ this.itemProperties = ain.getProperties();
+ this.setItemType(ain.getEntityType());
+ this.setItemNameKey(ain.getPrimaryKeyName());
+ this.setItemNameValue(ain.getPrimaryKeyValue());
+ this.setId(ain.getNodeId());
+ this.isRootNode = ain.isRootNode();
+ this.visualizationConfigs = visualizationConfigs;
+ this.setSubConfig(subConfig);
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("---");
+ LOG.debug("JsonNode constructor using AIN = " + ain.dumpNodeTree(true));
+ LOG.debug("---");
+ }
+
+ inboundNeighbors = ain.getInboundNeighbors();
+ outboundNeighbors = ain.getOutboundNeighbors();
+
+ nodeMeta = new NodeMeta(this.visualizationConfigs);
+
+ nodeMeta.setNodeIssue(ain.isNodeIssue());
+ nodeMeta.setNodeValidated(ain.isNodeValidated());
+ nodeMeta.setNodeDepth(ain.getNodeDepth());
+
+ nodeMeta.setNumInboundNeighbors(ain.getInboundNeighbors().size());
+ nodeMeta.setNumOutboundNeighbors(ain.getOutboundNeighbors().size());
+
+ nodeMeta.setAtMaxDepth(ain.isAtMaxDepth());
+ nodeMeta.setSelfLinkResolved(!ain.isSelflinkRetrievalFailure());
+ nodeMeta.setProcessingErrorOccurred(ain.isProcessingErrorOccurred());
+ nodeMeta.setHasNeighbors(
+ ain.getOutboundNeighbors().size() > 0 || ain.getInboundNeighbors().size() > 0);
+
+ if (subConfig.getIsLaunchOIEnabled()) {
+ try {
+ Collection<String> entityTypes = subConfig.getAnnEntitiyTypes();
+ for (String entityType : entityTypes) {
+ if (entityType.equals(this.getItemType())) {
+ ObjectInspectorPayload lic = ObjectInspectorPayload.getOIPayload(subConfig);
+ lic.getMessage().getPayload().getParams().setObjectName(this.getItemNameValue());
+ this.setExternalResourcePayload(lic);
+ break;
+ }
+ }
+ } catch (IOException e) {
+ String message = "Could not map JSON to object " + "Attempted to convert: "
+ + SparkyConstants.SUBSCRIPTION_OI_MAPPING + ". Error: " + e.getLocalizedMessage();
+ LOG.error(AaiUiMsgs.JSON_PROCESSING_ERROR, message);
+ }
+ }
+ nodeMeta.setProcessingState(ain.getState());
+
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public String getItemNameKey() {
+ return itemNameKey;
+ }
+
+ public String getItemNameValue() {
+ return itemNameValue;
+ }
+
+ public Map<String, String> getItemProperties() {
+ return itemProperties;
+ }
+
+ public String getItemType() {
+ return itemType;
+ }
+
+ public String getResourceKey() {
+ return resourceKey;
+ }
+
+ public void setItemNameKey(String itemNameKey) {
+ this.itemNameKey = itemNameKey;
+ }
+
+ public void setItemNameValue(String itemNameValue) {
+ this.itemNameValue = itemNameValue;
+ }
+
+ public void setItemProperties(HashMap<String, String> itemProperties) {
+ this.itemProperties = itemProperties;
+ }
+
+ public void setItemType(String itemType) {
+ this.itemType = itemType;
+ }
+
+ public void setResourceKey(String resourceKey) {
+ this.resourceKey = resourceKey;
+ }
+
+ public NodeMeta getNodeMeta() {
+ return nodeMeta;
+ }
+
+ public void setNodeMeta(NodeMeta nodeMeta) {
+ this.nodeMeta = nodeMeta;
+ }
+
+ public boolean isRootNode() {
+ return isRootNode;
+ }
+
+ public ObjectInspectorPayload getExternalResourcePayload() {
+ return externalResourcePayload;
+ }
+
+ public void setExternalResourcePayload(ObjectInspectorPayload externalResourcePayload) {
+ this.externalResourcePayload = externalResourcePayload;
+ }
+
+ public SubscriptionConfig getSubConfig() {
+ return subConfig;
+ }
+
+ public void setSubConfig(SubscriptionConfig subConfig) {
+ this.subConfig = subConfig;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ return "JsonNode [" + (id != null ? "id=" + id + ", " : "")
+ + (itemType != null ? "itemType=" + itemType + ", " : "")
+ + (itemNameKey != null ? "itemNameKey=" + itemNameKey + ", " : "")
+ + (itemNameValue != null ? "itemNameValue=" + itemNameValue + ", " : "")
+ + (itemProperties != null ? "itemProperties=" + itemProperties + ", " : "")
+ + (nodeMeta != null ? "nodeMeta=" + nodeMeta + ", " : "")
+ + (resourceKey != null ? "resourceKey=" + resourceKey + ", " : "")
+ + (inboundNeighbors != null ? "inboundNeighbors=" + inboundNeighbors + ", " : "")
+ + (outboundNeighbors != null ? "outboundNeighbors=" + outboundNeighbors : "") + "]";
+ }
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/enumeration/NodeProcessingAction.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/enumeration/NodeProcessingAction.java
new file mode 100644
index 0000000..5c6cdd8
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/enumeration/NodeProcessingAction.java
@@ -0,0 +1,36 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.viewandinspect.enumeration;
+
+/**
+ * The Enum NodeProcessingAction.
+ */
+public enum NodeProcessingAction {
+ SELF_LINK_SET, NEW_NODE_PROCESSED, SELF_LINK_RESOLVE_ERROR, SELF_LINK_DETERMINATION_ERROR,
+ SELF_LINK_RESOLVE_OK, SELF_LINK_RESPONSE_PARSE_ERROR, SELF_LINK_RESPONSE_PARSE_OK,
+ NEIGHBORS_PROCESSED_ERROR, NEIGHBORS_PROCESSED_OK, COMPLEX_ATTRIBUTE_GROUP_PARSE_ERROR,
+ COMPLEX_ATTRIBUTE_GROUP_PARSE_OK, NODE_IDENTITY_ERROR,UNEXPECTED_STATE_TRANSITION
+}
+
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/enumeration/NodeProcessingState.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/enumeration/NodeProcessingState.java
new file mode 100644
index 0000000..18673ef
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/enumeration/NodeProcessingState.java
@@ -0,0 +1,31 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.viewandinspect.enumeration;
+
+/**
+ * The Enum NodeProcessingState.
+ */
+public enum NodeProcessingState {
+ INIT, SELF_LINK_UNRESOLVED, SELF_LINK_RESPONSE_UNPROCESSED, NEIGHBORS_UNPROCESSED, READY, ERROR}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/search/ViewInspectSearchProvider.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/search/ViewInspectSearchProvider.java
new file mode 100644
index 0000000..c0a7711
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/search/ViewInspectSearchProvider.java
@@ -0,0 +1,426 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.viewandinspect.search;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.onap.aai.cl.api.Logger;
+import org.onap.aai.cl.eelf.LoggerFactory;
+import org.onap.aai.restclient.client.OperationResult;
+import org.onap.aai.sparky.common.search.CommonSearchSuggestion;
+import org.onap.aai.sparky.config.oxm.OxmEntityDescriptor;
+import org.onap.aai.sparky.config.oxm.OxmEntityLookup;
+import org.onap.aai.sparky.logging.AaiUiMsgs;
+import org.onap.aai.sparky.search.SearchServiceAdapter;
+import org.onap.aai.sparky.search.api.SearchProvider;
+import org.onap.aai.sparky.search.config.SuggestionConfig;
+import org.onap.aai.sparky.search.entity.QuerySearchEntity;
+import org.onap.aai.sparky.search.entity.SearchSuggestion;
+import org.onap.aai.sparky.util.NodeUtils;
+import org.onap.aai.sparky.viewandinspect.config.SparkyConstants;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+
+public class ViewInspectSearchProvider implements SearchProvider {
+
+ private static final Logger LOG =
+ LoggerFactory.getInstance().getLogger(ViewInspectSearchProvider.class);
+
+ private SearchServiceAdapter searchServiceAdapter = null;
+ private SuggestionConfig suggestionConfig;
+ private String additionalSearchSuggestionText;
+
+ private static final String KEY_SEARCH_RESULT = "searchResult";
+ private static final String KEY_HITS = "hits";
+ private static final String KEY_DOCUMENT = "document";
+ private static final String KEY_CONTENT = "content";
+
+ private static final String KEY_SEARCH_TAG_IDS = "searchTagIDs";
+ private static final String KEY_SEARCH_TAGS = "searchTags";
+ private static final String KEY_LINK = "link";
+ private static final String KEY_ENTITY_TYPE = "entityType";
+
+ private final String viewInspectIndexName;
+ private final String viewInspectSuggestionRoute;
+ private OxmEntityLookup oxmEntityLookup;
+
+ public ViewInspectSearchProvider(SearchServiceAdapter searchServiceAdapter,
+ SuggestionConfig suggestionConfig, String viewInspectIndexName,
+ String viewInspectSuggestionRoute, OxmEntityLookup oxmEntityLookup) throws Exception {
+
+ this.searchServiceAdapter = searchServiceAdapter;
+ this.oxmEntityLookup = oxmEntityLookup;
+ this.suggestionConfig = suggestionConfig;
+ additionalSearchSuggestionText = null;
+ this.viewInspectIndexName = viewInspectIndexName;
+ this.viewInspectSuggestionRoute = viewInspectSuggestionRoute;
+
+ }
+
+ @Override
+ public List<SearchSuggestion> search(QuerySearchEntity queryRequest) {
+
+ List<SearchSuggestion> suggestionEntityList = new ArrayList<SearchSuggestion>();
+
+ /*
+ * Based on the configured stop words, we need to strip any matched stop-words ( case
+ * insensitively ) from the query string, before hitting elastic to prevent the words from being
+ * used against the elastic view-and-inspect index. Another alternative to this approach would
+ * be to define stop words on the elastic search index configuration for the
+ * entity-search-index, but but that may be more complicated / more risky than just a simple bug
+ * fix, but it's something we should think about for the future.
+ */
+
+ try {
+ final String queryStringWithoutStopWords =
+ stripStopWordsFromQuery(queryRequest.getQueryStr());
+
+ final String fullUrlStr = searchServiceAdapter.buildSearchServiceQueryUrl(viewInspectIndexName);
+
+ String postBody = String.format(VIUI_SEARCH_TEMPLATE, Integer.parseInt(queryRequest.getMaxResults()),
+ queryStringWithoutStopWords);
+
+ OperationResult opResult = searchServiceAdapter.doPost(fullUrlStr, postBody, "application/json");
+ if (opResult.getResultCode() == 200) {
+ suggestionEntityList =
+ generateSuggestionsForSearchResponse(opResult.getResult(), queryRequest.getQueryStr());
+ }
+ } catch (Exception exc) {
+ LOG.error(AaiUiMsgs.SEARCH_SERVLET_ERROR,
+ "View and inspect query failed with error = " + exc.getMessage());
+ }
+ return suggestionEntityList;
+
+
+ }
+
+ public String getAdditionalSearchSuggestionText() {
+ return additionalSearchSuggestionText;
+ }
+
+ public void setAdditionalSearchSuggestionText(String additionalSearchSuggestionText) {
+ this.additionalSearchSuggestionText = additionalSearchSuggestionText;
+ }
+
+
+
+
+ /**
+ * Builds the search response.
+ *
+ * @param operationResult The Elasticsearch query result
+ * @param queryStr The string the user typed into the search bar
+ * @return A list of search suggestions and corresponding UI filter values
+ */
+ private List<SearchSuggestion> generateSuggestionsForSearchResponse(String operationResult,
+ String queryStr) {
+
+
+ if (operationResult == null || operationResult.length() == 0) {
+ return null;
+ }
+
+ ObjectMapper mapper = new ObjectMapper();
+ JsonNode rootNode = null;
+ List<SearchSuggestion> suggestionEntityList = new ArrayList<SearchSuggestion>();
+ try {
+ rootNode = mapper.readTree(operationResult);
+
+ JsonNode hitsNode = rootNode.get(KEY_SEARCH_RESULT);
+
+
+
+ // Check if there are hits that are coming back
+ if (hitsNode.has(KEY_HITS)) {
+ ArrayNode hitsArray = (ArrayNode) hitsNode.get(KEY_HITS);
+
+ /*
+ * next we iterate over the values in the hit array elements
+ */
+
+ Iterator<JsonNode> nodeIterator = hitsArray.elements();
+ JsonNode entityNode = null;
+ CommonSearchSuggestion suggestionEntity = null;
+ JsonNode sourceNode = null;
+ while (nodeIterator.hasNext()) {
+ entityNode = nodeIterator.next();
+ sourceNode = entityNode.get(KEY_DOCUMENT).get(KEY_CONTENT);
+
+ // do the point transformation as we build the response?
+ suggestionEntity = new CommonSearchSuggestion();
+ suggestionEntity.setRoute(viewInspectSuggestionRoute);
+
+ /*
+ * This is where we probably want to annotate the search tags because we also have access
+ * to the seachTagIds
+ */
+
+ String searchTagIds = getValueFromNode(sourceNode, KEY_SEARCH_TAG_IDS);
+ String searchTags = getValueFromNode(sourceNode, KEY_SEARCH_TAGS);
+ String entityType = getValueFromNode(sourceNode, KEY_ENTITY_TYPE);
+ String link = getValueFromNode(sourceNode, KEY_LINK);
+
+ if (link != null) {
+ suggestionEntity.setHashId(NodeUtils.generateUniqueShaDigest(link));
+ }
+
+ try {
+ suggestionEntity
+ .setText(annotateSearchTags(searchTags, searchTagIds, entityType, queryStr));
+ } catch (Exception exc) {
+ LOG.error(AaiUiMsgs.SEARCH_TAG_ANNOTATION_ERROR, searchTags.toString(),
+ exc.getLocalizedMessage());
+ // at least send back the un-annotated search tags
+ suggestionEntity.setText(searchTags);
+ }
+
+ if ( getAdditionalSearchSuggestionText() != null ) {
+ String suggestionText = suggestionEntity.getText() ;
+ suggestionText += SparkyConstants.SUGGESTION_TEXT_SEPARATOR
+ + getAdditionalSearchSuggestionText();
+ suggestionEntity.setText(suggestionText);
+ }
+
+ if (searchTags != null) {
+ suggestionEntityList.add(suggestionEntity);
+ }
+
+ }
+ }
+ } catch (IOException exc) {
+ LOG.warn(AaiUiMsgs.SEARCH_RESPONSE_BUILDING_EXCEPTION, exc.getLocalizedMessage());
+ }
+ return suggestionEntityList;
+ }
+
+
+
+ /**
+ * The current format of an UI-dropdown-item is like: "search-terms entityType att1=attr1_val".
+ * Example, for pserver: search-terms pserver hostname=djmAG-72060,
+ * pserver-name2=example-pserver-name2-val-17254, pserver-id=example-pserver-id-val-17254,
+ * ipv4-oam-address=example-ipv4-oam-address-val-17254 SearchController.js parses the above
+ * format. So if you are modifying the parsing below, please update SearchController.js as well.
+ *
+ * @param searchTags the search tags
+ * @param searchTagIds the search tag ids
+ * @param entityType the entity type
+ * @param queryStr the query str
+ * @return the string
+ */
+
+ private String annotateSearchTags(String searchTags, String searchTagIds, String entityType,
+ String queryStr) {
+
+ if (searchTags == null || searchTagIds == null) {
+ String valueOfSearchTags = String.valueOf(searchTags);
+ String valueOfSearchTagIds = String.valueOf(searchTagIds);
+
+ LOG.error(AaiUiMsgs.SEARCH_TAG_ANNOTATION_ERROR, "See error",
+ "Search tags = " + valueOfSearchTags + " and Seach tag IDs = " + valueOfSearchTagIds);
+ return searchTags;
+ }
+
+ if (entityType == null) {
+ LOG.error(AaiUiMsgs.SEARCH_TAG_ANNOTATION_ERROR, searchTags.toString(), "EntityType is null");
+ return searchTags;
+ }
+
+ if (queryStr == null) {
+ LOG.error(AaiUiMsgs.SEARCH_TAG_ANNOTATION_ERROR, searchTags.toString(),
+ "Query string is null");
+ return searchTags;
+ }
+
+ /*
+ * The ElasticSearch analyzer has already applied the lowercase filter, so we don't have to
+ * covert them again
+ */
+ String[] searchTagsArray = searchTags.split(";");
+ String[] searchTagIdsArray = searchTagIds.split(";");
+
+ // specifically apply lower case to the the query terms to make matching
+ // simpler
+ String[] queryTerms = queryStr.toLowerCase().split(" ");
+
+ OxmEntityDescriptor desc = oxmEntityLookup.getEntityDescriptors().get(entityType);
+
+ if (desc == null) {
+ LOG.error(AaiUiMsgs.ENTITY_NOT_FOUND_IN_OXM, entityType.toString());
+ return searchTags;
+ }
+
+ String primaryKeyName = NodeUtils.concatArray(desc.getPrimaryKeyAttributeNames(), "/");
+ String primaryKeyValue = null;
+
+ /*
+ * For each used attribute, get the fieldName for the attribute index and transform the search
+ * tag into t1,t2,t3 => h1=t1, h2=t2, h3=t3;
+ */
+ StringBuilder searchTagsBuilder = new StringBuilder(128);
+ searchTagsBuilder.append(entityType);
+
+ String primaryKeyConjunctionValue = null;
+ boolean queryTermsMatchedSearchTags = false;
+
+ if (searchTagsArray.length == searchTagIdsArray.length) {
+ for (int i = 0; i < searchTagsArray.length; i++) {
+ String searchTagAttributeId = searchTagIdsArray[i];
+ String searchTagAttributeValue = searchTagsArray[i];
+
+ // Find the concat conjunction
+ Map<String, String> pairConjunctionList = suggestionConfig.getPairingList();
+
+ String suggConjunction = null;
+ if (pairConjunctionList.get(searchTagAttributeId) != null) {
+ suggConjunction = pairConjunctionList.get(searchTagAttributeId);
+ } else {
+ suggConjunction = suggestionConfig.getDefaultPairingValue();
+ }
+
+ if (primaryKeyName.equals(searchTagAttributeId)) {
+ primaryKeyValue = searchTagAttributeValue;
+ primaryKeyConjunctionValue = suggConjunction;
+ }
+
+ if (queryTermsMatchSearchTag(queryTerms, searchTagAttributeValue)) {
+ searchTagsBuilder.append(" " + suggConjunction + " " + searchTagAttributeValue);
+ queryTermsMatchedSearchTags = true;
+ }
+ }
+ } else {
+ String errorMessage =
+ "Search tags length did not match search tag ID length for entity type " + entityType;
+ LOG.error(AaiUiMsgs.ENTITY_SYNC_SEARCH_TAG_ANNOTATION_FAILED, errorMessage);
+ }
+
+
+
+ /*
+ * if none of the user query terms matched the index entity search tags then we should still tag
+ * the matched entity with a conjunction set to at least it's entity primary key value to
+ * discriminate between the entities of the same type in the search results displayed in the UI
+ * search bar results
+ */
+
+ if (!queryTermsMatchedSearchTags) {
+
+ if (primaryKeyValue != null && primaryKeyConjunctionValue != null) {
+ searchTagsBuilder.append(" " + primaryKeyConjunctionValue + " " + primaryKeyValue);
+ } else {
+ LOG.error(AaiUiMsgs.SEARCH_TAG_ANNOTATION_ERROR, "See error",
+ "Could not annotate user query terms " + queryStr
+ + " from available entity search tags = " + searchTags);
+ return searchTags;
+ }
+
+ }
+
+ return searchTagsBuilder.toString();
+
+ }
+
+ /**
+ * Query terms match search tag.
+ *
+ * @param queryTerms the query terms
+ * @param searchTag the search tag
+ * @return true, if successful @return.
+ */
+ private boolean queryTermsMatchSearchTag(String[] queryTerms, String searchTag) {
+
+ if (queryTerms == null || queryTerms.length == 0 || searchTag == null) {
+ return false;
+ }
+
+ for (String queryTerm : queryTerms) {
+ if (searchTag.toLowerCase().contains(queryTerm.toLowerCase())) {
+ return true;
+ }
+ }
+
+ return false;
+
+ }
+
+ /**
+ * Gets the value from node.
+ *
+ * @param node the node
+ * @param fieldName the field name
+ * @return the value from node
+ */
+ private String getValueFromNode(JsonNode node, String fieldName) {
+
+ if (node == null || fieldName == null) {
+ return null;
+ }
+
+ JsonNode valueNode = node.get(fieldName);
+
+ if (valueNode != null) {
+ return valueNode.asText();
+ }
+
+ return null;
+
+ }
+
+ private static final String VIUI_SEARCH_TEMPLATE =
+ "{ " + "\"results-start\": 0," + "\"results-size\": %d," + "\"queries\": [{" + "\"must\": {"
+ + "\"match\": {" + "\"field\": \"entityType searchTags crossEntityReferenceValues\","
+ + "\"value\": \"%s\"," + "\"operator\": \"and\", "
+ + "\"analyzer\": \"whitespace_analyzer\"" + "}" + "}" + "}]" + "}";
+
+ //private SuggestionConfig suggestionConfig = null;
+
+ /**
+ * @param queryStr - space separate query search terms
+ * @return - query string with stop-words removed
+ */
+ private String stripStopWordsFromQuery(String queryStr) {
+
+ if (queryStr == null) {
+ return queryStr;
+ }
+
+ Collection<String> stopWords = suggestionConfig.getStopWords();
+ ArrayList<String> queryTerms =
+ new ArrayList<String>(Arrays.asList(queryStr.toLowerCase().split(" ")));
+
+ queryTerms.removeAll(stopWords);
+
+ return String.join(" ", queryTerms);
+ }
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/services/BaseGizmoVisualizationContext.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/services/BaseGizmoVisualizationContext.java
new file mode 100644
index 0000000..d0cabfe
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/services/BaseGizmoVisualizationContext.java
@@ -0,0 +1,990 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.viewandinspect.services;
+
+import static java.util.concurrent.CompletableFuture.supplyAsync;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.onap.aai.cl.api.Logger;
+import org.onap.aai.cl.eelf.LoggerFactory;
+import org.onap.aai.restclient.client.OperationResult;
+import org.onap.aai.sparky.config.oxm.OxmEntityDescriptor;
+import org.onap.aai.sparky.config.oxm.OxmEntityLookup;
+import org.onap.aai.sparky.dal.GizmoAdapter;
+import org.onap.aai.sparky.logging.AaiUiMsgs;
+import org.onap.aai.sparky.sync.entity.SearchableEntity;
+import org.onap.aai.sparky.util.NodeUtils;
+import org.onap.aai.sparky.viewandinspect.config.SparkyConstants;
+import org.onap.aai.sparky.viewandinspect.config.VisualizationConfigs;
+import org.onap.aai.sparky.viewandinspect.entity.ActiveInventoryNode;
+import org.onap.aai.sparky.viewandinspect.entity.GizmoEntity;
+import org.onap.aai.sparky.viewandinspect.entity.GizmoRelationshipEntity;
+import org.onap.aai.sparky.viewandinspect.entity.GizmoRelationshipHint;
+import org.onap.aai.sparky.viewandinspect.entity.InlineMessage;
+import org.onap.aai.sparky.viewandinspect.entity.NodeProcessingTransaction;
+import org.onap.aai.sparky.viewandinspect.entity.QueryParams;
+import org.onap.aai.sparky.viewandinspect.enumeration.NodeProcessingAction;
+import org.onap.aai.sparky.viewandinspect.enumeration.NodeProcessingState;
+import org.onap.aai.sparky.viewandinspect.task.PerformGizmoNodeSelfLinkProcessingTask;
+
+import com.fasterxml.jackson.annotation.JsonInclude.Include;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.PropertyNamingStrategy;
+
+/**
+ * The Class SelfLinkNodeCollector.
+ */
+public class BaseGizmoVisualizationContext implements VisualizationContext {
+
+ private static final int MAX_DEPTH_EVALUATION_ATTEMPTS = 100;
+
+ private static final Logger LOG =
+ LoggerFactory.getInstance().getLogger(BaseGizmoVisualizationContext.class);
+
+ private final GizmoAdapter gizmoAdapter;
+
+ private AtomicInteger numLinksDiscovered;
+ private AtomicInteger numSuccessfulLinkResolveFromCache;
+ private AtomicInteger numSuccessfulLinkResolveFromFromServer;
+ private AtomicInteger numFailedLinkResolve;
+ private AtomicInteger aaiWorkOnHand;
+
+ private VisualizationConfigs visualizationConfigs;
+
+ private AtomicInteger totalLinksRetrieved;
+
+ private final long contextId;
+ private final String contextIdStr;
+ private long lastProcessStatesSummaryLogInMs = -1;
+
+
+ private ObjectMapper mapper;
+ private InlineMessage inlineMessage = null;
+
+ private ExecutorService graphExecutorService;
+ private OxmEntityLookup oxmEntityLookup;
+ private boolean rootNodeFound;
+
+ /*
+ * The node cache is intended to be a flat structure indexed by a primary key to avoid needlessly
+ * re-requesting the same self-links over-and-over again, to speed up the overall render time and
+ * more importantly to reduce the network cost of determining information we already have.
+ */
+ private ConcurrentHashMap<String, ActiveInventoryNode> nodeCache;
+
+ /**
+ * Instantiates a new self link node collector.
+ *
+ * @param loader the loader
+ * @throws Exception the exception
+ */
+ public BaseGizmoVisualizationContext(long contextId, GizmoAdapter gizmoAdapter,
+ ExecutorService graphExecutorService, VisualizationConfigs visualizationConfigs,
+ OxmEntityLookup oxmEntityLookup) throws Exception {
+
+ this.contextId = contextId;
+ this.contextIdStr = "[Context-Id=" + contextId + "]";
+ this.gizmoAdapter = gizmoAdapter;
+ this.graphExecutorService = graphExecutorService;
+ this.visualizationConfigs = visualizationConfigs;
+ this.oxmEntityLookup = oxmEntityLookup;
+
+ this.nodeCache = new ConcurrentHashMap<String, ActiveInventoryNode>();
+ this.numLinksDiscovered = new AtomicInteger(0);
+ this.totalLinksRetrieved = new AtomicInteger(0);
+ this.numSuccessfulLinkResolveFromCache = new AtomicInteger(0);
+ this.numSuccessfulLinkResolveFromFromServer = new AtomicInteger(0);
+ this.numFailedLinkResolve = new AtomicInteger(0);
+ this.aaiWorkOnHand = new AtomicInteger(0);
+
+ this.mapper = new ObjectMapper();
+ mapper.setSerializationInclusion(Include.NON_EMPTY);
+ mapper.setPropertyNamingStrategy(new PropertyNamingStrategy.KebabCaseStrategy());
+ this.rootNodeFound = false;
+ }
+
+ protected boolean isRootNodeFound() {
+ return rootNodeFound;
+ }
+
+ protected void setRootNodeFound(boolean rootNodeFound) {
+ this.rootNodeFound = rootNodeFound;
+ }
+
+ public long getContextId() {
+ return contextId;
+ }
+
+ public GizmoAdapter getGizmoAdapter() {
+ return gizmoAdapter;
+ }
+
+ /**
+ * Process self link response.
+ *
+ * @param nodeId the node id
+ */
+ private void processSelfLinkResponse(String nodeId) {
+
+ if (nodeId == null) {
+ LOG.error(AaiUiMsgs.SELF_LINK_PROCESSING_ERROR,
+ "Cannot process self link" + " response because nodeId is null");
+ return;
+ }
+
+ ActiveInventoryNode ain = nodeCache.get(nodeId);
+
+ if (ain == null) {
+ LOG.error(AaiUiMsgs.SELF_LINK_PROCESSING_ERROR,
+ "Cannot process self link response" + " because can't find node for id = " + nodeId);
+ return;
+ }
+
+ GizmoEntity gizmoEntity = null;
+
+ try {
+ gizmoEntity = mapper.readValue(ain.getOpResult().getResult(), GizmoEntity.class);
+ } catch (Exception exc) {
+ exc.printStackTrace();
+ LOG.error(AaiUiMsgs.SELF_LINK_JSON_PARSE_ERROR, "Failed to marshal json"
+ + " response str into JsonNode with error, " + exc.getLocalizedMessage());
+ ain.changeState(NodeProcessingState.ERROR,
+ NodeProcessingAction.SELF_LINK_RESPONSE_PARSE_ERROR);
+ return;
+ }
+
+ if (gizmoEntity == null) {
+
+ LOG.error(AaiUiMsgs.SELF_LINK_JSON_PARSE_ERROR,
+ "Failed to parse json node str." + " Parse resulted a null value.");
+ ain.changeState(NodeProcessingState.ERROR,
+ NodeProcessingAction.SELF_LINK_RESPONSE_PARSE_ERROR);
+ return;
+ }
+
+ /*
+ * Now that we have the gizmo entity we can populate the AIN node with it, as well as the
+ * relationships
+ */
+
+ ain.setEntityType(gizmoEntity.getType());
+
+ ain.setPrimaryKeyName(getEntityTypePrimaryKeyName(gizmoEntity.getType()));
+
+ OxmEntityDescriptor descriptor = oxmEntityLookup.getEntityDescriptors().get(gizmoEntity);
+
+ if (descriptor != null) {
+ ain.setPrimaryKeyValue(getPrimaryKeyValues(gizmoEntity.getProperties(),
+ descriptor.getPrimaryKeyAttributeNames()));
+ } else {
+ LOG.error(AaiUiMsgs.ERROR_GENERIC, "Could not determine oxm descriptor for entity type = " + gizmoEntity.getType());
+ }
+
+ gizmoEntity.getProperties().forEach((key, value) -> {
+ ain.getProperties().put(key, value);
+ });
+
+ // add edit attributes link
+ if (ain.getSelfLink() != null) {
+ ain.addProperty(SparkyConstants.URI_ATTR_NAME, ain.getSelfLink());
+ }
+
+
+
+ /*
+ * Only discover neighbors if our depth is less than the Max-Traversal-Depth
+ */
+
+ if (ain.getNodeDepth() < this.visualizationConfigs.getMaxSelfLinkTraversalDepth()) {
+
+ /*
+ * I think the next thing to do is:
+ *
+ * 1. Calculate the source / target node id 2. Add the nodeId to the incoming / outgoing links
+ * collection 3. Add the node to the node cache for processing
+ */
+
+ String resourceLink = null;
+ String relationshipNodeId = null;
+ ActiveInventoryNode relationshipNode = null;
+
+ for (GizmoRelationshipHint inRelationship : gizmoEntity.getIn()) {
+
+ if (inRelationship.getSource() != null) {
+
+ resourceLink = NodeUtils.extractRawGizmoPathWithoutVersion(inRelationship.getSource());
+ relationshipNodeId = NodeUtils.generateUniqueShaDigest(resourceLink);
+
+ if (!nodeCache.containsKey(relationshipNodeId)) {
+
+ relationshipNode = new ActiveInventoryNode(visualizationConfigs, oxmEntityLookup);
+ relationshipNode.setNodeId(relationshipNodeId);
+ relationshipNode.setSelfLink(resourceLink);
+ relationshipNode.changeState(NodeProcessingState.SELF_LINK_UNRESOLVED,
+ NodeProcessingAction.NEW_NODE_PROCESSED);
+
+ ain.addInboundNeighbor(relationshipNodeId);
+
+ addNode(relationshipNode);
+
+ }
+ }
+
+ }
+
+ for (GizmoRelationshipHint outRelationship : gizmoEntity.getOut()) {
+
+ if (outRelationship.getTarget() != null) {
+
+ resourceLink = NodeUtils.extractRawGizmoPathWithoutVersion(outRelationship.getTarget());
+ relationshipNodeId = NodeUtils.generateUniqueShaDigest(resourceLink);
+
+ if (!nodeCache.containsKey(relationshipNodeId)) {
+
+ relationshipNode = new ActiveInventoryNode(visualizationConfigs, oxmEntityLookup);
+ relationshipNode.setNodeId(relationshipNodeId);
+ relationshipNode.setSelfLink(resourceLink);
+ relationshipNode.changeState(NodeProcessingState.SELF_LINK_UNRESOLVED,
+ NodeProcessingAction.NEW_NODE_PROCESSED);
+
+ ain.addOutboundNeighbor(relationshipNodeId);
+
+ addNode(relationshipNode);
+
+ }
+ }
+
+ }
+ }
+
+ ain.changeState(NodeProcessingState.READY, NodeProcessingAction.SELF_LINK_RESPONSE_PARSE_OK);
+
+ }
+
+ /**
+ * Perform self link resolve.
+ *
+ * @param nodeId the node id
+ */
+ private void performSelfLinkResolve(String nodeId) {
+
+ if (nodeId == null) {
+ LOG.error(AaiUiMsgs.SELF_LINK_PROCESSING_ERROR,
+ "Resolve of self-link" + " has been skipped because provided nodeId is null");
+ return;
+ }
+
+ ActiveInventoryNode ain = nodeCache.get(nodeId);
+
+ if (ain == null) {
+ LOG.error(AaiUiMsgs.SELF_LINK_PROCESSING_ERROR, "Failed to find node with id, " + nodeId
+ + ", from node cache. Resolve self-link method has been skipped.");
+ return;
+ }
+
+ if (!ain.isSelfLinkPendingResolve()) {
+
+ ain.setSelfLinkPendingResolve(true);
+
+ // kick off async self-link resolution
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug(AaiUiMsgs.DEBUG_GENERIC,
+ "About to process node in SELF_LINK_UNPROCESSED State, link = " + ain.getSelfLink());
+ }
+
+ numLinksDiscovered.incrementAndGet();
+
+ /*
+ * If the current node is the search target, we want to see everything the node has to offer
+ * from the self-link and not filter it to a single node.
+ */
+
+ NodeProcessingTransaction txn = new NodeProcessingTransaction();
+ txn.setProcessingNode(ain);
+ txn.setRequestParameters(null);
+ aaiWorkOnHand.incrementAndGet();
+ supplyAsync(new PerformGizmoNodeSelfLinkProcessingTask(txn, null, gizmoAdapter),
+ graphExecutorService).whenComplete((nodeTxn, error) -> {
+
+ if (error != null) {
+
+ /*
+ * an error processing the self link should probably result in the node processing
+ * state shifting to ERROR
+ */
+
+ nodeTxn.getProcessingNode().setSelflinkRetrievalFailure(true);
+
+ nodeTxn.getProcessingNode().changeState(NodeProcessingState.ERROR,
+ NodeProcessingAction.SELF_LINK_RESOLVE_ERROR);
+
+ nodeTxn.getProcessingNode().setSelfLinkPendingResolve(false);
+
+ } else {
+
+ totalLinksRetrieved.incrementAndGet();
+
+ OperationResult opResult = nodeTxn.getOpResult();
+
+ if (opResult != null && opResult.wasSuccessful()) {
+
+ if (!opResult.wasSuccessful()) {
+ numFailedLinkResolve.incrementAndGet();
+ }
+
+ if (opResult.isFromCache()) {
+ numSuccessfulLinkResolveFromCache.incrementAndGet();
+ } else {
+ numSuccessfulLinkResolveFromFromServer.incrementAndGet();
+ }
+
+ // success path
+ nodeTxn.getProcessingNode().setOpResult(opResult);
+ nodeTxn.getProcessingNode().changeState(
+ NodeProcessingState.SELF_LINK_RESPONSE_UNPROCESSED,
+ NodeProcessingAction.SELF_LINK_RESOLVE_OK);
+
+ nodeTxn.getProcessingNode().setSelfLinkProcessed(true);
+ nodeTxn.getProcessingNode().setSelfLinkPendingResolve(false);
+
+ } else {
+ LOG.error(AaiUiMsgs.SELF_LINK_PROCESSING_ERROR,
+ "Self Link retrieval for link," + txn.getSelfLinkWithModifiers()
+ + ", failed with error code," + nodeTxn.getOpResult().getResultCode()
+ + ", and message," + nodeTxn.getOpResult().getResult());
+
+ nodeTxn.getProcessingNode().setSelflinkRetrievalFailure(true);
+ nodeTxn.getProcessingNode().setSelfLinkProcessed(true);
+
+ nodeTxn.getProcessingNode().changeState(NodeProcessingState.ERROR,
+ NodeProcessingAction.SELF_LINK_RESOLVE_ERROR);
+
+ nodeTxn.getProcessingNode().setSelfLinkPendingResolve(false);
+
+ }
+ }
+
+ aaiWorkOnHand.decrementAndGet();
+
+ });
+
+ }
+
+ }
+
+ public GizmoRelationshipEntity getGizmoRelationshipEntity(String gizmoJsonResponse) {
+
+ GizmoRelationshipEntity gizmoRelationship = null;
+ try {
+ gizmoRelationship = mapper.readValue(gizmoJsonResponse, GizmoRelationshipEntity.class);
+ } catch (IOException exc) {
+ LOG.error(AaiUiMsgs.ERROR_GENERIC, "Failed to map json to GizmoRelationshipEntity. Error: " + exc.getMessage());
+ }
+
+ return gizmoRelationship;
+
+ }
+
+ public String getPrimaryKeyValues(Map<String, String> properties, List<String> pkeyNames) {
+
+ StringBuilder sb = new StringBuilder(64);
+
+ if (pkeyNames.size() > 0) {
+ String primaryKey = properties.get(pkeyNames.get(0));
+ if (primaryKey != null) {
+ sb.append(primaryKey);
+ } else {
+ // this should be a fatal error because unless we can
+ // successfully retrieve all the expected keys we'll end up
+ // with a garbage node
+ LOG.error(AaiUiMsgs.EXTRACTION_ERROR, "ERROR: Failed to extract" + " keyName, "
+ + pkeyNames.get(0) + ", from properties , " + properties);
+ return null;
+ }
+
+ for (int i = 1; i < pkeyNames.size(); i++) {
+
+ String kv = properties.get(pkeyNames.get(i));
+ if (kv != null) {
+ sb.append("/").append(kv);
+ } else {
+ // this should be a fatal error because unless we can
+ // successfully retrieve all the expected keys we'll end up
+ // with a garbage node
+ LOG.error(AaiUiMsgs.EXTRACTION_ERROR, "ERROR: failed to extract keyName, "
+ + pkeyNames.get(i) + ", from properties, " + properties);
+ return null;
+ }
+ }
+
+ return sb.toString();
+
+ }
+
+ return null;
+
+ }
+
+
+
+ /**
+ * Find and mark root node.
+ *
+ * @param queryParams the query params
+ * @return true, if successful
+ */
+ private void findAndMarkRootNode(QueryParams queryParams) {
+
+ if (isRootNodeFound()) {
+ return;
+ }
+
+ for (ActiveInventoryNode cacheNode : nodeCache.values()) {
+
+ if (queryParams.getSearchTargetNodeId().equals(cacheNode.getNodeId())) {
+ cacheNode.setNodeDepth(0);
+ cacheNode.setRootNode(true);
+ LOG.info(AaiUiMsgs.ROOT_NODE_DISCOVERED, queryParams.getSearchTargetNodeId());
+ setRootNodeFound(true);
+ }
+ }
+
+ }
+
+ public void addNode(ActiveInventoryNode node) {
+
+ if (node == null) {
+ return;
+ }
+
+ nodeCache.putIfAbsent(node.getNodeId(), node);
+ }
+
+ public VisualizationConfigs getVisualizationConfigs() {
+ return visualizationConfigs;
+ }
+
+ public void setVisualizationConfigs(VisualizationConfigs visualizationConfigs) {
+ this.visualizationConfigs = visualizationConfigs;
+ }
+
+ public OxmEntityLookup getOxmEntityLookup() {
+ return oxmEntityLookup;
+ }
+
+ public void setOxmEntityLookup(OxmEntityLookup oxmEntityLookup) {
+ this.oxmEntityLookup = oxmEntityLookup;
+ }
+
+ public ObjectMapper getMapper() {
+ return mapper;
+ }
+
+ public void setMapper(ObjectMapper mapper) {
+ this.mapper = mapper;
+ }
+
+ private void dumpThrottledWorkOnHandLog() {
+ dumpThrottledWorkOnHandLog(false);
+ }
+
+ private void dumpThrottledWorkOnHandLog(boolean override) {
+
+ if ((lastProcessStatesSummaryLogInMs < 0)
+ || ((System.currentTimeMillis() > (lastProcessStatesSummaryLogInMs + 5000))) || override) {
+
+ lastProcessStatesSummaryLogInMs = System.currentTimeMillis();
+
+ int numInit = 0;
+ int numReady = 0;
+ int numError = 0;
+ int numSelfLinkUnresolved = 0;
+ int numSelfLinkResponseUnprocessed = 0;
+
+ for (ActiveInventoryNode cacheNode : nodeCache.values()) {
+
+ switch (cacheNode.getState()) {
+
+ case INIT: {
+ numInit++;
+ break;
+ }
+
+ case READY: {
+ numReady++;
+ break;
+ }
+ case ERROR: {
+ numError++;
+ break;
+ }
+
+ case SELF_LINK_UNRESOLVED: {
+ numSelfLinkUnresolved++;
+ break;
+ }
+
+ case SELF_LINK_RESPONSE_UNPROCESSED: {
+ numSelfLinkResponseUnprocessed++;
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ }
+
+ LOG.info(AaiUiMsgs.INFO_GENERIC,
+ String.format(
+ "ProcessCurrentStates for ContextId=%s, [PendingTxns=%d, numInit=%d, numSelfLinkUnresolved=%d, numSelfLinkResponseUnProcessed=%d, numReady=%d, numError=%d]",
+ contextIdStr, aaiWorkOnHand.get(), numInit, numSelfLinkUnresolved, numSelfLinkResponseUnprocessed,
+ numReady, numError));
+ }
+
+ }
+
+ /**
+ * Process current node states.
+ *
+ * @param rootNodeDiscovered the root node discovered
+ */
+ private void processCurrentNodeStates(QueryParams queryParams) {
+ /*
+ * Force an evaluation of node depths before determining if we should limit state-based
+ * traversal or processing.
+ */
+
+ findAndMarkRootNode(queryParams);
+
+ verifyOutboundNeighbors();
+
+ for (ActiveInventoryNode cacheNode : nodeCache.values()) {
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug(AaiUiMsgs.DEBUG_GENERIC, "processCurrentNodeState(), nid = "
+ + cacheNode.getNodeId() + " , nodeDepth = " + cacheNode.getNodeDepth());
+ }
+
+ switch (cacheNode.getState()) {
+
+ case INIT: {
+ processInitialState(cacheNode.getNodeId());
+ break;
+ }
+
+ case READY:
+ case ERROR: {
+ break;
+ }
+
+ case SELF_LINK_UNRESOLVED: {
+ performSelfLinkResolve(cacheNode.getNodeId());
+ break;
+ }
+
+ case SELF_LINK_RESPONSE_UNPROCESSED: {
+ processSelfLinkResponse(cacheNode.getNodeId());
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ }
+
+ dumpThrottledWorkOnHandLog();
+
+ }
+
+
+
+ public int getNumSuccessfulLinkResolveFromCache() {
+ return numSuccessfulLinkResolveFromCache.get();
+ }
+
+ public int getNumSuccessfulLinkResolveFromFromServer() {
+ return numSuccessfulLinkResolveFromFromServer.get();
+ }
+
+ public int getNumFailedLinkResolve() {
+ return numFailedLinkResolve.get();
+ }
+
+ public InlineMessage getInlineMessage() {
+ return inlineMessage;
+ }
+
+ public void setInlineMessage(InlineMessage inlineMessage) {
+ this.inlineMessage = inlineMessage;
+ }
+
+ public ConcurrentHashMap<String, ActiveInventoryNode> getNodeCache() {
+ return nodeCache;
+ }
+
+
+
+ /**
+ * Process initial state.
+ *
+ * @param nodeId the node id
+ */
+ private void processInitialState(String nodeId) {
+
+ if (nodeId == null) {
+ LOG.error(AaiUiMsgs.FAILED_TO_PROCESS_INITIAL_STATE, "Node id is null");
+ return;
+ }
+
+ ActiveInventoryNode cachedNode = nodeCache.get(nodeId);
+
+ if (cachedNode == null) {
+ LOG.error(AaiUiMsgs.FAILED_TO_PROCESS_INITIAL_STATE,
+ "Node cannot be" + " found for nodeId, " + nodeId);
+ return;
+ }
+
+ if (cachedNode.getSelfLink() == null) {
+
+ if (cachedNode.getNodeId() == null) {
+
+ /*
+ * if the self link is null at the INIT state, which could be valid if this node is a
+ * complex attribute group which didn't originate from a self-link, but in that situation
+ * both the node id and node key should already be set.
+ */
+
+ cachedNode.changeState(NodeProcessingState.ERROR, NodeProcessingAction.NODE_IDENTITY_ERROR);
+
+ }
+
+ if (cachedNode.getNodeId() != null) {
+
+ /*
+ * This should be the success path branch if the self-link is not set
+ */
+
+ cachedNode.changeState(NodeProcessingState.SELF_LINK_RESPONSE_UNPROCESSED,
+ NodeProcessingAction.SELF_LINK_RESPONSE_PARSE_OK);
+
+ }
+
+ } else {
+
+ if (cachedNode.hasResolvedSelfLink()) {
+ LOG.error(AaiUiMsgs.INVALID_RESOLVE_STATE_DURING_INIT);
+ cachedNode.changeState(NodeProcessingState.ERROR,
+ NodeProcessingAction.UNEXPECTED_STATE_TRANSITION);
+ } else {
+ cachedNode.changeState(NodeProcessingState.SELF_LINK_UNRESOLVED,
+ NodeProcessingAction.SELF_LINK_SET);
+ }
+ }
+ }
+
+ /**
+ * Process skeleton node.
+ *
+ * @param skeletonNode the skeleton node
+ * @param queryParams the query params
+ */
+ private void processSearchableEntity(SearchableEntity searchTargetEntity,
+ QueryParams queryParams) {
+
+ if (searchTargetEntity == null) {
+ return;
+ }
+
+ if (searchTargetEntity.getId() == null) {
+ LOG.error(AaiUiMsgs.FAILED_TO_PROCESS_SKELETON_NODE, "Failed to process skeleton"
+ + " node because nodeId is null for node, " + searchTargetEntity.getLink());
+ return;
+ }
+
+ ActiveInventoryNode newNode =
+ new ActiveInventoryNode(this.visualizationConfigs, oxmEntityLookup);
+
+ newNode.setNodeId(searchTargetEntity.getId());
+
+ newNode.setNodeDepth(0);
+ newNode.setRootNode(true);
+ LOG.info(AaiUiMsgs.ROOT_NODE_DISCOVERED, queryParams.getSearchTargetNodeId());
+ setRootNodeFound(true);
+
+ newNode.setSelfLink(searchTargetEntity.getLink());
+
+ nodeCache.putIfAbsent(newNode.getNodeId(), newNode);
+ }
+
+ private int getTotalWorkOnHand() {
+
+ int numNodesWithPendingStates = 0;
+
+ if (isRootNodeFound()) {
+ evaluateNodeDepths();
+ }
+
+ for (ActiveInventoryNode n : nodeCache.values()) {
+
+ switch (n.getState()) {
+
+ case READY:
+ case ERROR: {
+ // do nothing, these are our normal
+ // exit states
+ break;
+ }
+
+ default: {
+
+ /*
+ * for all other states, there is work to be done
+ */
+ numNodesWithPendingStates++;
+ }
+
+ }
+
+ }
+
+ return (aaiWorkOnHand.get() + numNodesWithPendingStates);
+
+ }
+
+ /**
+ * Checks for out standing work.
+ *
+ * @return true, if successful
+ */
+ private void processOutstandingWork(QueryParams queryParams) {
+
+ while (getTotalWorkOnHand() > 0) {
+
+ /*
+ * Force an evaluation of node depths before determining if we should limit state-based
+ * traversal or processing.
+ */
+
+ processCurrentNodeStates(queryParams);
+
+ try {
+ Thread.sleep(10);
+ } catch (InterruptedException exc) {
+ LOG.error(AaiUiMsgs.PROCESSING_LOOP_INTERUPTED, exc.getMessage());
+ return;
+ }
+
+ }
+
+ dumpThrottledWorkOnHandLog(true);
+
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.onap.aai.sparky.viewandinspect.services.VisualizationContext#processSelfLinks(org.onap.aai.
+ * sparky.sync.entity.SearchableEntity, org.onap.aai.sparky.viewandinspect.entity.QueryParams)
+ */
+ @Override
+ public void processSelfLinks(SearchableEntity searchtargetEntity, QueryParams queryParams) {
+
+ try {
+
+
+ if (searchtargetEntity == null) {
+ LOG.error(AaiUiMsgs.SELF_LINK_PROCESSING_ERROR,
+ contextIdStr + " - Failed to" + " processSelfLinks, searchtargetEntity is null");
+ return;
+ }
+
+ long startTimeInMs = System.currentTimeMillis();
+
+ processSearchableEntity(searchtargetEntity, queryParams);
+
+ /*
+ * This method is blocking until we decouple it with a CountDownLatch await condition, and
+ * make the internal graph processing more event-y.
+ */
+
+ processOutstandingWork(queryParams);
+
+ long totalResolveTime = (System.currentTimeMillis() - startTimeInMs);
+
+ long opTime = System.currentTimeMillis() - startTimeInMs;
+
+ LOG.info(AaiUiMsgs.ALL_TRANSACTIONS_RESOLVED, String.valueOf(totalResolveTime),
+ String.valueOf(totalLinksRetrieved.get()), String.valueOf(opTime));
+
+ } catch (Exception exc) {
+ LOG.error(AaiUiMsgs.VISUALIZATION_OUTPUT_ERROR, exc.getMessage());
+ }
+
+ }
+
+ /**
+ * Verify outbound neighbors.
+ */
+ private void verifyOutboundNeighbors() {
+
+ for (ActiveInventoryNode srcNode : nodeCache.values()) {
+
+ for (String targetNodeId : srcNode.getOutboundNeighbors()) {
+
+ ActiveInventoryNode targetNode = nodeCache.get(targetNodeId);
+
+ if (targetNode != null && srcNode.getNodeId() != null) {
+
+ targetNode.addInboundNeighbor(srcNode.getNodeId());
+
+ if (this.visualizationConfigs.makeAllNeighborsBidirectional()) {
+ targetNode.addOutboundNeighbor(srcNode.getNodeId());
+ }
+
+ }
+
+ }
+
+ }
+
+ }
+
+ /**
+ * Evaluate node depths.
+ */
+ private void evaluateNodeDepths() {
+
+ int numChanged = -1;
+ int numAttempts = 0;
+
+ while (numChanged != 0) {
+
+ numChanged = 0;
+ numAttempts++;
+
+ for (ActiveInventoryNode srcNode : nodeCache.values()) {
+
+ if (srcNode.getState() == NodeProcessingState.INIT) {
+
+ /*
+ * this maybe the only state that we don't want to to process the node depth on, because
+ * typically it won't have any valid fields set, and it may remain in a partial state
+ * until we have processed the self-link.
+ */
+
+ continue;
+
+ }
+
+ for (String targetNodeId : srcNode.getOutboundNeighbors()) {
+ ActiveInventoryNode targetNode = nodeCache.get(targetNodeId);
+
+ if (targetNode != null) {
+
+ if (targetNode.changeDepth(srcNode.getNodeDepth() + 1)) {
+ numChanged++;
+ }
+ }
+ }
+
+ for (String targetNodeId : srcNode.getInboundNeighbors()) {
+ ActiveInventoryNode targetNode = nodeCache.get(targetNodeId);
+
+ if (targetNode != null) {
+
+ if (targetNode.changeDepth(srcNode.getNodeDepth() + 1)) {
+ numChanged++;
+ }
+ }
+ }
+ }
+
+ if (numAttempts >= MAX_DEPTH_EVALUATION_ATTEMPTS) {
+ LOG.info(AaiUiMsgs.MAX_EVALUATION_ATTEMPTS_EXCEEDED);
+ return;
+ }
+
+ }
+
+ if (LOG.isDebugEnabled()) {
+ if (numAttempts > 0) {
+ LOG.debug(AaiUiMsgs.DEBUG_GENERIC,
+ "Evaluate node depths completed in " + numAttempts + " attempts");
+ } else {
+ LOG.debug(AaiUiMsgs.DEBUG_GENERIC,
+ "Evaluate node depths completed in 0 attempts because all nodes at correct depth");
+ }
+ }
+
+ }
+
+
+ /**
+ * Gets the entity type primary key name.
+ *
+ * @param entityType the entity type
+ * @return the entity type primary key name
+ */
+
+
+ private String getEntityTypePrimaryKeyName(String entityType) {
+
+ if (entityType == null) {
+ LOG.error(AaiUiMsgs.FAILED_TO_DETERMINE,
+ "node primary key" + " name because entity type is null");
+ return null;
+ }
+
+ OxmEntityDescriptor descriptor = oxmEntityLookup.getEntityDescriptors().get(entityType);
+
+ if (descriptor == null) {
+ LOG.error(AaiUiMsgs.FAILED_TO_DETERMINE,
+ "oxm entity" + " descriptor for entityType = " + entityType);
+ return null;
+ }
+
+ List<String> pkeyNames = descriptor.getPrimaryKeyAttributeNames();
+
+ if (pkeyNames == null || pkeyNames.size() == 0) {
+ LOG.error(AaiUiMsgs.FAILED_TO_DETERMINE,
+ "node primary" + " key because descriptor primary key names is empty");
+ return null;
+ }
+
+ return NodeUtils.concatArray(pkeyNames, "/");
+
+ }
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/services/BaseVisualizationContext.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/services/BaseVisualizationContext.java
new file mode 100644
index 0000000..b2bdb43
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/services/BaseVisualizationContext.java
@@ -0,0 +1,1631 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.viewandinspect.services;
+
+import static java.util.concurrent.CompletableFuture.supplyAsync;
+
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.http.client.utils.URIBuilder;
+import org.onap.aai.cl.api.Logger;
+import org.onap.aai.cl.eelf.LoggerFactory;
+import org.onap.aai.restclient.client.OperationResult;
+import org.onap.aai.sparky.config.oxm.OxmEntityDescriptor;
+import org.onap.aai.sparky.config.oxm.OxmEntityLookup;
+import org.onap.aai.sparky.dal.ActiveInventoryAdapter;
+import org.onap.aai.sparky.logging.AaiUiMsgs;
+import org.onap.aai.sparky.sync.entity.SearchableEntity;
+import org.onap.aai.sparky.util.NodeUtils;
+import org.onap.aai.sparky.viewandinspect.config.SparkyConstants;
+import org.onap.aai.sparky.viewandinspect.config.VisualizationConfigs;
+import org.onap.aai.sparky.viewandinspect.entity.ActiveInventoryNode;
+import org.onap.aai.sparky.viewandinspect.entity.InlineMessage;
+import org.onap.aai.sparky.viewandinspect.entity.NodeProcessingTransaction;
+import org.onap.aai.sparky.viewandinspect.entity.QueryParams;
+import org.onap.aai.sparky.viewandinspect.entity.Relationship;
+import org.onap.aai.sparky.viewandinspect.entity.RelationshipData;
+import org.onap.aai.sparky.viewandinspect.entity.RelationshipList;
+import org.onap.aai.sparky.viewandinspect.entity.SelfLinkDeterminationTransaction;
+import org.onap.aai.sparky.viewandinspect.enumeration.NodeProcessingAction;
+import org.onap.aai.sparky.viewandinspect.enumeration.NodeProcessingState;
+import org.onap.aai.sparky.viewandinspect.task.PerformNodeSelfLinkProcessingTask;
+import org.onap.aai.sparky.viewandinspect.task.PerformSelfLinkDeterminationTask;
+
+import com.fasterxml.jackson.annotation.JsonInclude.Include;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.PropertyNamingStrategy;
+
+/**
+ * The Class SelfLinkNodeCollector.
+ */
+public class BaseVisualizationContext implements VisualizationContext {
+
+ private static final int MAX_DEPTH_EVALUATION_ATTEMPTS = 100;
+ private static final String DEPTH_ALL_MODIFIER = "?depth=all";
+ private static final String NODES_ONLY_MODIFIER = "?nodes-only";
+ private static final String SERVICE_INSTANCE = "service-instance";
+
+ private static final Logger LOG = LoggerFactory.getInstance().getLogger(
+ BaseVisualizationContext.class);
+ private final ActiveInventoryAdapter aaiAdapter;
+
+ private int maxSelfLinkTraversalDepth;
+ private AtomicInteger numLinksDiscovered;
+ private AtomicInteger numSuccessfulLinkResolveFromCache;
+ private AtomicInteger numSuccessfulLinkResolveFromFromServer;
+ private AtomicInteger numFailedLinkResolve;
+ private AtomicInteger aaiWorkOnHand;
+
+ private VisualizationConfigs visualizationConfigs;
+
+ private AtomicInteger totalLinksRetrieved;
+
+ private final long contextId;
+ private final String contextIdStr;
+
+ private ObjectMapper mapper;
+ private InlineMessage inlineMessage = null;
+
+ private ExecutorService aaiExecutorService;
+ private OxmEntityLookup oxmEntityLookup;
+ private boolean rootNodeFound;
+
+ /*
+ * The node cache is intended to be a flat structure indexed by a primary key to avoid needlessly
+ * re-requesting the same self-links over-and-over again, to speed up the overall render time and
+ * more importantly to reduce the network cost of determining information we already have.
+ */
+ private ConcurrentHashMap<String, ActiveInventoryNode> nodeCache;
+
+ /**
+ * Instantiates a new self link node collector.
+ *
+ * @param loader the loader
+ * @throws Exception the exception
+ */
+ public BaseVisualizationContext(long contextId, ActiveInventoryAdapter aaiAdapter,
+ ExecutorService aaiExecutorService, VisualizationConfigs visualizationConfigs,
+ OxmEntityLookup oxmEntityLookup)
+ throws Exception {
+
+ this.contextId = contextId;
+ this.contextIdStr = "[Context-Id=" + contextId + "]";
+ this.aaiAdapter = aaiAdapter;
+ this.aaiExecutorService = aaiExecutorService;
+ this.visualizationConfigs = visualizationConfigs;
+ this.oxmEntityLookup = oxmEntityLookup;
+
+ this.nodeCache = new ConcurrentHashMap<String, ActiveInventoryNode>();
+ this.numLinksDiscovered = new AtomicInteger(0);
+ this.totalLinksRetrieved = new AtomicInteger(0);
+ this.numSuccessfulLinkResolveFromCache = new AtomicInteger(0);
+ this.numSuccessfulLinkResolveFromFromServer = new AtomicInteger(0);
+ this.numFailedLinkResolve = new AtomicInteger(0);
+ this.aaiWorkOnHand = new AtomicInteger(0);
+
+ this.maxSelfLinkTraversalDepth = this.visualizationConfigs.getMaxSelfLinkTraversalDepth();
+
+ this.mapper = new ObjectMapper();
+ mapper.setSerializationInclusion(Include.NON_EMPTY);
+ mapper.setPropertyNamingStrategy(new PropertyNamingStrategy.KebabCaseStrategy());
+ this.rootNodeFound = false;
+ }
+
+ protected boolean isRootNodeFound() {
+ return rootNodeFound;
+ }
+
+ protected void setRootNodeFound(boolean rootNodeFound) {
+ this.rootNodeFound = rootNodeFound;
+ }
+
+ public long getContextId() {
+ return contextId;
+ }
+
+ /**
+ * A utility method for extracting all entity-type primary key values from a provided self-link
+ * and return a set of generic-query API keys.
+ *
+ * @param parentEntityType
+ * @param link
+ * @return a list of key values that can be used for this entity with the AAI generic-query API
+ */
+ protected List<String> extractQueryParamsFromSelfLink(String link) {
+
+ List<String> queryParams = new ArrayList<String>();
+
+ if (link == null) {
+ LOG.error(AaiUiMsgs.QUERY_PARAM_EXTRACTION_ERROR, "self link is null");
+ return queryParams;
+ }
+
+ Map<String, OxmEntityDescriptor> entityDescriptors = oxmEntityLookup.getEntityDescriptors();
+
+ try {
+
+ URIBuilder urlBuilder = new URIBuilder(link);
+ String urlPath = urlBuilder.getPath();
+
+ OxmEntityDescriptor descriptor = null;
+ String[] urlPathElements = urlPath.split("/");
+ List<String> primaryKeyNames = null;
+ int index = 0;
+ String entityType = null;
+
+ while (index < urlPathElements.length) {
+
+ descriptor = entityDescriptors.get(urlPathElements[index]);
+
+ if (descriptor != null) {
+ entityType = urlPathElements[index];
+ primaryKeyNames = descriptor.getPrimaryKeyAttributeNames();
+
+ /*
+ * Make sure from what ever index we matched the parent entity-type on that we can extract
+ * additional path elements for the primary key values.
+ */
+
+ if (index + primaryKeyNames.size() < urlPathElements.length) {
+
+ for (String primaryKeyName : primaryKeyNames) {
+ index++;
+ queryParams.add(entityType + "." + primaryKeyName + ":" + urlPathElements[index]);
+ }
+ } else {
+ LOG.error(AaiUiMsgs.QUERY_PARAM_EXTRACTION_ERROR,
+ "Could not extract query parametrs for entity-type = '" + entityType
+ + "' from self-link = " + link);
+ }
+ }
+
+ index++;
+ }
+
+ } catch (URISyntaxException exc) {
+
+ LOG.error(AaiUiMsgs.QUERY_PARAM_EXTRACTION_ERROR,
+ "Error extracting query parameters from self-link = " + link + ". Error = "
+ + exc.getMessage());
+ }
+
+ return queryParams;
+
+ }
+
+ /**
+ * Decode complex attribute group.
+ *
+ * @param ain the ain
+ * @param attributeGroup the attribute group
+ * @return boolean indicating whether operation was successful (true), / failure(false).
+ */
+ public boolean decodeComplexAttributeGroup(ActiveInventoryNode ain, JsonNode attributeGroup) {
+
+ try {
+
+ Iterator<Entry<String, JsonNode>> entityArrays = attributeGroup.fields();
+ Entry<String, JsonNode> entityArray = null;
+
+ if (entityArrays == null) {
+ LOG.error(AaiUiMsgs.ATTRIBUTE_GROUP_FAILURE, attributeGroup.toString());
+ ain.changeState(NodeProcessingState.ERROR, NodeProcessingAction.NEIGHBORS_PROCESSED_ERROR);
+ return false;
+ }
+
+ while (entityArrays.hasNext()) {
+
+ entityArray = entityArrays.next();
+
+ String entityType = entityArray.getKey();
+ JsonNode entityArrayObject = entityArray.getValue();
+
+ if (entityArrayObject.isArray()) {
+
+ Iterator<JsonNode> entityCollection = entityArrayObject.elements();
+ JsonNode entity = null;
+ while (entityCollection.hasNext()) {
+ entity = entityCollection.next();
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug(AaiUiMsgs.DEBUG_GENERIC, "decodeComplexAttributeGroup(),"
+ + " entity = " + entity.toString());
+ }
+
+ /**
+ * Here's what we are going to do:
+ *
+ * <li>In the ActiveInventoryNode, on construction maintain a collection of queryParams
+ * that is added to for the purpose of discovering parent->child hierarchies.
+ *
+ * <li>When we hit this block of the code then we'll use the queryParams to feed the
+ * generic query to resolve the self-link asynchronously.
+ *
+ * <li>Upon successful link determination, then and only then will we create a new node
+ * in the nodeCache and process the child
+ *
+ */
+
+ ActiveInventoryNode newNode = new ActiveInventoryNode(this.visualizationConfigs, oxmEntityLookup);
+ newNode.setEntityType(entityType);
+
+ /*
+ * This is partially a lie because we actually don't have a self-link for complex nodes
+ * discovered in this way.
+ */
+ newNode.setSelfLinkProcessed(true);
+ newNode.changeState(NodeProcessingState.SELF_LINK_RESPONSE_UNPROCESSED,
+ NodeProcessingAction.COMPLEX_ATTRIBUTE_GROUP_PARSE_OK);
+
+ /*
+ * copy parent query params into new child
+ */
+
+ if (SERVICE_INSTANCE.equals(entityType)) {
+
+ /*
+ * 1707 AAI has an issue being tracked with AAI-8932 where the generic-query cannot be
+ * resolved if all the service-instance path keys are provided. The query only works
+ * if only the service-instance key and valude are passed due to a historical reason.
+ * A fix is being worked on for 1707, and when it becomes available we can revert this
+ * small change.
+ */
+
+ newNode.clearQueryParams();
+
+ } else {
+
+ /*
+ * For all other entity-types we want to copy the parent query parameters into the new node
+ * query parameters.
+ */
+
+ for (String queryParam : ain.getQueryParams()) {
+ newNode.addQueryParam(queryParam);
+ }
+
+ }
+
+
+ if (!addComplexGroupToNode(newNode, entity)) {
+ LOG.error(AaiUiMsgs.ATTRIBUTE_GROUP_FAILURE, "Failed to add child to parent for child = " + entity.toString());
+ }
+
+ if (!addNodeQueryParams(newNode)) {
+ LOG.error(AaiUiMsgs.FAILED_TO_DETERMINE_NODE_ID, "Error determining node id and key for node = " + newNode.dumpNodeTree(true)
+ + " skipping relationship processing");
+ newNode.changeState(NodeProcessingState.ERROR,
+ NodeProcessingAction.NODE_IDENTITY_ERROR);
+ return false;
+ } else {
+
+ newNode.changeState(NodeProcessingState.NEIGHBORS_UNPROCESSED,
+ NodeProcessingAction.COMPLEX_ATTRIBUTE_GROUP_PARSE_OK);
+
+ }
+
+
+ /*
+ * Order matters for the query params. We need to set the parent ones before the child
+ * node
+ */
+
+ String selfLinkQuery =
+ aaiAdapter.getGenericQueryForSelfLink(entityType, newNode.getQueryParams());
+
+ /**
+ * <li>get the self-link
+ * <li>add it to the new node
+ * <li>generate node id
+ * <li>add node to node cache
+ * <li>add node id to parent outbound links list
+ * <li>process node children (should be automatic) (but don't query and resolve
+ * self-link as we already have all the data)
+ */
+
+ SelfLinkDeterminationTransaction txn = new SelfLinkDeterminationTransaction();
+
+ txn.setQueryString(selfLinkQuery);
+ txn.setNewNode(newNode);
+ txn.setParentNodeId(ain.getNodeId());
+ aaiWorkOnHand.incrementAndGet();
+ supplyAsync(new PerformSelfLinkDeterminationTask(txn, null, aaiAdapter),
+ aaiExecutorService).whenComplete((nodeTxn, error) -> {
+
+ if (error != null) {
+ LOG.error(AaiUiMsgs.SELF_LINK_DETERMINATION_FAILED_GENERIC, selfLinkQuery);
+ } else {
+
+ OperationResult opResult = nodeTxn.getOpResult();
+
+ ActiveInventoryNode newChildNode = txn.getNewNode();
+
+ if (opResult != null && opResult.wasSuccessful()) {
+
+ if (!opResult.wasSuccessful()) {
+ numFailedLinkResolve.incrementAndGet();
+ }
+
+ if (opResult.isFromCache()) {
+ numSuccessfulLinkResolveFromCache.incrementAndGet();
+ } else {
+ numSuccessfulLinkResolveFromFromServer.incrementAndGet();
+ }
+
+ /*
+ * extract the self-link from the operational result.
+ */
+
+ Collection<JsonNode> entityLinks = new ArrayList<JsonNode>();
+ JsonNode genericQueryResult = null;
+ try {
+ genericQueryResult =
+ NodeUtils.convertJsonStrToJsonNode(nodeTxn.getOpResult().getResult());
+ } catch (Exception exc) {
+ LOG.error(AaiUiMsgs.JSON_CONVERSION_ERROR, JsonNode.class.toString(), exc.getMessage());
+ }
+
+ NodeUtils.extractObjectsByKey(genericQueryResult, "resource-link",
+ entityLinks);
+
+ String selfLink = null;
+
+ if (entityLinks.size() != 1) {
+
+ LOG.error(AaiUiMsgs.SELF_LINK_DETERMINATION_FAILED_UNEXPECTED_LINKS, String.valueOf(entityLinks.size()));
+
+ } else {
+ selfLink = ((JsonNode) entityLinks.toArray()[0]).asText();
+ selfLink = ActiveInventoryAdapter.extractResourcePath(selfLink);
+
+ newChildNode.setSelfLink(selfLink);
+ newChildNode.setNodeId(NodeUtils.generateUniqueShaDigest(selfLink));
+
+ String uri = NodeUtils.calculateEditAttributeUri(selfLink);
+ if (uri != null) {
+ newChildNode.addProperty(SparkyConstants.URI_ATTR_NAME, uri);
+ }
+
+ ActiveInventoryNode parent = nodeCache.get(txn.getParentNodeId());
+
+ if (parent != null) {
+ parent.addOutboundNeighbor(newChildNode.getNodeId());
+ newChildNode.addInboundNeighbor(parent.getNodeId());
+ }
+
+ newChildNode.setSelfLinkPendingResolve(false);
+ newChildNode.setSelfLinkProcessed(true);
+ newChildNode.changeState(NodeProcessingState.NEIGHBORS_UNPROCESSED,
+ NodeProcessingAction.SELF_LINK_RESPONSE_PARSE_OK);
+
+ nodeCache.putIfAbsent(newChildNode.getNodeId(), newChildNode);
+
+ }
+
+ } else {
+ LOG.error(AaiUiMsgs.SELF_LINK_RETRIEVAL_FAILED, txn.getQueryString(),
+ String.valueOf(nodeTxn.getOpResult().getResultCode()), nodeTxn.getOpResult().getResult());
+ newChildNode.setSelflinkRetrievalFailure(true);
+ newChildNode.setSelfLinkProcessed(true);
+ newChildNode.setSelfLinkPendingResolve(false);
+
+ newChildNode.changeState(NodeProcessingState.ERROR,
+ NodeProcessingAction.SELF_LINK_DETERMINATION_ERROR);
+
+ }
+
+ }
+
+ aaiWorkOnHand.decrementAndGet();
+
+ });
+
+ }
+
+ return true;
+
+ } else {
+ LOG.error(AaiUiMsgs.UNHANDLED_OBJ_TYPE_FOR_ENTITY_TYPE, entityType);
+ }
+
+ }
+ } catch (Exception exc) {
+ LOG.error(AaiUiMsgs.SELF_LINK_PROCESSING_ERROR, "Exception caught while"
+ + " decoding complex attribute group - " + exc.getMessage());
+ }
+
+ return false;
+
+ }
+
+ /**
+ * Process self link response.
+ *
+ * @param nodeId the node id
+ */
+ private void processSelfLinkResponse(String nodeId) {
+
+ if (nodeId == null) {
+ LOG.error(AaiUiMsgs.SELF_LINK_PROCESSING_ERROR, "Cannot process self link"
+ + " response because nodeId is null");
+ return;
+ }
+
+ ActiveInventoryNode ain = nodeCache.get(nodeId);
+
+ if (ain == null) {
+ LOG.error(AaiUiMsgs.SELF_LINK_PROCESSING_ERROR, "Cannot process self link response"
+ + " because can't find node for id = " + nodeId);
+ return;
+ }
+
+ JsonNode jsonNode = null;
+
+ try {
+ jsonNode = mapper.readValue(ain.getOpResult().getResult(), JsonNode.class);
+ } catch (Exception exc) {
+ LOG.error(AaiUiMsgs.SELF_LINK_JSON_PARSE_ERROR, "Failed to marshal json"
+ + " response str into JsonNode with error, " + exc.getLocalizedMessage());
+ ain.changeState(NodeProcessingState.ERROR,
+ NodeProcessingAction.SELF_LINK_RESPONSE_PARSE_ERROR);
+ return;
+ }
+
+ if (jsonNode == null) {
+ LOG.error(AaiUiMsgs.SELF_LINK_JSON_PARSE_ERROR, "Failed to parse json node str."
+ + " Parse resulted a null value.");
+ ain.changeState(NodeProcessingState.ERROR,
+ NodeProcessingAction.SELF_LINK_RESPONSE_PARSE_ERROR);
+ return;
+ }
+
+ Iterator<Entry<String, JsonNode>> fieldNames = jsonNode.fields();
+ Entry<String, JsonNode> field = null;
+
+ RelationshipList relationshipList = null;
+
+ while (fieldNames.hasNext()) {
+
+ field = fieldNames.next();
+ String fieldName = field.getKey();
+
+ if ("relationship-list".equals(fieldName)) {
+
+ try {
+ relationshipList = mapper.readValue(field.getValue().toString(), RelationshipList.class);
+
+ if (relationshipList != null) {
+ ain.addRelationshipList(relationshipList);
+ }
+
+ } catch (Exception exc) {
+ LOG.error(AaiUiMsgs.SELF_LINK_JSON_PARSE_ERROR, "Failed to parse relationship-list"
+ + " attribute. Parse resulted in error, " + exc.getLocalizedMessage());
+ ain.changeState(NodeProcessingState.ERROR,
+ NodeProcessingAction.SELF_LINK_RESPONSE_PARSE_ERROR);
+ return;
+ }
+
+ } else {
+
+ JsonNode nodeValue = field.getValue();
+
+ if (nodeValue != null && nodeValue.isValueNode()) {
+
+ if (oxmEntityLookup.getEntityDescriptors().get(fieldName) == null) {
+
+ /*
+ * entity property name is not an entity, thus we can add this property name and value
+ * to our property set
+ */
+
+ ain.addProperty(fieldName, nodeValue.asText());
+
+ }
+
+ } else {
+
+ if (nodeValue.isArray()) {
+
+ if (oxmEntityLookup.getEntityDescriptors().get(fieldName) == null) {
+
+ /*
+ * entity property name is not an entity, thus we can add this property name and value
+ * to our property set
+ */
+
+ ain.addProperty(field.getKey(), nodeValue.toString());
+
+ }
+
+ } else {
+
+ ain.addComplexGroup(nodeValue);
+
+ }
+
+ }
+ }
+
+ }
+
+ String uri = NodeUtils.calculateEditAttributeUri(ain.getSelfLink());
+ if (uri != null) {
+ ain.addProperty(SparkyConstants.URI_ATTR_NAME, uri);
+ }
+
+ /*
+ * We need a special behavior for intermediate entities from the REST model
+ *
+ * Tenants are not top level entities, and when we want to visualization
+ * their children, we need to construct keys that include the parent entity query
+ * keys, the current entity type keys, and the child keys. We'll always have the
+ * current entity and children, but never the parent entity in the current (1707) REST
+ * data model.
+ *
+ * We have two possible solutions:
+ *
+ * 1) Try to use the custom-query approach to learn about the entity keys
+ * - this could be done, but it could be very expensive for large objects. When we do the first
+ * query to get a tenant, it will list all the in and out edges related to this entity,
+ * there is presently no way to filter this. But the approach could be made to work and it would be
+ * somewhat data-model driven, other than the fact that we have to first realize that the entity
+ * that is being searched for is not top-level entity. Once we have globally unique ids for resources
+ * this logic will not be needed and everything will be simpler. The only reason we are in this logic
+ * at all is to be able to calculate a url for the child entities so we can hash it to generate
+ * a globally unique id that can be safely used for the node.
+ *
+ * *2* Extract the keys from the pathed self-link.
+ * This is a bad solution and I don't like it but it will be fast for all resource types, as the
+ * information is already encoded in the URI. When we get to a point where we switch to a better
+ * globally unique entity identity model, then a lot of the code being used to calculate an entity url
+ * to in-turn generate a deterministic globally unique id will disappear.
+ *
+ *
+ * right now we have the following:
+ *
+ * - cloud-regions/cloud-region/{cloud-region-id}/{cloud-owner-id}/tenants/tenant/{tenant-id}
+ *
+ */
+
+ /*
+ * For all entity types use the self-link extraction method to be consistent. Once we have a
+ * globally unique identity mechanism for entities, this logic can be revisited.
+ */
+ ain.clearQueryParams();
+ ain.addQueryParams(extractQueryParamsFromSelfLink(ain.getSelfLink()));
+ ain.changeState(NodeProcessingState.NEIGHBORS_UNPROCESSED,
+ NodeProcessingAction.SELF_LINK_RESPONSE_PARSE_OK);
+
+
+ }
+
+ /**
+ * Perform self link resolve.
+ *
+ * @param nodeId the node id
+ */
+ private void performSelfLinkResolve(String nodeId) {
+
+ if (nodeId == null) {
+ LOG.error(AaiUiMsgs.SELF_LINK_PROCESSING_ERROR, "Resolve of self-link"
+ + " has been skipped because provided nodeId is null");
+ return;
+ }
+
+ ActiveInventoryNode ain = nodeCache.get(nodeId);
+
+ if (ain == null) {
+ LOG.error(AaiUiMsgs.SELF_LINK_PROCESSING_ERROR, "Failed to find node with id, " + nodeId
+ + ", from node cache. Resolve self-link method has been skipped.");
+ return;
+ }
+
+ if (!ain.isSelfLinkPendingResolve()) {
+
+ ain.setSelfLinkPendingResolve(true);
+
+ // kick off async self-link resolution
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug(AaiUiMsgs.DEBUG_GENERIC,
+ "About to process node in SELF_LINK_UNPROCESSED State, link = " + ain.getSelfLink());
+ }
+
+ numLinksDiscovered.incrementAndGet();
+
+ String depthModifier = DEPTH_ALL_MODIFIER;
+
+ /*
+ * If the current node is the search target, we want to see everything the node has to offer
+ * from the self-link and not filter it to a single node.
+ */
+
+ if (visualizationConfigs.getShallowEntities().contains(ain.getEntityType())
+ && !ain.isRootNode()) {
+ depthModifier = NODES_ONLY_MODIFIER;
+ }
+
+ NodeProcessingTransaction txn = new NodeProcessingTransaction();
+ txn.setProcessingNode(ain);
+ txn.setRequestParameters(depthModifier);
+ aaiWorkOnHand.incrementAndGet();
+ supplyAsync(
+ new PerformNodeSelfLinkProcessingTask(txn, depthModifier, aaiAdapter),
+ aaiExecutorService).whenComplete((nodeTxn, error) -> {
+
+ if (error != null) {
+
+ /*
+ * an error processing the self link should probably result in the node processing
+ * state shifting to ERROR
+ */
+
+ nodeTxn.getProcessingNode().setSelflinkRetrievalFailure(true);
+
+ nodeTxn.getProcessingNode().changeState(NodeProcessingState.ERROR,
+ NodeProcessingAction.SELF_LINK_RESOLVE_ERROR);
+
+ nodeTxn.getProcessingNode().setSelfLinkPendingResolve(false);
+
+ } else {
+
+ totalLinksRetrieved.incrementAndGet();
+
+ OperationResult opResult = nodeTxn.getOpResult();
+
+ if (opResult != null && opResult.wasSuccessful()) {
+
+ if (!opResult.wasSuccessful()) {
+ numFailedLinkResolve.incrementAndGet();
+ }
+
+ if (opResult.isFromCache()) {
+ numSuccessfulLinkResolveFromCache.incrementAndGet();
+ } else {
+ numSuccessfulLinkResolveFromFromServer.incrementAndGet();
+ }
+
+ // success path
+ nodeTxn.getProcessingNode().setOpResult(opResult);
+ nodeTxn.getProcessingNode().changeState(
+ NodeProcessingState.SELF_LINK_RESPONSE_UNPROCESSED,
+ NodeProcessingAction.SELF_LINK_RESOLVE_OK);
+
+ nodeTxn.getProcessingNode().setSelfLinkProcessed(true);
+ nodeTxn.getProcessingNode().setSelfLinkPendingResolve(false);
+
+ } else {
+ LOG.error(AaiUiMsgs.SELF_LINK_PROCESSING_ERROR, "Self Link retrieval for link,"
+ + txn.getSelfLinkWithModifiers() + ", failed with error code,"
+ + nodeTxn.getOpResult().getResultCode() + ", and message,"
+ + nodeTxn.getOpResult().getResult());
+
+ nodeTxn.getProcessingNode().setSelflinkRetrievalFailure(true);
+ nodeTxn.getProcessingNode().setSelfLinkProcessed(true);
+
+ nodeTxn.getProcessingNode().changeState(NodeProcessingState.ERROR,
+ NodeProcessingAction.SELF_LINK_RESOLVE_ERROR);
+
+ nodeTxn.getProcessingNode().setSelfLinkPendingResolve(false);
+
+ }
+ }
+
+ aaiWorkOnHand.decrementAndGet();
+
+ });
+
+ }
+
+ }
+
+
+ /**
+ * Process neighbors.
+ *
+ * @param nodeId the node id
+ */
+ private void processNeighbors(String nodeId) {
+
+ if (nodeId == null) {
+ LOG.error(AaiUiMsgs.SELF_LINK_PROCESS_NEIGHBORS_ERROR, "Failed to process"
+ + " neighbors because nodeId is null.");
+ return;
+ }
+
+ ActiveInventoryNode ain = nodeCache.get(nodeId);
+
+ if (ain == null) {
+ LOG.error(AaiUiMsgs.SELF_LINK_PROCESS_NEIGHBORS_ERROR, "Failed to process"
+ + " neighbors because node could not be found in nodeCache with id, " + nodeId);
+ return;
+ }
+
+ /*
+ * process complex attribute and relationships
+ */
+
+ boolean neighborsProcessedSuccessfully = true;
+
+ for (JsonNode n : ain.getComplexGroups()) {
+ neighborsProcessedSuccessfully &= decodeComplexAttributeGroup(ain, n);
+ }
+
+ for (RelationshipList relationshipList : ain.getRelationshipLists()) {
+ neighborsProcessedSuccessfully &= addSelfLinkRelationshipChildren(ain, relationshipList);
+ }
+
+
+ if (neighborsProcessedSuccessfully) {
+ ain.changeState(NodeProcessingState.READY, NodeProcessingAction.NEIGHBORS_PROCESSED_OK);
+ } else {
+ ain.changeState(NodeProcessingState.ERROR, NodeProcessingAction.NEIGHBORS_PROCESSED_ERROR);
+ }
+
+
+ /*
+ * If neighbors fail to process, there is already a call to change the state within the
+ * relationship and neighbor processing functions.
+ */
+
+ }
+
+ /**
+ * Find and mark root node.
+ *
+ * @param queryParams the query params
+ * @return true, if successful
+ */
+ private void findAndMarkRootNode(QueryParams queryParams) {
+
+ if (isRootNodeFound()) {
+ return;
+ }
+
+ for (ActiveInventoryNode cacheNode : nodeCache.values()) {
+
+ if (queryParams.getSearchTargetNodeId().equals(cacheNode.getNodeId())) {
+ cacheNode.setNodeDepth(0);
+ cacheNode.setRootNode(true);
+ LOG.info(AaiUiMsgs.ROOT_NODE_DISCOVERED, queryParams.getSearchTargetNodeId());
+ setRootNodeFound(true);
+ }
+ }
+
+ }
+
+ /**
+ * Process current node states.
+ *
+ * @param rootNodeDiscovered the root node discovered
+ */
+ private void processCurrentNodeStates(QueryParams queryParams) {
+ /*
+ * Force an evaluation of node depths before determining if we should limit state-based
+ * traversal or processing.
+ */
+
+ findAndMarkRootNode(queryParams);
+
+ verifyOutboundNeighbors();
+
+ for (ActiveInventoryNode cacheNode : nodeCache.values()) {
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug(AaiUiMsgs.DEBUG_GENERIC,
+ "processCurrentNodeState(), nid = "
+ + cacheNode.getNodeId() + " , nodeDepth = " + cacheNode.getNodeDepth());
+ }
+
+ switch (cacheNode.getState()) {
+
+ case INIT: {
+ processInitialState(cacheNode.getNodeId());
+ break;
+ }
+
+ case READY:
+ case ERROR: {
+ break;
+ }
+
+ case SELF_LINK_UNRESOLVED: {
+ performSelfLinkResolve(cacheNode.getNodeId());
+ break;
+ }
+
+ case SELF_LINK_RESPONSE_UNPROCESSED: {
+ processSelfLinkResponse(cacheNode.getNodeId());
+ break;
+ }
+
+ case NEIGHBORS_UNPROCESSED: {
+
+ /*
+ * We use the rootNodeDiscovered flag to ignore depth retrieval thresholds until the root
+ * node is identified. Then the evaluative depth calculations should re-balance the graph
+ * around the root node.
+ */
+
+ if (!isRootNodeFound() || cacheNode.getNodeDepth() < this.visualizationConfigs
+ .getMaxSelfLinkTraversalDepth()) {
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug(AaiUiMsgs.DEBUG_GENERIC,
+ "processCurrentNodeState() -- Node at max depth,"
+ + " halting processing at current state = -- "
+ + cacheNode.getState() + " nodeId = " + cacheNode.getNodeId());
+ }
+
+ processNeighbors(cacheNode.getNodeId());
+
+ }
+
+ break;
+ }
+ default:
+ break;
+ }
+
+ }
+
+ }
+
+ /**
+ * Adds the complex group to node.
+ *
+ * @param targetNode the target node
+ * @param attributeGroup the attribute group
+ * @return true, if successful
+ */
+ private boolean addComplexGroupToNode(ActiveInventoryNode targetNode, JsonNode attributeGroup) {
+
+ if (attributeGroup == null) {
+ targetNode.changeState(NodeProcessingState.ERROR,
+ NodeProcessingAction.COMPLEX_ATTRIBUTE_GROUP_PARSE_OK);
+ return false;
+ }
+
+ RelationshipList relationshipList = null;
+
+ if (attributeGroup.isObject()) {
+
+ Iterator<Entry<String, JsonNode>> fields = attributeGroup.fields();
+ Entry<String, JsonNode> field = null;
+ String fieldName;
+ JsonNode fieldValue;
+
+ while (fields.hasNext()) {
+ field = fields.next();
+ fieldName = field.getKey();
+ fieldValue = field.getValue();
+
+ if (fieldValue.isObject()) {
+
+ if (fieldName.equals("relationship-list")) {
+
+ try {
+ relationshipList =
+ mapper.readValue(field.getValue().toString(), RelationshipList.class);
+
+ if (relationshipList != null) {
+ targetNode.addRelationshipList(relationshipList);
+ }
+
+ } catch (Exception exc) {
+ LOG.error(AaiUiMsgs.SELF_LINK_JSON_PARSE_ERROR, "Failed to parse"
+ + " relationship-list attribute. Parse resulted in error, "
+ + exc.getLocalizedMessage());
+ targetNode.changeState(NodeProcessingState.ERROR,
+ NodeProcessingAction.COMPLEX_ATTRIBUTE_GROUP_PARSE_ERROR);
+ return false;
+ }
+
+ } else {
+ targetNode.addComplexGroup(fieldValue);
+ }
+
+ } else if (fieldValue.isArray()) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug(AaiUiMsgs.DEBUG_GENERIC,
+ "Unexpected array type with a key = " + fieldName);
+ }
+ } else if (fieldValue.isValueNode()) {
+ if (oxmEntityLookup.getEntityDescriptors().get(field.getKey()) == null) {
+ /*
+ * property key is not an entity type, add it to our property set.
+ */
+ targetNode.addProperty(field.getKey(), fieldValue.asText());
+ }
+
+ }
+ }
+
+ } else if (attributeGroup.isArray()) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug(AaiUiMsgs.DEBUG_GENERIC,
+ "Unexpected array type for attributeGroup = " + attributeGroup);
+ }
+ } else if (attributeGroup.isValueNode()) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug(AaiUiMsgs.DEBUG_GENERIC,
+ "Unexpected value type for attributeGroup = " + attributeGroup);
+ }
+ }
+
+ return true;
+ }
+
+ public int getNumSuccessfulLinkResolveFromCache() {
+ return numSuccessfulLinkResolveFromCache.get();
+ }
+
+ public int getNumSuccessfulLinkResolveFromFromServer() {
+ return numSuccessfulLinkResolveFromFromServer.get();
+ }
+
+ public int getNumFailedLinkResolve() {
+ return numFailedLinkResolve.get();
+ }
+
+ public InlineMessage getInlineMessage() {
+ return inlineMessage;
+ }
+
+ public void setInlineMessage(InlineMessage inlineMessage) {
+ this.inlineMessage = inlineMessage;
+ }
+
+ public void setMaxSelfLinkTraversalDepth(int depth) {
+ this.maxSelfLinkTraversalDepth = depth;
+ }
+
+ public int getMaxSelfLinkTraversalDepth() {
+ return this.maxSelfLinkTraversalDepth;
+ }
+
+ public ConcurrentHashMap<String, ActiveInventoryNode> getNodeCache() {
+ return nodeCache;
+ }
+
+ /**
+ * Gets the relationship primary key values.
+ *
+ * @param r the r
+ * @param entityType the entity type
+ * @param pkeyNames the pkey names
+ * @return the relationship primary key values
+ */
+ private String getRelationshipPrimaryKeyValues(Relationship r, String entityType,
+ List<String> pkeyNames) {
+
+ StringBuilder sb = new StringBuilder(64);
+
+ if (pkeyNames.size() > 0) {
+ String primaryKey = extractKeyValueFromRelationData(r, entityType + "." + pkeyNames.get(0));
+ if (primaryKey != null) {
+
+ sb.append(primaryKey);
+
+ } else {
+ // this should be a fatal error because unless we can
+ // successfully retrieve all the expected keys we'll end up
+ // with a garbage node
+ LOG.error(AaiUiMsgs.EXTRACTION_ERROR, "ERROR: Failed to extract"
+ + " keyName, " + entityType + "." + pkeyNames.get(0)
+ + ", from relationship data, " + r.toString());
+ return null;
+ }
+
+ for (int i = 1; i < pkeyNames.size(); i++) {
+
+ String kv = extractKeyValueFromRelationData(r, entityType + "." + pkeyNames.get(i));
+ if (kv != null) {
+ sb.append("/").append(kv);
+ } else {
+ // this should be a fatal error because unless we can
+ // successfully retrieve all the expected keys we'll end up
+ // with a garbage node
+ LOG.error(AaiUiMsgs.EXTRACTION_ERROR, "ERROR: failed to extract keyName, "
+ + entityType + "." + pkeyNames.get(i)
+ + ", from relationship data, " + r.toString());
+ return null;
+ }
+ }
+
+ return sb.toString();
+
+ }
+
+ return null;
+
+ }
+
+ /**
+ * Extract key value from relation data.
+ *
+ * @param r the r
+ * @param keyName the key name
+ * @return the string
+ */
+ private String extractKeyValueFromRelationData(Relationship r, String keyName) {
+
+ RelationshipData[] rdList = r.getRelationshipData();
+
+ for (RelationshipData relData : rdList) {
+
+ if (relData.getRelationshipKey().equals(keyName)) {
+ return relData.getRelationshipValue();
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Determine node id and key.
+ *
+ * @param ain the ain
+ * @return true, if successful
+ */
+ private boolean addNodeQueryParams(ActiveInventoryNode ain) {
+
+ if (ain == null) {
+ LOG.error(AaiUiMsgs.FAILED_TO_DETERMINE_NODE_ID, "ActiveInventoryNode is null");
+ return false;
+ }
+
+ List<String> pkeyNames =
+ oxmEntityLookup.getEntityDescriptors().get(ain.getEntityType()).getPrimaryKeyAttributeNames();
+
+ if (pkeyNames == null || pkeyNames.size() == 0) {
+ LOG.error(AaiUiMsgs.FAILED_TO_DETERMINE_NODE_ID, "Primary key names is empty");
+ return false;
+ }
+
+ StringBuilder sb = new StringBuilder(64);
+
+ if (pkeyNames.size() > 0) {
+ String primaryKey = ain.getProperties().get(pkeyNames.get(0));
+ if (primaryKey != null) {
+ sb.append(primaryKey);
+ } else {
+ // this should be a fatal error because unless we can
+ // successfully retrieve all the expected keys we'll end up
+ // with a garbage node
+ LOG.error(AaiUiMsgs.EXTRACTION_ERROR, "ERROR: Failed to extract keyName, "
+ + pkeyNames.get(0) + ", from entity properties");
+ return false;
+ }
+
+ for (int i = 1; i < pkeyNames.size(); i++) {
+
+ String kv = ain.getProperties().get(pkeyNames.get(i));
+ if (kv != null) {
+ sb.append("/").append(kv);
+ } else {
+ // this should be a fatal error because unless we can
+ // successfully retrieve all the expected keys we'll end up
+ // with a garbage node
+ LOG.error(AaiUiMsgs.EXTRACTION_ERROR, "ERROR: Failed to extract keyName, "
+ + pkeyNames.get(i) + ", from entity properties");
+ return false;
+ }
+ }
+
+ /*final String nodeId = NodeUtils.generateUniqueShaDigest(ain.getEntityType(),
+ NodeUtils.concatArray(pkeyNames, "/"), sb.toString());*/
+
+ //ain.setNodeId(nodeId);
+ ain.setPrimaryKeyName(NodeUtils.concatArray(pkeyNames, "/"));
+ ain.setPrimaryKeyValue(sb.toString());
+
+ if (ain.getEntityType() != null && ain.getPrimaryKeyName() != null
+ && ain.getPrimaryKeyValue() != null) {
+ ain.addQueryParam(
+ ain.getEntityType() + "." + ain.getPrimaryKeyName() + ":" + ain.getPrimaryKeyValue());
+ }
+ return true;
+
+ }
+
+ return false;
+
+ }
+
+ /**
+ * Adds the self link relationship children.
+ *
+ * @param processingNode the processing node
+ * @param relationshipList the relationship list
+ * @return true, if successful
+ */
+ private boolean addSelfLinkRelationshipChildren(ActiveInventoryNode processingNode,
+ RelationshipList relationshipList) {
+
+ if (relationshipList == null) {
+ LOG.debug(AaiUiMsgs.DEBUG_GENERIC, "No relationships added to parent node = "
+ + processingNode.getNodeId() + " because relationshipList is empty");
+ processingNode.changeState(NodeProcessingState.ERROR,
+ NodeProcessingAction.NEIGHBORS_PROCESSED_ERROR);
+ return false;
+ }
+
+ Relationship[] relationshipArray = relationshipList.getRelationshipList();
+ OxmEntityDescriptor descriptor = null;
+ String repairedSelfLink = null;
+
+ if (relationshipArray != null) {
+
+ ActiveInventoryNode newNode = null;
+ String resourcePath = null;
+
+ for (Relationship r : relationshipArray) {
+
+ resourcePath = ActiveInventoryAdapter.extractResourcePath(r.getRelatedLink());
+
+ String nodeId = NodeUtils.generateUniqueShaDigest(resourcePath);
+
+ if (nodeId == null) {
+
+ LOG.error(AaiUiMsgs.SKIPPING_RELATIONSHIP, r.toString());
+ processingNode.changeState(NodeProcessingState.ERROR,
+ NodeProcessingAction.NODE_IDENTITY_ERROR);
+ return false;
+ }
+
+ newNode = new ActiveInventoryNode(this.visualizationConfigs, oxmEntityLookup);
+
+ String entityType = r.getRelatedTo();
+
+ if (r.getRelationshipData() != null) {
+ for (RelationshipData rd : r.getRelationshipData()) {
+ newNode.addQueryParam(rd.getRelationshipKey() + ":" + rd.getRelationshipValue());
+ }
+ }
+
+ descriptor = oxmEntityLookup.getEntityDescriptors().get(r.getRelatedTo());
+
+ newNode.setNodeId(nodeId);
+ newNode.setEntityType(entityType);
+ newNode.setSelfLink(resourcePath);
+
+ processingNode.addOutboundNeighbor(nodeId);
+
+ if (descriptor != null) {
+
+ List<String> pkeyNames = descriptor.getPrimaryKeyAttributeNames();
+
+ newNode.changeState(NodeProcessingState.SELF_LINK_UNRESOLVED,
+ NodeProcessingAction.SELF_LINK_SET);
+
+ newNode.setPrimaryKeyName(NodeUtils.concatArray(pkeyNames, "/"));
+
+ String primaryKeyValues = getRelationshipPrimaryKeyValues(r, entityType, pkeyNames);
+ newNode.setPrimaryKeyValue(primaryKeyValues);
+
+ } else {
+
+ LOG.error(AaiUiMsgs.VISUALIZATION_OUTPUT_ERROR,
+ "Failed to parse entity because OXM descriptor could not be found for type = "
+ + r.getRelatedTo());
+
+ newNode.changeState(NodeProcessingState.ERROR,
+ NodeProcessingAction.NEIGHBORS_PROCESSED_ERROR);
+
+ }
+
+ if (nodeCache.putIfAbsent(nodeId, newNode) != null) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug(AaiUiMsgs.DEBUG_GENERIC,
+ "Failed to add node to nodeCache because it already exists. Node id = "
+ + newNode.getNodeId());
+ }
+ }
+
+ }
+
+ }
+
+ return true;
+
+ }
+
+ /**
+ * Process initial state.
+ *
+ * @param nodeId the node id
+ */
+ private void processInitialState(String nodeId) {
+
+ if (nodeId == null) {
+ LOG.error(AaiUiMsgs.FAILED_TO_PROCESS_INITIAL_STATE, "Node id is null");
+ return;
+ }
+
+ ActiveInventoryNode cachedNode = nodeCache.get(nodeId);
+
+ if (cachedNode == null) {
+ LOG.error(AaiUiMsgs.FAILED_TO_PROCESS_INITIAL_STATE, "Node cannot be"
+ + " found for nodeId, " + nodeId);
+ return;
+ }
+
+ if (cachedNode.getSelfLink() == null) {
+
+ if (cachedNode.getNodeId() == null ) {
+
+ /*
+ * if the self link is null at the INIT state, which could be valid if this node is a
+ * complex attribute group which didn't originate from a self-link, but in that situation
+ * both the node id and node key should already be set.
+ */
+
+ cachedNode.changeState(NodeProcessingState.ERROR, NodeProcessingAction.NODE_IDENTITY_ERROR);
+
+ }
+
+ if (cachedNode.getNodeId() != null) {
+
+ /*
+ * This should be the success path branch if the self-link is not set
+ */
+
+ cachedNode.changeState(NodeProcessingState.SELF_LINK_RESPONSE_UNPROCESSED,
+ NodeProcessingAction.SELF_LINK_RESPONSE_PARSE_OK);
+
+ }
+
+ } else {
+
+ if (cachedNode.hasResolvedSelfLink()) {
+ LOG.error(AaiUiMsgs.INVALID_RESOLVE_STATE_DURING_INIT);
+ cachedNode.changeState(NodeProcessingState.ERROR,
+ NodeProcessingAction.UNEXPECTED_STATE_TRANSITION);
+ } else {
+ cachedNode.changeState(NodeProcessingState.SELF_LINK_UNRESOLVED,
+ NodeProcessingAction.SELF_LINK_SET);
+ }
+ }
+ }
+
+ /**
+ * Process skeleton node.
+ *
+ * @param skeletonNode the skeleton node
+ * @param queryParams the query params
+ */
+ private void processSearchableEntity(SearchableEntity searchTargetEntity, QueryParams queryParams) {
+
+ if (searchTargetEntity == null) {
+ return;
+ }
+
+ if (searchTargetEntity.getId() == null) {
+ LOG.error(AaiUiMsgs.FAILED_TO_PROCESS_SKELETON_NODE, "Failed to process skeleton"
+ + " node because nodeId is null for node, " + searchTargetEntity.getLink());
+ return;
+ }
+
+ ActiveInventoryNode newNode = new ActiveInventoryNode(this.visualizationConfigs, oxmEntityLookup);
+
+ newNode.setNodeId(searchTargetEntity.getId());
+ newNode.setEntityType(searchTargetEntity.getEntityType());
+ newNode.setPrimaryKeyName(getEntityTypePrimaryKeyName(searchTargetEntity.getEntityType()));
+ newNode.setPrimaryKeyValue(searchTargetEntity.getEntityPrimaryKeyValue());
+
+ if (newNode.getEntityType() != null && newNode.getPrimaryKeyName() != null
+ && newNode.getPrimaryKeyValue() != null) {
+ newNode.addQueryParam(
+ newNode.getEntityType() + "." + newNode.getPrimaryKeyName() + ":" + newNode.getPrimaryKeyValue());
+ }
+ /*
+ * This code may need some explanation. In any graph there will be a single root node. The root
+ * node is really the center of the universe, and for now, we are tagging the search target as
+ * the root node. Everything else in the visualization of the graph will be centered around this
+ * node as the focal point of interest.
+ *
+ * Due to it's special nature, there will only ever be one root node, and it's node depth will
+ * always be equal to zero.
+ */
+
+ if (!isRootNodeFound()) {
+ if (queryParams.getSearchTargetNodeId().equals(newNode.getNodeId())) {
+ newNode.setNodeDepth(0);
+ newNode.setRootNode(true);
+ LOG.info(AaiUiMsgs.ROOT_NODE_DISCOVERED, queryParams.getSearchTargetNodeId());
+ setRootNodeFound(true);
+ }
+ }
+
+ newNode.setSelfLink(searchTargetEntity.getLink());
+
+ nodeCache.putIfAbsent(newNode.getNodeId(), newNode);
+ }
+
+ private int getTotalWorkOnHand() {
+
+ int numNodesWithPendingStates = 0;
+
+ if( isRootNodeFound()) {
+ evaluateNodeDepths();
+ }
+
+ for (ActiveInventoryNode n : nodeCache.values()) {
+
+ switch (n.getState()) {
+
+ case READY:
+ case ERROR: {
+ // do nothing, these are our normal
+ // exit states
+ break;
+ }
+
+ case NEIGHBORS_UNPROCESSED: {
+
+ if (n.getNodeDepth() < this.visualizationConfigs.getMaxSelfLinkTraversalDepth()) {
+ /*
+ * Only process our neighbors relationships if our current depth is less than the max
+ * depth
+ */
+ numNodesWithPendingStates++;
+ }
+
+ break;
+ }
+
+ default: {
+
+ /*
+ * for all other states, there is work to be done
+ */
+ numNodesWithPendingStates++;
+ }
+
+ }
+
+ }
+
+ LOG.debug(AaiUiMsgs.OUTSTANDING_WORK_PENDING_NODES,
+ String.valueOf(numNodesWithPendingStates));
+
+ int totalWorkOnHand = aaiWorkOnHand.get() + numNodesWithPendingStates;
+
+ return totalWorkOnHand;
+
+ }
+
+ /**
+ * Checks for out standing work.
+ *
+ * @return true, if successful
+ */
+ private void processOutstandingWork(QueryParams queryParams) {
+
+ while (getTotalWorkOnHand() > 0) {
+
+ /*
+ * Force an evaluation of node depths before determining if we should limit state-based
+ * traversal or processing.
+ */
+
+ processCurrentNodeStates(queryParams);
+
+ try {
+ Thread.sleep(10);
+ } catch (InterruptedException exc) {
+ LOG.error(AaiUiMsgs.PROCESSING_LOOP_INTERUPTED, exc.getMessage());
+ return;
+ }
+
+ }
+
+ }
+
+ /* (non-Javadoc)
+ * @see org.onap.aai.sparky.viewandinspect.services.VisualizationContext#processSelfLinks(org.onap.aai.sparky.sync.entity.SearchableEntity, org.onap.aai.sparky.viewandinspect.entity.QueryParams)
+ */
+ @Override
+ public void processSelfLinks(SearchableEntity searchtargetEntity, QueryParams queryParams) {
+
+ try {
+
+
+ if (searchtargetEntity == null) {
+ LOG.error(AaiUiMsgs.SELF_LINK_PROCESSING_ERROR, contextIdStr + " - Failed to"
+ + " processSelfLinks, searchtargetEntity is null");
+ return;
+ }
+
+ long startTimeInMs = System.currentTimeMillis();
+
+ processSearchableEntity(searchtargetEntity, queryParams);
+
+ /*
+ * This method is blocking until we decouple it with a CountDownLatch await condition,
+ * and make the internal graph processing more event-y.
+ */
+
+ processOutstandingWork(queryParams);
+
+ long totalResolveTime = (System.currentTimeMillis() - startTimeInMs);
+
+ long opTime = System.currentTimeMillis() - startTimeInMs;
+
+ LOG.info(AaiUiMsgs.ALL_TRANSACTIONS_RESOLVED, String.valueOf(totalResolveTime),
+ String.valueOf(totalLinksRetrieved.get()), String.valueOf(opTime));
+
+ } catch (Exception exc) {
+ LOG.error(AaiUiMsgs.VISUALIZATION_OUTPUT_ERROR, exc.getMessage());
+ }
+
+ }
+
+ /**
+ * Verify outbound neighbors.
+ */
+ private void verifyOutboundNeighbors() {
+
+ for (ActiveInventoryNode srcNode : nodeCache.values()) {
+
+ for (String targetNodeId : srcNode.getOutboundNeighbors()) {
+
+ ActiveInventoryNode targetNode = nodeCache.get(targetNodeId);
+
+ if (targetNode != null && srcNode.getNodeId() != null) {
+
+ targetNode.addInboundNeighbor(srcNode.getNodeId());
+
+ if (this.visualizationConfigs.makeAllNeighborsBidirectional()) {
+ targetNode.addOutboundNeighbor(srcNode.getNodeId());
+ }
+
+ }
+
+ }
+
+ }
+
+ }
+
+ /**
+ * Evaluate node depths.
+ */
+ private void evaluateNodeDepths() {
+
+ int numChanged = -1;
+ int numAttempts = 0;
+
+ while (numChanged != 0) {
+
+ numChanged = 0;
+ numAttempts++;
+
+ for (ActiveInventoryNode srcNode : nodeCache.values()) {
+
+ if (srcNode.getState() == NodeProcessingState.INIT) {
+
+ /*
+ * this maybe the only state that we don't want to to process the node depth on, because
+ * typically it won't have any valid fields set, and it may remain in a partial state
+ * until we have processed the self-link.
+ */
+
+ continue;
+
+ }
+
+ for (String targetNodeId : srcNode.getOutboundNeighbors()) {
+ ActiveInventoryNode targetNode = nodeCache.get(targetNodeId);
+
+ if (targetNode != null) {
+
+ if (targetNode.changeDepth(srcNode.getNodeDepth() + 1)) {
+ numChanged++;
+ }
+ }
+ }
+
+ for (String targetNodeId : srcNode.getInboundNeighbors()) {
+ ActiveInventoryNode targetNode = nodeCache.get(targetNodeId);
+
+ if (targetNode != null) {
+
+ if (targetNode.changeDepth(srcNode.getNodeDepth() + 1)) {
+ numChanged++;
+ }
+ }
+ }
+ }
+
+ if (numAttempts >= MAX_DEPTH_EVALUATION_ATTEMPTS) {
+ LOG.info(AaiUiMsgs.MAX_EVALUATION_ATTEMPTS_EXCEEDED);
+ return;
+ }
+
+ }
+
+ if (LOG.isDebugEnabled()) {
+ if (numAttempts > 0) {
+ LOG.debug(AaiUiMsgs.DEBUG_GENERIC,
+ "Evaluate node depths completed in " + numAttempts + " attempts");
+ } else {
+ LOG.debug(AaiUiMsgs.DEBUG_GENERIC,
+ "Evaluate node depths completed in 0 attempts because all nodes at correct depth");
+ }
+ }
+
+ }
+
+
+ /**
+ * Gets the entity type primary key name.
+ *
+ * @param entityType the entity type
+ * @return the entity type primary key name
+ */
+
+
+ private String getEntityTypePrimaryKeyName(String entityType) {
+
+ if (entityType == null) {
+ LOG.error(AaiUiMsgs.FAILED_TO_DETERMINE, "node primary key"
+ + " name because entity type is null");
+ return null;
+ }
+
+ OxmEntityDescriptor descriptor = oxmEntityLookup.getEntityDescriptors().get(entityType);
+
+ if (descriptor == null) {
+ LOG.error(AaiUiMsgs.FAILED_TO_DETERMINE, "oxm entity"
+ + " descriptor for entityType = " + entityType);
+ return null;
+ }
+
+ List<String> pkeyNames = descriptor.getPrimaryKeyAttributeNames();
+
+ if (pkeyNames == null || pkeyNames.size() == 0) {
+ LOG.error(AaiUiMsgs.FAILED_TO_DETERMINE, "node primary"
+ + " key because descriptor primary key names is empty");
+ return null;
+ }
+
+ return NodeUtils.concatArray(pkeyNames, "/");
+
+ }
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/services/BaseVisualizationService.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/services/BaseVisualizationService.java
new file mode 100644
index 0000000..b0b8b9e
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/services/BaseVisualizationService.java
@@ -0,0 +1,382 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.viewandinspect.services;
+
+import java.io.IOException;
+import java.security.SecureRandom;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutorService;
+
+import javax.servlet.ServletException;
+
+import org.onap.aai.cl.api.Logger;
+import org.onap.aai.cl.eelf.LoggerFactory;
+import org.onap.aai.restclient.client.OperationResult;
+import org.onap.aai.sparky.config.oxm.OxmEntityLookup;
+import org.onap.aai.sparky.config.oxm.OxmModelLoader;
+import org.onap.aai.sparky.dal.ActiveInventoryAdapter;
+import org.onap.aai.sparky.dal.ElasticSearchAdapter;
+import org.onap.aai.sparky.dal.GizmoAdapter;
+import org.onap.aai.sparky.logging.AaiUiMsgs;
+import org.onap.aai.sparky.subscription.config.SubscriptionConfig;
+import org.onap.aai.sparky.sync.config.ElasticSearchEndpointConfig;
+import org.onap.aai.sparky.sync.config.ElasticSearchSchemaConfig;
+import org.onap.aai.sparky.sync.entity.SearchableEntity;
+import org.onap.aai.sparky.util.NodeUtils;
+import org.onap.aai.sparky.viewandinspect.config.VisualizationConfigs;
+import org.onap.aai.sparky.viewandinspect.entity.ActiveInventoryNode;
+import org.onap.aai.sparky.viewandinspect.entity.D3VisualizationOutput;
+import org.onap.aai.sparky.viewandinspect.entity.GraphMeta;
+import org.onap.aai.sparky.viewandinspect.entity.QueryParams;
+import org.onap.aai.sparky.viewandinspect.entity.QueryRequest;
+
+import com.fasterxml.jackson.annotation.JsonInclude.Include;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+public class BaseVisualizationService implements VisualizationService {
+
+ private static final Logger LOG =
+ LoggerFactory.getInstance().getLogger(BaseVisualizationService.class);
+
+ private ObjectMapper mapper = new ObjectMapper();
+
+ private final ActiveInventoryAdapter aaiAdapter;
+ private final GizmoAdapter gizmoAdapter;
+ private final ElasticSearchAdapter esAdapter;
+ private final ExecutorService aaiExecutorService;
+
+ private ConcurrentHashMap<Long, VisualizationContext> contextMap;
+ private final SecureRandom secureRandom;
+
+ private VisualizationConfigs visualizationConfigs;
+ private SubscriptionConfig subConfig;
+ private ElasticSearchEndpointConfig endpointEConfig;
+ private ElasticSearchSchemaConfig schemaEConfig;
+ private OxmEntityLookup oxmEntityLookup;
+
+ public BaseVisualizationService(OxmModelLoader loader, VisualizationConfigs visualizationConfigs,
+ ActiveInventoryAdapter aaiAdapter, GizmoAdapter gizmoAdapter, ElasticSearchAdapter esAdapter,
+ ElasticSearchEndpointConfig endpointConfig, ElasticSearchSchemaConfig schemaConfig,
+ int numActiveInventoryWorkers, OxmEntityLookup oxmEntityLookup, SubscriptionConfig subscriptionConfig)
+ throws Exception {
+
+ this.visualizationConfigs = visualizationConfigs;
+ this.endpointEConfig = endpointConfig;
+ this.schemaEConfig = schemaConfig;
+ this.oxmEntityLookup = oxmEntityLookup;
+ this.subConfig = subscriptionConfig;
+
+
+ secureRandom = new SecureRandom();
+
+ /*
+ * Fix constructor with properly wired in properties
+ */
+
+ this.aaiAdapter = aaiAdapter;
+ this.gizmoAdapter = gizmoAdapter;
+ this.esAdapter = esAdapter;
+
+ this.mapper = new ObjectMapper();
+ mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
+
+ this.contextMap = new ConcurrentHashMap<Long, VisualizationContext>();
+
+ this.aaiExecutorService = NodeUtils.createNamedExecutor("SLNC-WORKER",
+ numActiveInventoryWorkers, LOG);
+
+ }
+
+ /**
+ * Analyze query request body.
+ *
+ * @param queryRequestJson the query request json
+ * @return the query request
+ */
+
+ public QueryRequest analyzeQueryRequestBody(String queryRequestJson) {
+
+
+ LOG.debug(AaiUiMsgs.DEBUG_GENERIC,
+ "analyzeQueryRequestBody()," + " queryRequestJson = " + queryRequestJson);
+
+ ObjectMapper nonEmptyMapper = new ObjectMapper();
+ nonEmptyMapper.setSerializationInclusion(Include.NON_EMPTY);
+
+ QueryRequest queryBody = null;
+
+ try {
+ queryBody = nonEmptyMapper.readValue(queryRequestJson, QueryRequest.class);
+ } catch (Exception exc) {
+ LOG.error(AaiUiMsgs.EXCEPTION_CAUGHT, "Analyzing query request body.",
+ exc.getLocalizedMessage());
+ }
+
+ return queryBody;
+
+ }
+
+ /**
+ * Log optime.
+ *
+ * @param method the method
+ * @param opStartTimeInMs the op start time in ms
+ */
+ private void logOptime(String method, long opStartTimeInMs) {
+ LOG.info(AaiUiMsgs.OPERATION_TIME, method,
+ String.valueOf(System.currentTimeMillis() - opStartTimeInMs));
+ }
+
+ private SearchableEntity extractSearchableEntityFromElasticEntity(OperationResult operationResult) {
+ if (operationResult == null || !operationResult.wasSuccessful()) {
+ // error, return empty collection
+ return null;
+ }
+
+ SearchableEntity sourceEntity = null;
+ if (operationResult.wasSuccessful()) {
+
+ try {
+ JsonNode elasticValue = mapper.readValue(operationResult.getResult(), JsonNode.class);
+
+ if (elasticValue != null) {
+ JsonNode sourceField = elasticValue.get("_source");
+
+ if (sourceField != null) {
+ sourceEntity = new SearchableEntity();
+
+ String entityType = NodeUtils.extractFieldValueFromObject(sourceField, "entityType");
+ sourceEntity.setEntityType(entityType);
+ String entityPrimaryKeyValue = NodeUtils.extractFieldValueFromObject(sourceField, "entityPrimaryKeyValue");
+ sourceEntity.setEntityPrimaryKeyValue(entityPrimaryKeyValue);
+ String link = NodeUtils.extractFieldValueFromObject(sourceField, "link");
+ sourceEntity.setLink(link);
+ String lastmodTimestamp = NodeUtils.extractFieldValueFromObject(sourceField, "lastmodTimestamp");
+ sourceEntity.setEntityTimeStamp(lastmodTimestamp);
+ }
+ }
+ } catch (IOException ioe) {
+ LOG.error(AaiUiMsgs.JSON_CONVERSION_ERROR, "a json node ", ioe.getLocalizedMessage());
+ }
+ }
+ return sourceEntity;
+ }
+
+ /**
+ * Builds the visualization using generic query.
+ *
+ * @param queryRequest the query request
+ * @return the operation result
+ */
+ public OperationResult buildVisualizationUsingGenericQuery(QueryRequest queryRequest) {
+
+ OperationResult returnValue = new OperationResult();
+ OperationResult dataCollectionResult = null;
+ QueryParams queryParams = null;
+ SearchableEntity sourceEntity = null;
+
+ try {
+
+ /*
+ * Here is where we need to make a dip to elastic-search for the self-link by entity-id (link
+ * hash).
+ */
+ dataCollectionResult = esAdapter.retrieveEntityById(endpointEConfig.getEsIpAddress(),
+ endpointEConfig.getEsServerPort(),schemaEConfig.getIndexName(),
+ schemaEConfig.getIndexDocType(), queryRequest.getHashId());
+ sourceEntity = extractSearchableEntityFromElasticEntity(dataCollectionResult);
+
+ if (sourceEntity != null) {
+ sourceEntity.generateId();
+ }
+
+ queryParams = new QueryParams();
+ queryParams.setSearchTargetNodeId(queryRequest.getHashId());
+
+ } catch (Exception e1) {
+ LOG.error(AaiUiMsgs.FAILED_TO_GET_NODES_QUERY_RESULT, e1.getLocalizedMessage());
+ dataCollectionResult = new OperationResult(500, "Failed to get nodes-query result from AAI");
+ }
+
+ if (dataCollectionResult.getResultCode() == 200) {
+
+ String d3OutputJsonOutput = null;
+
+ try {
+
+ d3OutputJsonOutput = getVisualizationOutputBasedonGenericQuery( sourceEntity, queryParams, queryRequest);
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug(AaiUiMsgs.DEBUG_GENERIC,
+ "Generated D3" + " output as json = " + d3OutputJsonOutput);
+ }
+
+ if (d3OutputJsonOutput != null) {
+ returnValue.setResultCode(200);
+ returnValue.setResult(d3OutputJsonOutput);
+ } else {
+ returnValue.setResult(500, "Failed to generate D3 graph visualization");
+ }
+
+ } catch (Exception exc) {
+ returnValue.setResult(500,
+ "Failed to generate D3 graph visualization, due to a servlet exception.");
+ LOG.error(AaiUiMsgs.ERROR_D3_GRAPH_VISUALIZATION, exc.getLocalizedMessage());
+ }
+ } else {
+ returnValue.setResult(dataCollectionResult.getResultCode(), dataCollectionResult.getResult());
+ }
+
+ return returnValue;
+
+ }
+
+
+ /**
+ * Gets the visualization output basedon generic query.
+ *
+ * @param searchtargetEntity entity that will be used to start visualization flow
+ * @param queryParams the query params
+ * @return the visualization output basedon generic query
+ * @throws ServletException the servlet exception
+ * @throws
+ */
+ private String getVisualizationOutputBasedonGenericQuery(SearchableEntity searchtargetEntity,
+ QueryParams queryParams, QueryRequest request) throws ServletException {
+
+ long opStartTimeInMs = System.currentTimeMillis();
+
+ VisualizationTransformer transformer = null;
+ try {
+ transformer = new VisualizationTransformer(visualizationConfigs, subConfig);
+ } catch (Exception exc) {
+ throw new ServletException(
+ "Failed to create VisualizationTransformer instance because of execption", exc);
+ }
+
+ VisualizationContext visContext = null;
+ long contextId = secureRandom.nextLong();
+ try {
+ if ( visualizationConfigs.isGizmoEnabled()) {
+ visContext = new BaseGizmoVisualizationContext(contextId, this.gizmoAdapter, aaiExecutorService,
+ this.visualizationConfigs, oxmEntityLookup);
+ } else {
+ visContext = new BaseVisualizationContext(contextId, this.aaiAdapter, aaiExecutorService,
+ this.visualizationConfigs, oxmEntityLookup);
+ }
+
+ contextMap.putIfAbsent(contextId, visContext);
+ } catch (Exception e1) {
+ LOG.error(AaiUiMsgs.EXCEPTION_CAUGHT,
+ "While building Visualization Context, " + e1.getLocalizedMessage());
+ throw new ServletException(e1);
+ }
+
+ String jsonResponse = null;
+
+ long startTimeInMs = System.currentTimeMillis();
+
+ visContext.processSelfLinks(searchtargetEntity, queryParams);
+ contextMap.remove(contextId);
+
+ logOptime("collectSelfLinkNodes()", startTimeInMs);
+
+ /*
+ * Flatten the graphs into a set of Graph and Link nodes. In this method I want the node graph
+ * resulting from the edge-tag-query to be represented first, and then we'll layer in
+ * relationship data.
+ */
+ long overlayDataStartTimeInMs = System.currentTimeMillis();
+
+ Map<String, ActiveInventoryNode> cachedNodeMap = visContext.getNodeCache();
+
+ if (LOG.isDebugEnabled()) {
+
+ StringBuilder sb = new StringBuilder(128);
+
+ sb.append("\nCached Node Map:\n");
+ for (String k : cachedNodeMap.keySet()) {
+ sb.append("\n----");
+ sb.append("\n").append(cachedNodeMap.get(k).dumpNodeTree(true));
+ }
+
+ LOG.debug(AaiUiMsgs.DEBUG_GENERIC, sb.toString());
+ }
+
+ transformer.buildFlatNodeArrayFromGraphCollection(cachedNodeMap);
+ transformer.buildLinksFromGraphCollection(cachedNodeMap);
+
+ /*
+ * - Apply configuration-driven styling
+ * - Build the final transformation response object
+ * - Use information we have to populate the GraphMeta object
+ */
+
+ transformer.addSearchTargetAttributesToRootNode();
+
+ GraphMeta graphMeta = new GraphMeta();
+
+ D3VisualizationOutput output = null;
+ try {
+ output = transformer
+ .generateVisualizationOutput((System.currentTimeMillis() - opStartTimeInMs), graphMeta);
+ } catch (JsonProcessingException exc) {
+ throw new ServletException("Caught an exception while generation visualization output", exc);
+ } catch (IOException exc) {
+ LOG.error(AaiUiMsgs.FAILURE_TO_PROCESS_REQUEST, exc.getLocalizedMessage());
+ }
+
+ output.setInlineMessage(visContext.getInlineMessage());
+ output.getGraphMeta().setNumLinkResolveFailed(visContext.getNumFailedLinkResolve());
+ output.getGraphMeta().setNumLinksResolvedSuccessfullyFromCache(
+ visContext.getNumSuccessfulLinkResolveFromCache());
+ output.getGraphMeta().setNumLinksResolvedSuccessfullyFromServer(
+ visContext.getNumSuccessfulLinkResolveFromFromServer());
+
+ try {
+ jsonResponse = transformer.convertVisualizationOutputToJson(output);
+ } catch (JsonProcessingException jpe) {
+ throw new ServletException(
+ "Caught an exception while converting visualization output to json", jpe);
+ }
+
+ logOptime("[build flat node array, add relationship data, search target,"
+ + " color scheme, and generate visualization output]", overlayDataStartTimeInMs);
+
+ logOptime("doFilter()", opStartTimeInMs);
+
+ return jsonResponse;
+
+ }
+
+ public void shutdown() {
+ aaiExecutorService.shutdown();
+ }
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/services/VisualizationContext.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/services/VisualizationContext.java
new file mode 100644
index 0000000..6d4ed88
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/services/VisualizationContext.java
@@ -0,0 +1,55 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.viewandinspect.services;
+
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.onap.aai.sparky.sync.entity.SearchableEntity;
+import org.onap.aai.sparky.viewandinspect.entity.ActiveInventoryNode;
+import org.onap.aai.sparky.viewandinspect.entity.InlineMessage;
+import org.onap.aai.sparky.viewandinspect.entity.QueryParams;
+
+
+public interface VisualizationContext {
+
+ /**
+ * Process self links.
+ *
+ * @param skeletonNode the skeleton node
+ * @param queryParams the query params
+ */
+ void processSelfLinks(SearchableEntity searchtargetEntity, QueryParams queryParams);
+
+ ConcurrentHashMap<String, ActiveInventoryNode> getNodeCache();
+
+ InlineMessage getInlineMessage();
+
+ int getNumFailedLinkResolve();
+
+ int getNumSuccessfulLinkResolveFromCache();
+
+ int getNumSuccessfulLinkResolveFromFromServer();
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/services/VisualizationService.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/services/VisualizationService.java
new file mode 100644
index 0000000..c8f252c
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/services/VisualizationService.java
@@ -0,0 +1,52 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.viewandinspect.services;
+
+
+import org.onap.aai.restclient.client.OperationResult;
+import org.onap.aai.sparky.viewandinspect.entity.QueryRequest;
+
+public interface VisualizationService {
+
+ /**
+ * Analyze query request body.
+ *
+ * @param queryRequestJson the query request json
+ * @return the query request
+ */
+
+ QueryRequest analyzeQueryRequestBody(String queryRequestJson);
+
+ /**
+ * Builds the visualization using generic query.
+ *
+ * @param queryRequest the query request
+ * @return the operation result
+ */
+ OperationResult buildVisualizationUsingGenericQuery(QueryRequest queryRequest);
+
+ void shutdown();
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/services/VisualizationTransformer.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/services/VisualizationTransformer.java
new file mode 100644
index 0000000..46a70c3
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/services/VisualizationTransformer.java
@@ -0,0 +1,305 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.viewandinspect.services;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+import org.onap.aai.cl.api.Logger;
+import org.onap.aai.cl.eelf.LoggerFactory;
+import org.onap.aai.sparky.config.SparkyResourceLoader;
+import org.onap.aai.sparky.logging.AaiUiMsgs;
+import org.onap.aai.sparky.subscription.config.SubscriptionConfig;
+import org.onap.aai.sparky.util.ConfigHelper;
+import org.onap.aai.sparky.viewandinspect.config.VisualizationConfigs;
+import org.onap.aai.sparky.viewandinspect.entity.ActiveInventoryNode;
+import org.onap.aai.sparky.viewandinspect.entity.D3VisualizationOutput;
+import org.onap.aai.sparky.viewandinspect.entity.GraphMeta;
+import org.onap.aai.sparky.viewandinspect.entity.NodeDebug;
+import org.onap.aai.sparky.viewandinspect.entity.SparkyGraphLink;
+import org.onap.aai.sparky.viewandinspect.entity.SparkyGraphNode;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.ObjectWriter;
+
+/**
+ * The idea here is to receive a collection of graphs and then fold them together (or not) based on
+ * configuration. The first goal will be to fold all like-resources together, but the choice of
+ * folding could/should be configurable, and will simply change the degree of link based nodes when
+ * we generate the Node-Array and Link-Array output.
+ *
+ * @author DAVEA
+ *
+ */
+
+public class VisualizationTransformer {
+
+ private static final Logger LOG = LoggerFactory.getInstance().getLogger(
+ VisualizationTransformer.class);
+
+ List<SparkyGraphNode> flatNodeArray = new ArrayList<SparkyGraphNode>();
+
+ /*
+ * Maybe this isn't a string but Json-Model objects that we will convert to final string
+ * representation when we dump the node-array and link-array collections the post-data blob in the
+ * HttpServletResponse.
+ */
+
+ List<SparkyGraphLink> linkArrayOutput = new ArrayList<SparkyGraphLink>();
+
+ private VisualizationConfigs visualizationConfigs;
+ private SubscriptionConfig subConfig;
+
+ /**
+ * Instantiates a new visualization transformer.
+ *
+ * @throws Exception the exception
+ */
+ public VisualizationTransformer(VisualizationConfigs visualizationConfigs,
+ SubscriptionConfig subConfig) throws Exception {
+ this.visualizationConfigs = visualizationConfigs;
+ this.subConfig = subConfig;
+ }
+
+
+ /**
+ * Log optime.
+ *
+ * @param method the method
+ * @param startTimeInMs the start time in ms
+ */
+ private void logOptime(String method, long startTimeInMs) {
+ LOG.info(AaiUiMsgs.OPERATION_TIME, method,
+ String.valueOf((System.currentTimeMillis() - startTimeInMs)));
+ }
+
+ /**
+ * Adds the search target attributes to root node.
+ */
+ public void addSearchTargetAttributesToRootNode() {
+
+ for (SparkyGraphNode n : flatNodeArray) {
+ if (n.isRootNode()) {
+ n.getNodeMeta().setSearchTarget(true);
+ n.getNodeMeta().setClassName(this.visualizationConfigs.getSelectedSearchedNodeClassName());
+ }
+
+ }
+
+ }
+
+ /**
+ * Generate visualization output.
+ *
+ * @param preProcessingOpTimeInMs the pre processing op time in ms
+ * @param graphMeta the graph meta
+ * @return the d 3 visualization output
+ * @throws JsonProcessingException the json processing exception
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+
+ public D3VisualizationOutput generateVisualizationOutput(long preProcessingOpTimeInMs,
+ GraphMeta graphMeta) throws JsonProcessingException, IOException {
+
+ long opStartTimeInMs = System.currentTimeMillis();
+
+ /*
+ * iterate over the flat collection, and only add the graph nodes to the graph node collection
+ */
+
+ D3VisualizationOutput output = new D3VisualizationOutput();
+
+ output.setGraphMeta(graphMeta);
+
+ for (SparkyGraphNode n : flatNodeArray) {
+ if ( n.getItemType()!= null) {
+ output.pegCounter(n.getItemType());
+ }
+ }
+
+ output.addNodes(flatNodeArray);
+ output.addLinks(linkArrayOutput);
+
+ int numNodes = flatNodeArray.size();
+ int numLinks = linkArrayOutput.size();
+
+ LOG.info(AaiUiMsgs.VISUALIZATION_GRAPH_OUTPUT, String.valueOf(numNodes),
+ String.valueOf(numLinks));
+
+ if (numLinks < (numNodes - 1)) {
+ LOG.warn(AaiUiMsgs.DANGLING_NODE_WARNING, String.valueOf(numLinks),
+ String.valueOf(numNodes));
+ }
+
+ ObjectMapper mapper = new ObjectMapper();
+
+ SparkyResourceLoader resourceLoader = visualizationConfigs.getResourceLoader();
+ File aaiEntityDescriptorsFile = resourceLoader.getResourceAsFile(visualizationConfigs.getAaiEntityNodeDescriptors(), true);
+
+ if (aaiEntityDescriptorsFile != null) {
+ com.fasterxml.jackson.databind.JsonNode aaiEntityNodeDefinitions =
+ mapper.readTree(aaiEntityDescriptorsFile);
+ graphMeta.setAaiEntityNodeDescriptors(aaiEntityNodeDefinitions);
+ } else {
+ LOG.error(AaiUiMsgs.ERROR_GENERIC, "Failed to find " + visualizationConfigs.getAaiEntityNodeDescriptors());
+ graphMeta.setAaiEntityNodeDescriptors(null);
+ }
+
+ graphMeta.setNumLinks(linkArrayOutput.size());
+ graphMeta.setNumNodes(flatNodeArray.size());
+ graphMeta.setRenderTimeInMs(preProcessingOpTimeInMs);
+
+ output.setGraphMeta(graphMeta);
+
+ logOptime("generateVisualizationOutput()", opStartTimeInMs);
+
+ return output;
+ }
+
+ /**
+ * Convert visualization output to json.
+ *
+ * @param output the output
+ * @return the string
+ * @throws JsonProcessingException the json processing exception
+ */
+ public String convertVisualizationOutputToJson(D3VisualizationOutput output)
+ throws JsonProcessingException {
+
+ if (output == null) {
+ return null;
+ }
+
+ ObjectWriter ow = new ObjectMapper().writer().withDefaultPrettyPrinter();
+
+ return ow.writeValueAsString(output);
+
+ }
+
+ /**
+ * Builds the links from graph collection.
+ *
+ * @param nodeMap the node map
+ */
+ public void buildLinksFromGraphCollection(Map<String, ActiveInventoryNode> nodeMap) {
+
+ for (ActiveInventoryNode ain : nodeMap.values()) {
+
+ /*
+ * This one is a little bit different, when we iterate over the collection we only want to
+ * draw the links for node that are less than the max traversal depth. We want to only draw
+ * links at a depth of n-1 because we are basing the links on the outbound neighbors from the
+ * current node.
+ */
+
+ if (ain.getNodeDepth() < this.visualizationConfigs.getMaxSelfLinkTraversalDepth()) {
+
+ Collection<String> outboundNeighbors = ain.getOutboundNeighbors();
+
+ for (String outboundNeighbor : outboundNeighbors) {
+
+ SparkyGraphLink nodeLink = new SparkyGraphLink();
+
+ nodeLink.setId(UUID.randomUUID().toString());
+ nodeLink.setSource(ain.getNodeId());
+ nodeLink.setTarget(outboundNeighbor);
+
+ linkArrayOutput.add(nodeLink);
+
+ }
+
+ Collection<String> inboundNeighbors = ain.getInboundNeighbors();
+
+ for (String inboundNeighbor : inboundNeighbors) {
+
+ SparkyGraphLink nodeLink = new SparkyGraphLink();
+
+ nodeLink.setId(UUID.randomUUID().toString());
+ nodeLink.setSource(ain.getNodeId());
+ nodeLink.setTarget(inboundNeighbor);
+
+ linkArrayOutput.add(nodeLink);
+
+ }
+
+
+ } else {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug(AaiUiMsgs.DEBUG_GENERIC, "buildLinks(),"
+ + " Filtering node = " + ain.getNodeId() + " @ depth = "
+ + ain.getNodeDepth());
+ }
+
+ }
+ }
+
+ }
+
+ /**
+ * Builds the flat node array from graph collection.
+ *
+ * @param nodeMap the node map
+ */
+ /*
+ * Recursive function to walk multi-graph nodes and children to build a folded resource target
+ * graph.
+ */
+ public void buildFlatNodeArrayFromGraphCollection(Map<String, ActiveInventoryNode> nodeMap) {
+
+ for (ActiveInventoryNode n : nodeMap.values()) {
+
+ if (n.getNodeDepth() <= this.visualizationConfigs.getMaxSelfLinkTraversalDepth()) {
+
+ SparkyGraphNode jsonNode = new SparkyGraphNode(n, this.visualizationConfigs, this.subConfig);
+
+ jsonNode.getNodeMeta().setClassName(this.visualizationConfigs.getGeneralNodeClassName());
+
+ if (this.visualizationConfigs.isVisualizationDebugEnabled()) {
+
+ NodeDebug nodeDebug = jsonNode.getNodeMeta().getNodeDebug();
+
+ if (nodeDebug != null) {
+ nodeDebug.setProcessingError(n.isProcessingErrorOccurred());
+ nodeDebug.setProcessingErrorCauses(n.getProcessingErrorCauses());
+ }
+ }
+ flatNodeArray.add(jsonNode);
+ } else {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug(AaiUiMsgs.DEBUG_GENERIC,
+ "Filtering node from visualization: " + n.getNodeId() + " @ depth = "
+ + n.getNodeDepth());
+ }
+ }
+ }
+ }
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/task/PerformGizmoNodeSelfLinkProcessingTask.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/task/PerformGizmoNodeSelfLinkProcessingTask.java
new file mode 100644
index 0000000..820b749
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/task/PerformGizmoNodeSelfLinkProcessingTask.java
@@ -0,0 +1,128 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.viewandinspect.task;
+
+import java.util.Map;
+import java.util.function.Supplier;
+
+import org.onap.aai.cl.api.Logger;
+import org.onap.aai.cl.eelf.LoggerFactory;
+import org.onap.aai.restclient.client.OperationResult;
+import org.onap.aai.sparky.dal.GizmoAdapter;
+import org.onap.aai.sparky.logging.AaiUiMsgs;
+import org.onap.aai.sparky.viewandinspect.entity.NodeProcessingTransaction;
+import org.slf4j.MDC;
+
+/**
+ * The Class PerformNodeSelfLinkProcessingTask.
+ */
+public class PerformGizmoNodeSelfLinkProcessingTask implements Supplier<NodeProcessingTransaction> {
+
+ private static final Logger logger =
+ LoggerFactory.getInstance().getLogger(PerformGizmoNodeSelfLinkProcessingTask.class);
+
+ private NodeProcessingTransaction txn;
+ private GizmoAdapter gizmoAdapter;
+ private Map<String, String> contextMap;
+
+ /**
+ * Instantiates a new perform node self link processing task.
+ *
+ * @param txn the txn
+ * @param aaiProvider the aai provider
+ * @param aaiConfig the aai config
+ */
+ /**
+ *
+ * @param txn
+ * @param requestParameters
+ * @param aaiProvider
+ * @param aaiConfig
+ */
+ public PerformGizmoNodeSelfLinkProcessingTask(NodeProcessingTransaction txn, String requestParameters,
+ GizmoAdapter gizmoAdapter) {
+ this.gizmoAdapter = gizmoAdapter;
+ this.txn = txn;
+ this.contextMap = MDC.getCopyOfContextMap();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.util.function.Supplier#get()
+ */
+ @Override
+ public NodeProcessingTransaction get() {
+ MDC.setContextMap(contextMap);
+ OperationResult opResult = new OperationResult();
+ String link = txn.getSelfLink();
+
+ if (link == null) {
+ opResult.setResult(500, "Aborting self-link processing because self link is null");
+ txn.setOpResult(opResult);
+ return txn;
+ }
+
+ /**
+ * Rebuild the self link:
+ *
+ * <li>build the base url with the configured scheme + authority (server:port)
+ * <li>recombine baseUrl + originalEncodedLink + queryStringParameters
+ *
+ */
+
+ final String urlSchemeAndAuthority = gizmoAdapter.repairInventorySelfLink("", null);
+
+ String parameters = txn.getRequestParameters();
+ link = urlSchemeAndAuthority + link;
+
+ if (parameters != null) {
+ link += parameters;
+ }
+
+ if (logger.isDebugEnabled()) {
+ logger.debug(AaiUiMsgs.DEBUG_GENERIC, "Collecting " + link);
+ }
+
+ try {
+
+ opResult = gizmoAdapter.queryGizmoWithRetries(link, "application/json",
+ gizmoAdapter.getEndpointConfig().getNumRequestRetries());
+ } catch (Exception exc) {
+ opResult = new OperationResult();
+ opResult.setResult(500, "Querying AAI with retry failed due to an exception.");
+ logger.error(AaiUiMsgs.ERROR_AAI_QUERY_WITH_RETRY, exc.getMessage());
+ }
+
+ if (logger.isDebugEnabled()) {
+ logger.debug(AaiUiMsgs.DEBUG_GENERIC, "Operation result = " + opResult.toString());
+ }
+
+ txn.setOpResult(opResult);
+ return txn;
+
+ }
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/task/PerformNodeSelfLinkProcessingTask.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/task/PerformNodeSelfLinkProcessingTask.java
new file mode 100644
index 0000000..c686443
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/task/PerformNodeSelfLinkProcessingTask.java
@@ -0,0 +1,129 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.viewandinspect.task;
+
+import java.util.Map;
+import java.util.function.Supplier;
+
+import org.onap.aai.cl.api.Logger;
+import org.onap.aai.cl.eelf.LoggerFactory;
+import org.onap.aai.restclient.client.OperationResult;
+import org.onap.aai.sparky.dal.ActiveInventoryAdapter;
+import org.onap.aai.sparky.logging.AaiUiMsgs;
+import org.onap.aai.sparky.viewandinspect.entity.NodeProcessingTransaction;
+import org.slf4j.MDC;
+
+/**
+ * The Class PerformNodeSelfLinkProcessingTask.
+ */
+public class PerformNodeSelfLinkProcessingTask implements Supplier<NodeProcessingTransaction> {
+
+ private static final Logger logger =
+ LoggerFactory.getInstance().getLogger(PerformNodeSelfLinkProcessingTask.class);
+
+ private NodeProcessingTransaction txn;
+ private ActiveInventoryAdapter aaiAdapter;
+ private Map<String, String> contextMap;
+
+ /**
+ * Instantiates a new perform node self link processing task.
+ *
+ * @param txn the txn
+ * @param aaiProvider the aai provider
+ * @param aaiConfig the aai config
+ */
+ /**
+ *
+ * @param txn
+ * @param requestParameters
+ * @param aaiProvider
+ * @param aaiConfig
+ */
+ public PerformNodeSelfLinkProcessingTask(NodeProcessingTransaction txn, String requestParameters,
+ ActiveInventoryAdapter aaiAdapter) {
+ this.aaiAdapter = aaiAdapter;
+ this.txn = txn;
+ this.contextMap = MDC.getCopyOfContextMap();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.util.function.Supplier#get()
+ */
+ @Override
+ public NodeProcessingTransaction get() {
+ MDC.setContextMap(contextMap);
+ OperationResult opResult = new OperationResult();
+ String link = txn.getSelfLink();
+
+ if (link == null) {
+ opResult.setResult(500, "Aborting self-link processing because self link is null");
+ txn.setOpResult(opResult);
+ return txn;
+ }
+
+ /**
+ * Rebuild the self link:
+ *
+ * <li>build the base url with the configured scheme + authority (server:port)
+ * <li>recombine baseUrl + originalEncodedLink + queryStringParameters
+ *
+ */
+
+ final String urlSchemeAndAuthority = aaiAdapter.repairSelfLink("");
+
+ String parameters = txn.getRequestParameters();
+ link = urlSchemeAndAuthority + link;
+
+ if (parameters != null) {
+ link += parameters;
+ }
+
+
+
+ if (logger.isDebugEnabled()) {
+ logger.debug(AaiUiMsgs.DEBUG_GENERIC, "Collecting " + link);
+ }
+
+ try {
+ opResult = aaiAdapter.queryActiveInventoryWithRetries(link, "application/json",
+ aaiAdapter.getEndpointConfig().getNumRequestRetries());
+ } catch (Exception exc) {
+ opResult = new OperationResult();
+ opResult.setResult(500, "Querying AAI with retry failed due to an exception.");
+ logger.error(AaiUiMsgs.ERROR_AAI_QUERY_WITH_RETRY, exc.getMessage());
+ }
+
+ if (logger.isDebugEnabled()) {
+ logger.debug(AaiUiMsgs.DEBUG_GENERIC, "Operation result = " + opResult.toString());
+ }
+
+ txn.setOpResult(opResult);
+ return txn;
+
+ }
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/task/PerformSelfLinkDeterminationTask.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/task/PerformSelfLinkDeterminationTask.java
new file mode 100644
index 0000000..6d39849
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/task/PerformSelfLinkDeterminationTask.java
@@ -0,0 +1,95 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.viewandinspect.task;
+
+import java.util.Map;
+import java.util.function.Supplier;
+
+import org.onap.aai.cl.api.Logger;
+import org.onap.aai.cl.eelf.LoggerFactory;
+import org.onap.aai.restclient.client.OperationResult;
+import org.onap.aai.sparky.dal.ActiveInventoryAdapter;
+import org.onap.aai.sparky.logging.AaiUiMsgs;
+import org.onap.aai.sparky.viewandinspect.entity.SelfLinkDeterminationTransaction;
+import org.slf4j.MDC;
+
+public class PerformSelfLinkDeterminationTask implements Supplier<SelfLinkDeterminationTransaction> {
+
+ private static final Logger logger =
+ LoggerFactory.getInstance().getLogger(PerformSelfLinkDeterminationTask.class);
+
+ private SelfLinkDeterminationTransaction txn;
+ private ActiveInventoryAdapter aaiAdapter;
+ private Map<String, String> contextMap;
+
+
+ /**
+ * Instantiates a new perform node self link processing task.
+ *
+ * @param txn the txn
+ * @param requestParameters the request parameters
+ * @param aaiProvider the aai provider
+ */
+ public PerformSelfLinkDeterminationTask(SelfLinkDeterminationTransaction txn, String requestParameters,
+ ActiveInventoryAdapter aaiAdapter) {
+
+ this.aaiAdapter = aaiAdapter;
+ this.txn = txn;
+ this.contextMap = MDC.getCopyOfContextMap();
+ }
+
+ /* (non-Javadoc)
+ * @see java.util.function.Supplier#get()
+ */
+ @Override
+ public SelfLinkDeterminationTransaction get() {
+ MDC.setContextMap(contextMap);
+ if (txn.getQueryString() == null) {
+ OperationResult opResult = new OperationResult();
+ opResult.setResult(500, "Aborting self-link determination because self link query is null.");
+ txn.setOpResult(opResult);
+ return txn;
+ }
+
+ OperationResult opResult = null;
+ try {
+ opResult = aaiAdapter.queryActiveInventoryWithRetries(txn.getQueryString(), "application/json",
+ aaiAdapter.getEndpointConfig().getNumRequestRetries());
+ } catch (Exception exc) {
+ opResult = new OperationResult();
+ opResult.setResult(500, "Querying AAI with retry failed due to an exception.");
+ logger.error(AaiUiMsgs.ERROR_AAI_QUERY_WITH_RETRY, exc.getMessage());
+ }
+
+ if (logger.isDebugEnabled()) {
+ logger.debug("Operation result = " + opResult.toString());
+ }
+
+ txn.setOpResult(opResult);
+ return txn;
+
+ }
+
+} \ No newline at end of file
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewinspect/sync/ViewInspectEntitySynchronizer.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewinspect/sync/ViewInspectEntitySynchronizer.java
new file mode 100644
index 0000000..8f29519
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewinspect/sync/ViewInspectEntitySynchronizer.java
@@ -0,0 +1,779 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.viewinspect.sync;
+
+import static java.util.concurrent.CompletableFuture.supplyAsync;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Deque;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentLinkedDeque;
+import java.util.concurrent.ExecutorService;
+import java.util.function.Supplier;
+
+import org.onap.aai.cl.api.Logger;
+import org.onap.aai.cl.eelf.LoggerFactory;
+import org.onap.aai.cl.mdc.MdcContext;
+import org.onap.aai.restclient.client.OperationResult;
+import org.onap.aai.sparky.config.oxm.OxmEntityDescriptor;
+import org.onap.aai.sparky.config.oxm.OxmEntityLookup;
+import org.onap.aai.sparky.config.oxm.SearchableEntityLookup;
+import org.onap.aai.sparky.config.oxm.SearchableOxmEntityDescriptor;
+import org.onap.aai.sparky.dal.ActiveInventoryAdapter;
+import org.onap.aai.sparky.dal.NetworkTransaction;
+import org.onap.aai.sparky.dal.rest.HttpMethod;
+import org.onap.aai.sparky.logging.AaiUiMsgs;
+import org.onap.aai.sparky.sync.AbstractEntitySynchronizer;
+import org.onap.aai.sparky.sync.IndexSynchronizer;
+import org.onap.aai.sparky.sync.SynchronizerConstants;
+import org.onap.aai.sparky.sync.config.ElasticSearchSchemaConfig;
+import org.onap.aai.sparky.sync.config.NetworkStatisticsConfig;
+import org.onap.aai.sparky.sync.entity.MergableEntity;
+import org.onap.aai.sparky.sync.entity.SearchableEntity;
+import org.onap.aai.sparky.sync.entity.SelfLinkDescriptor;
+import org.onap.aai.sparky.sync.enumeration.OperationState;
+import org.onap.aai.sparky.sync.enumeration.SynchronizerState;
+import org.onap.aai.sparky.sync.task.PerformActiveInventoryRetrieval;
+import org.onap.aai.sparky.sync.task.PerformElasticSearchPut;
+import org.onap.aai.sparky.sync.task.PerformElasticSearchRetrieval;
+import org.onap.aai.sparky.sync.task.PerformElasticSearchUpdate;
+import org.onap.aai.sparky.util.NodeUtils;
+import org.slf4j.MDC;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectReader;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+
+/**
+ * The Class SearchableEntitySynchronizer.
+ */
+public class ViewInspectEntitySynchronizer extends AbstractEntitySynchronizer
+ implements IndexSynchronizer {
+
+ /**
+ * The Class RetrySearchableEntitySyncContainer.
+ */
+ private class RetrySearchableEntitySyncContainer {
+ NetworkTransaction txn;
+ SearchableEntity se;
+
+ /**
+ * Instantiates a new retry searchable entity sync container.
+ *
+ * @param txn the txn
+ * @param se the se
+ */
+ public RetrySearchableEntitySyncContainer(NetworkTransaction txn, SearchableEntity se) {
+ this.txn = txn;
+ this.se = se;
+ }
+
+ public NetworkTransaction getNetworkTransaction() {
+ return txn;
+ }
+
+ public SearchableEntity getSearchableEntity() {
+ return se;
+ }
+ }
+
+ private static final Logger LOG =
+ LoggerFactory.getInstance().getLogger(ViewInspectEntitySynchronizer.class);
+
+ private boolean allWorkEnumerated;
+ private Deque<SelfLinkDescriptor> selflinks;
+ private Deque<RetrySearchableEntitySyncContainer> retryQueue;
+ private Map<String, Integer> retryLimitTracker;
+ protected ExecutorService esPutExecutor;
+ private OxmEntityLookup oxmEntityLookup;
+ private SearchableEntityLookup searchableEntityLookup;
+
+ /**
+ * Instantiates a new searchable entity synchronizer.
+ *
+ * @param indexName the index name
+ * @throws Exception the exception
+ */
+ public ViewInspectEntitySynchronizer(ElasticSearchSchemaConfig schemaConfig,
+ int internalSyncWorkers, int aaiWorkers, int esWorkers, NetworkStatisticsConfig aaiStatConfig,
+ NetworkStatisticsConfig esStatConfig, OxmEntityLookup oxmEntityLookup,
+ SearchableEntityLookup searchableEntityLookup) throws Exception {
+ super(LOG, "SES", internalSyncWorkers, aaiWorkers, esWorkers, schemaConfig.getIndexName(),
+ aaiStatConfig, esStatConfig);
+
+ this.oxmEntityLookup = oxmEntityLookup;
+ this.searchableEntityLookup = searchableEntityLookup;
+ this.allWorkEnumerated = false;
+ this.selflinks = new ConcurrentLinkedDeque<SelfLinkDescriptor>();
+ this.retryQueue = new ConcurrentLinkedDeque<RetrySearchableEntitySyncContainer>();
+ this.retryLimitTracker = new ConcurrentHashMap<String, Integer>();
+ this.synchronizerName = "Searchable Entity Synchronizer";
+ this.esPutExecutor = NodeUtils.createNamedExecutor("SES-ES-PUT", 5, LOG);
+ this.aaiEntityStats.intializeEntityCounters(
+ searchableEntityLookup.getSearchableEntityDescriptors().keySet());
+ this.esEntityStats.intializeEntityCounters(
+ searchableEntityLookup.getSearchableEntityDescriptors().keySet());
+ this.syncDurationInMs = -1;
+ }
+
+ /**
+ * Collect all the work.
+ *
+ * @return the operation state
+ */
+ private OperationState collectAllTheWork() {
+ final Map<String, String> contextMap = MDC.getCopyOfContextMap();
+ Map<String, SearchableOxmEntityDescriptor> descriptorMap =
+ searchableEntityLookup.getSearchableEntityDescriptors();
+
+ if (descriptorMap.isEmpty()) {
+ LOG.error(AaiUiMsgs.ERROR_LOADING_OXM_SEARCHABLE_ENTITIES);
+ LOG.info(AaiUiMsgs.ERROR_LOADING_OXM_SEARCHABLE_ENTITIES);
+ return OperationState.ERROR;
+ }
+
+ Collection<String> syncTypes = descriptorMap.keySet();
+
+ /*Collection<String> syncTypes = new ArrayList<String>();
+ syncTypes.add("service-instance");*/
+
+ try {
+
+ /*
+ * launch a parallel async thread to process the documents for each entity-type (to max the
+ * of the configured executor anyway)
+ */
+
+ aaiWorkOnHand.set(syncTypes.size());
+
+ for (String key : syncTypes) {
+
+ supplyAsync(new Supplier<Void>() {
+
+ @Override
+ public Void get() {
+ MDC.setContextMap(contextMap);
+ OperationResult typeLinksResult = null;
+ try {
+ typeLinksResult = aaiAdapter.getSelfLinksByEntityType(key);
+ System.out.println(typeLinksResult);
+ aaiWorkOnHand.decrementAndGet();
+ processEntityTypeSelfLinks(typeLinksResult);
+ } catch (Exception exc) {
+ // TODO -> LOG, what should be logged here?
+ }
+
+ return null;
+ }
+
+ }, aaiExecutor).whenComplete((result, error) -> {
+
+ if (error != null) {
+ LOG.error(AaiUiMsgs.ERROR_GENERIC,
+ "An error occurred getting data from AAI. Error = " + error.getMessage());
+ }
+ });
+
+ }
+
+ while (aaiWorkOnHand.get() != 0) {
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug(AaiUiMsgs.WAIT_FOR_ALL_SELFLINKS_TO_BE_COLLECTED);
+ }
+
+ Thread.sleep(1000);
+ }
+
+ aaiWorkOnHand.set(selflinks.size());
+ allWorkEnumerated = true;
+ syncEntityTypes();
+
+ while (!isSyncDone()) {
+ performRetrySync();
+ Thread.sleep(1000);
+ }
+
+ /*
+ * Make sure we don't hang on to retries that failed which could cause issues during future
+ * syncs
+ */
+ retryLimitTracker.clear();
+
+ } catch (Exception exc) {
+ // TODO -> LOG, waht should be logged here?
+ }
+
+ return OperationState.OK;
+ }
+
+ /* (non-Javadoc)
+ * @see org.openecomp.sparky.synchronizer.IndexSynchronizer#doSync()
+ */
+ @Override
+ public OperationState doSync() {
+ this.syncDurationInMs = -1;
+ String txnID = NodeUtils.getRandomTxnId();
+ MdcContext.initialize(txnID, "SearchableEntitySynchronizer", "", "Sync", "");
+
+ resetCounters();
+ this.allWorkEnumerated = false;
+ syncStartedTimeStampInMs = System.currentTimeMillis();
+ collectAllTheWork();
+
+ return OperationState.OK;
+ }
+
+ /**
+ * Process entity type self links.
+ *
+ * @param operationResult the operation result
+ */
+ private void processEntityTypeSelfLinks(OperationResult operationResult) {
+
+ JsonNode rootNode = null;
+
+ final String jsonResult = operationResult.getResult();
+
+ if (jsonResult != null && jsonResult.length() > 0 && operationResult.wasSuccessful()) {
+
+ try {
+ rootNode = mapper.readTree(jsonResult);
+ } catch (IOException exc) {
+ String message =
+ "Could not deserialize JSON (representing operation result) as node tree. " +
+ "Operation result = " + jsonResult + ". " + exc.getLocalizedMessage();
+ LOG.error(AaiUiMsgs.JSON_PROCESSING_ERROR, message);
+ }
+
+ JsonNode resultData = rootNode.get("result-data");
+ ArrayNode resultDataArrayNode = null;
+
+ if (resultData.isArray()) {
+ resultDataArrayNode = (ArrayNode) resultData;
+
+ Iterator<JsonNode> elementIterator = resultDataArrayNode.elements();
+ JsonNode element = null;
+
+ while (elementIterator.hasNext()) {
+ element = elementIterator.next();
+
+ final String resourceType = NodeUtils.getNodeFieldAsText(element, "resource-type");
+ final String resourceLink = NodeUtils.getNodeFieldAsText(element, "resource-link");
+
+ SearchableOxmEntityDescriptor descriptor = null;
+
+ if (resourceType != null && resourceLink != null) {
+
+ descriptor = searchableEntityLookup.getSearchableEntityDescriptors().get(resourceType);
+
+ if (descriptor == null) {
+ LOG.error(AaiUiMsgs.MISSING_ENTITY_DESCRIPTOR, resourceType);
+ // go to next element in iterator
+ continue;
+ }
+
+ if (descriptor.hasSearchableAttributes()) {
+ selflinks.add(new SelfLinkDescriptor(resourceLink, SynchronizerConstants.NODES_ONLY_MODIFIER, resourceType));
+ }
+
+ }
+ }
+ }
+ }
+
+ }
+
+ /**
+ * Sync entity types.
+ */
+ private void syncEntityTypes() {
+
+ while (selflinks.peek() != null) {
+
+ SelfLinkDescriptor linkDescriptor = selflinks.poll();
+ aaiWorkOnHand.decrementAndGet();
+
+ OxmEntityDescriptor descriptor = null;
+
+ if (linkDescriptor.getSelfLink() != null && linkDescriptor.getEntityType() != null) {
+
+ descriptor = oxmEntityLookup.getEntityDescriptors().get(linkDescriptor.getEntityType());
+
+ if (descriptor == null) {
+ LOG.error(AaiUiMsgs.MISSING_ENTITY_DESCRIPTOR, linkDescriptor.getEntityType());
+ // go to next element in iterator
+ continue;
+ }
+
+ NetworkTransaction txn = new NetworkTransaction();
+ txn.setDescriptor(descriptor);
+ txn.setLink(linkDescriptor.getSelfLink());
+ txn.setOperationType(HttpMethod.GET);
+ txn.setEntityType(linkDescriptor.getEntityType());
+
+ aaiWorkOnHand.incrementAndGet();
+
+ supplyAsync(new PerformActiveInventoryRetrieval(txn, aaiAdapter), aaiExecutor)
+ .whenComplete((result, error) -> {
+
+ aaiWorkOnHand.decrementAndGet();
+
+ if (error != null) {
+ LOG.error(AaiUiMsgs.AAI_RETRIEVAL_FAILED_GENERIC, error.getLocalizedMessage());
+ } else {
+ if (result == null) {
+ LOG.error(AaiUiMsgs.AAI_RETRIEVAL_FAILED_FOR_SELF_LINK,
+ linkDescriptor.getSelfLink());
+ } else {
+ updateActiveInventoryCounters(result);
+ fetchDocumentForUpsert(result);
+ }
+ }
+ });
+ }
+
+ }
+
+ }
+
+ /**
+ * Perform document upsert.
+ *
+ * @param esGetTxn the es get txn
+ * @param se the se
+ */
+ protected void performDocumentUpsert(NetworkTransaction esGetTxn, SearchableEntity se) {
+ /**
+ * <p>
+ * <ul>
+ * As part of the response processing we need to do the following:
+ * <li>1. Extract the version (if present), it will be the ETAG when we use the
+ * Search-Abstraction-Service
+ * <li>2. Spawn next task which is to do the PUT operation into elastic with or with the version
+ * tag
+ * <li>a) if version is null or RC=404, then standard put, no _update with version tag
+ * <li>b) if version != null, do PUT with _update?version= versionNumber in the URI to elastic
+ * </ul>
+ * </p>
+ */
+ String link = null;
+ try {
+ link = elasticSearchAdapter.buildElasticSearchGetDocUrl(getIndexName(), se.getId());
+ } catch (Exception exc) {
+ LOG.error(AaiUiMsgs.ES_LINK_UPSERT, exc.getLocalizedMessage());
+ return;
+ }
+
+ String versionNumber = null;
+ boolean wasEntryDiscovered = false;
+ if (esGetTxn.getOperationResult().getResultCode() == 404) {
+ LOG.info(AaiUiMsgs.ES_SIMPLE_PUT, se.getEntityPrimaryKeyValue());
+ } else if (esGetTxn.getOperationResult().getResultCode() == 200) {
+ wasEntryDiscovered = true;
+ try {
+ versionNumber = NodeUtils.extractFieldValueFromObject(
+ NodeUtils.convertJsonStrToJsonNode(esGetTxn.getOperationResult().getResult()),
+ "_version");
+ } catch (IOException exc) {
+ String message =
+ "Error extracting version number from response, aborting searchable entity sync of "
+ + se.getEntityPrimaryKeyValue() + ". Error - " + exc.getLocalizedMessage();
+ LOG.error(AaiUiMsgs.ERROR_EXTRACTING_FROM_RESPONSE, message);
+ return;
+ }
+ } else {
+ /*
+ * Not being a 200 does not mean a failure. eg 201 is returned for created. TODO -> Should we
+ * return.
+ */
+ LOG.error(AaiUiMsgs.ES_OPERATION_RETURN_CODE,
+ String.valueOf(esGetTxn.getOperationResult().getResultCode()));
+ return;
+ }
+
+ try {
+ String jsonPayload = null;
+ if (wasEntryDiscovered) {
+ try {
+ ArrayList<JsonNode> sourceObject = new ArrayList<JsonNode>();
+ NodeUtils.extractObjectsByKey(
+ NodeUtils.convertJsonStrToJsonNode(esGetTxn.getOperationResult().getResult()),
+ "_source", sourceObject);
+
+ if (!sourceObject.isEmpty()) {
+ String responseSource = NodeUtils.convertObjectToJson(sourceObject.get(0), false);
+ MergableEntity me = mapper.readValue(responseSource, MergableEntity.class);
+ ObjectReader updater = mapper.readerForUpdating(me);
+ MergableEntity merged = updater.readValue(NodeUtils.convertObjectToJson(se,false));
+ jsonPayload = mapper.writeValueAsString(merged);
+ }
+ } catch (IOException exc) {
+ String message =
+ "Error extracting source value from response, aborting searchable entity sync of "
+ + se.getEntityPrimaryKeyValue() + ". Error - " + exc.getLocalizedMessage();
+ LOG.error(AaiUiMsgs.ERROR_EXTRACTING_FROM_RESPONSE, message);
+ return;
+ }
+ } else {
+ jsonPayload = se.getAsJson();
+ }
+
+ if (wasEntryDiscovered) {
+ if (versionNumber != null && jsonPayload != null) {
+
+ String requestPayload = elasticSearchAdapter.buildBulkImportOperationRequest(getIndexName(),
+ "default", se.getId(), versionNumber, jsonPayload);
+
+ NetworkTransaction transactionTracker = new NetworkTransaction();
+ transactionTracker.setEntityType(esGetTxn.getEntityType());
+ transactionTracker.setDescriptor(esGetTxn.getDescriptor());
+ transactionTracker.setOperationType(HttpMethod.PUT);
+
+ esWorkOnHand.incrementAndGet();
+ supplyAsync(new PerformElasticSearchUpdate(elasticSearchAdapter.getBulkUrl(),
+ requestPayload, elasticSearchAdapter, transactionTracker), esPutExecutor)
+ .whenComplete((result, error) -> {
+
+ esWorkOnHand.decrementAndGet();
+
+ if (error != null) {
+ String message = "Searchable entity sync UPDATE PUT error - "
+ + error.getLocalizedMessage();
+ LOG.error(AaiUiMsgs.ES_SEARCHABLE_ENTITY_SYNC_ERROR, message);
+ } else {
+ updateElasticSearchCounters(result);
+ processStoreDocumentResult(result, esGetTxn, se);
+ }
+ });
+ }
+
+ } else {
+
+ if (link != null && jsonPayload != null) {
+
+ NetworkTransaction updateElasticTxn = new NetworkTransaction();
+ updateElasticTxn.setLink(link);
+ updateElasticTxn.setEntityType(esGetTxn.getEntityType());
+ updateElasticTxn.setDescriptor(esGetTxn.getDescriptor());
+ updateElasticTxn.setOperationType(HttpMethod.PUT);
+
+ esWorkOnHand.incrementAndGet();
+ supplyAsync(new PerformElasticSearchPut(jsonPayload, updateElasticTxn, elasticSearchAdapter),
+ esPutExecutor).whenComplete((result, error) -> {
+
+ esWorkOnHand.decrementAndGet();
+
+ if (error != null) {
+ String message =
+ "Searchable entity sync UPDATE PUT error - " + error.getLocalizedMessage();
+ LOG.error(AaiUiMsgs.ES_SEARCHABLE_ENTITY_SYNC_ERROR, message);
+ } else {
+ updateElasticSearchCounters(result);
+ processStoreDocumentResult(result, esGetTxn, se);
+ }
+ });
+ }
+ }
+ } catch (Exception exc) {
+ String message = "Exception caught during searchable entity sync PUT operation. Message - "
+ + exc.getLocalizedMessage();
+ LOG.error(AaiUiMsgs.ES_SEARCHABLE_ENTITY_SYNC_ERROR, message);
+ }
+ }
+
+ /**
+ * Populate searchable entity document.
+ *
+ * @param doc the doc
+ * @param result the result
+ * @param resultDescriptor the result descriptor
+ * @throws JsonProcessingException the json processing exception
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ protected void populateSearchableEntityDocument(SearchableEntity doc, String result,
+ OxmEntityDescriptor resultDescriptor) throws JsonProcessingException, IOException {
+
+ doc.setEntityType(resultDescriptor.getEntityName());
+
+ JsonNode entityNode = mapper.readTree(result);
+
+ List<String> primaryKeyValues = new ArrayList<String>();
+ String pkeyValue = null;
+
+ SearchableOxmEntityDescriptor searchableDescriptor = searchableEntityLookup.getSearchableEntityDescriptors().get(resultDescriptor.getEntityName());
+
+ for (String keyName : searchableDescriptor.getPrimaryKeyAttributeNames()) {
+ pkeyValue = NodeUtils.getNodeFieldAsText(entityNode, keyName);
+ if (pkeyValue != null) {
+ primaryKeyValues.add(pkeyValue);
+ } else {
+ String message = "populateSearchableEntityDocument(), pKeyValue is null for entityType = "
+ + resultDescriptor.getEntityName();
+ LOG.warn(AaiUiMsgs.WARN_GENERIC, message);
+ }
+ }
+
+ final String primaryCompositeKeyValue = NodeUtils.concatArray(primaryKeyValues, "/");
+ doc.setEntityPrimaryKeyValue(primaryCompositeKeyValue);
+
+ final List<String> searchTagFields = searchableDescriptor.getSearchableAttributes();
+
+ /*
+ * Based on configuration, use the configured field names for this entity-Type to build a
+ * multi-value collection of search tags for elastic search entity search criteria.
+ */
+ for (String searchTagField : searchTagFields) {
+ String searchTagValue = NodeUtils.getNodeFieldAsText(entityNode, searchTagField);
+ if (searchTagValue != null && !searchTagValue.isEmpty()) {
+ doc.addSearchTagWithKey(searchTagValue, searchTagField);
+ }
+ }
+ }
+
+ /**
+ * Fetch document for upsert.
+ *
+ * @param txn the txn
+ */
+ private void fetchDocumentForUpsert(NetworkTransaction txn) {
+ if (!txn.getOperationResult().wasSuccessful()) {
+ String message = "Self link failure. Result - " + txn.getOperationResult().getResult();
+ LOG.error(AaiUiMsgs.ERROR_GENERIC, message);
+ return;
+ }
+
+ SearchableOxmEntityDescriptor searchableDescriptor = searchableEntityLookup
+ .getSearchableEntityDescriptors().get(txn.getDescriptor().getEntityName());
+
+ try {
+ if (searchableDescriptor.hasSearchableAttributes()) {
+
+ final String jsonResult = txn.getOperationResult().getResult();
+ if (jsonResult != null && jsonResult.length() > 0) {
+
+ SearchableEntity se = new SearchableEntity();
+ se.setLink(ActiveInventoryAdapter.extractResourcePath(txn.getLink()));
+ populateSearchableEntityDocument(se, jsonResult, txn.getDescriptor());
+ se.deriveFields();
+
+ String link = null;
+ try {
+ link = elasticSearchAdapter.buildElasticSearchGetDocUrl(getIndexName(), se.getId());
+ } catch (Exception exc) {
+ LOG.error(AaiUiMsgs.ES_FAILED_TO_CONSTRUCT_QUERY, exc.getLocalizedMessage());
+ }
+
+ if (link != null) {
+ NetworkTransaction n2 = new NetworkTransaction();
+ n2.setLink(link);
+ n2.setEntityType(txn.getEntityType());
+ n2.setDescriptor(txn.getDescriptor());
+ n2.setOperationType(HttpMethod.GET);
+
+ esWorkOnHand.incrementAndGet();
+
+ supplyAsync(new PerformElasticSearchRetrieval(n2, elasticSearchAdapter), esExecutor)
+ .whenComplete((result, error) -> {
+
+ esWorkOnHand.decrementAndGet();
+
+ if (error != null) {
+ LOG.error(AaiUiMsgs.ES_RETRIEVAL_FAILED, error.getLocalizedMessage());
+ } else {
+ updateElasticSearchCounters(result);
+ performDocumentUpsert(result, se);
+ }
+ });
+ }
+ }
+
+ }
+ } catch (JsonProcessingException exc) {
+ // TODO -> LOG, waht should be logged here?
+ } catch (IOException exc) {
+ // TODO -> LOG, waht should be logged here?
+ }
+ }
+
+ /**
+ * Process store document result.
+ *
+ * @param esPutResult the es put result
+ * @param esGetResult the es get result
+ * @param se the se
+ */
+ private void processStoreDocumentResult(NetworkTransaction esPutResult,
+ NetworkTransaction esGetResult, SearchableEntity se) {
+
+ OperationResult or = esPutResult.getOperationResult();
+
+ if (!or.wasSuccessful()) {
+ if (or.getResultCode() == VERSION_CONFLICT_EXCEPTION_CODE) {
+
+ if (shouldAllowRetry(se.getId())) {
+ esWorkOnHand.incrementAndGet();
+
+ RetrySearchableEntitySyncContainer rsc =
+ new RetrySearchableEntitySyncContainer(esGetResult, se);
+ retryQueue.push(rsc);
+
+ String message = "Store document failed during searchable entity synchronization"
+ + " due to version conflict. Entity will be re-synced.";
+ LOG.warn(AaiUiMsgs.ES_SEARCHABLE_ENTITY_SYNC_ERROR, message);
+ }
+ } else {
+ String message =
+ "Store document failed during searchable entity synchronization with result code "
+ + or.getResultCode() + " and result message " + or.getResult();
+ LOG.error(AaiUiMsgs.ES_SEARCHABLE_ENTITY_SYNC_ERROR, message);
+ }
+ }
+ }
+
+ /**
+ * Perform retry sync.
+ */
+ private void performRetrySync() {
+ while (retryQueue.peek() != null) {
+
+ RetrySearchableEntitySyncContainer rsc = retryQueue.poll();
+ if (rsc != null) {
+
+ SearchableEntity se = rsc.getSearchableEntity();
+ NetworkTransaction txn = rsc.getNetworkTransaction();
+
+ String link = null;
+ try {
+ /*
+ * In this retry flow the se object has already derived its fields
+ */
+ link = elasticSearchAdapter.buildElasticSearchGetDocUrl(getIndexName(), se.getId());
+ } catch (Exception exc) {
+ LOG.error(AaiUiMsgs.ES_FAILED_TO_CONSTRUCT_URI, exc.getLocalizedMessage());
+ }
+
+ if (link != null) {
+ NetworkTransaction retryTransaction = new NetworkTransaction();
+ retryTransaction.setLink(link);
+ retryTransaction.setEntityType(txn.getEntityType());
+ retryTransaction.setDescriptor(txn.getDescriptor());
+ retryTransaction.setOperationType(HttpMethod.GET);
+
+ /*
+ * IMPORTANT - DO NOT incrementAndGet the esWorkOnHand as this is a retry flow! We already
+ * called incrementAndGet when queuing the failed PUT!
+ */
+
+ supplyAsync(new PerformElasticSearchRetrieval(retryTransaction, elasticSearchAdapter),
+ esExecutor).whenComplete((result, error) -> {
+
+ esWorkOnHand.decrementAndGet();
+
+ if (error != null) {
+ LOG.error(AaiUiMsgs.ES_RETRIEVAL_FAILED_RESYNC, error.getLocalizedMessage());
+ } else {
+ updateElasticSearchCounters(result);
+ performDocumentUpsert(result, se);
+ }
+ });
+ }
+
+ }
+ }
+ }
+
+ /**
+ * Should allow retry.
+ *
+ * @param id the id
+ * @return true, if successful
+ */
+ private boolean shouldAllowRetry(String id) {
+ boolean isRetryAllowed = true;
+ if (retryLimitTracker.get(id) != null) {
+ Integer currentCount = retryLimitTracker.get(id);
+ if (currentCount.intValue() >= RETRY_COUNT_PER_ENTITY_LIMIT.intValue()) {
+ isRetryAllowed = false;
+ String message = "Searchable entity re-sync limit reached for " + id
+ + ", re-sync will no longer be attempted for this entity";
+ LOG.error(AaiUiMsgs.ES_SEARCHABLE_ENTITY_SYNC_ERROR, message);
+ } else {
+ Integer newCount = new Integer(currentCount.intValue() + 1);
+ retryLimitTracker.put(id, newCount);
+ }
+ } else {
+ Integer firstRetryCount = new Integer(1);
+ retryLimitTracker.put(id, firstRetryCount);
+ }
+
+ return isRetryAllowed;
+ }
+
+ @Override
+ public SynchronizerState getState() {
+ if (!isSyncDone()) {
+ return SynchronizerState.PERFORMING_SYNCHRONIZATION;
+ }
+
+ return SynchronizerState.IDLE;
+
+ }
+
+ /* (non-Javadoc)
+ * @see org.openecomp.sparky.synchronizer.IndexSynchronizer#getStatReport(boolean)
+ */
+ @Override
+ public String getStatReport(boolean showFinalReport) {
+ syncDurationInMs = System.currentTimeMillis() - syncStartedTimeStampInMs;
+ return this.getStatReport(syncDurationInMs, showFinalReport);
+ }
+
+ /* (non-Javadoc)
+ * @see org.openecomp.sparky.synchronizer.IndexSynchronizer#shutdown()
+ */
+ @Override
+ public void shutdown() {
+ this.shutdownExecutors();
+ }
+
+ @Override
+ protected boolean isSyncDone() {
+ int totalWorkOnHand = aaiWorkOnHand.get() + esWorkOnHand.get();
+
+ if (totalWorkOnHand > 0 || !allWorkEnumerated) {
+ return false;
+ }
+
+ return true;
+ }
+
+}
diff --git a/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewinspect/sync/ViewInspectSyncController.java b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewinspect/sync/ViewInspectSyncController.java
new file mode 100644
index 0000000..bd15e1f
--- /dev/null
+++ b/sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewinspect/sync/ViewInspectSyncController.java
@@ -0,0 +1,122 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.viewinspect.sync;
+
+import org.onap.aai.sparky.config.oxm.CrossEntityReferenceLookup;
+import org.onap.aai.sparky.config.oxm.OxmEntityLookup;
+import org.onap.aai.sparky.config.oxm.SearchableEntityLookup;
+import org.onap.aai.sparky.crossentityreference.sync.CrossEntityReferenceSynchronizer;
+import org.onap.aai.sparky.dal.ActiveInventoryAdapter;
+import org.onap.aai.sparky.dal.ElasticSearchAdapter;
+import org.onap.aai.sparky.sync.ElasticSearchIndexCleaner;
+import org.onap.aai.sparky.sync.ElasticSearchSchemaFactory;
+import org.onap.aai.sparky.sync.IndexCleaner;
+import org.onap.aai.sparky.sync.IndexIntegrityValidator;
+import org.onap.aai.sparky.sync.SyncControllerImpl;
+import org.onap.aai.sparky.sync.SyncControllerRegistrar;
+import org.onap.aai.sparky.sync.SyncControllerRegistry;
+import org.onap.aai.sparky.sync.config.ElasticSearchEndpointConfig;
+import org.onap.aai.sparky.sync.config.ElasticSearchSchemaConfig;
+import org.onap.aai.sparky.sync.config.NetworkStatisticsConfig;
+import org.onap.aai.sparky.sync.config.SyncControllerConfig;
+
+public class ViewInspectSyncController extends SyncControllerImpl
+ implements SyncControllerRegistrar {
+
+ private SyncControllerRegistry syncControllerRegistry;
+ private ActiveInventoryAdapter aaiAdapter;
+ private ElasticSearchAdapter esAdapter;
+ private ElasticSearchSchemaConfig schemaConfig;
+ private ElasticSearchEndpointConfig endpointConfig;
+
+ public ViewInspectSyncController(SyncControllerConfig syncControllerConfig,
+ ActiveInventoryAdapter aaiAdapter, ElasticSearchAdapter esAdapter,
+ ElasticSearchSchemaConfig schemaConfig, ElasticSearchEndpointConfig endpointConfig,
+ NetworkStatisticsConfig aaiStatConfig, NetworkStatisticsConfig esStatConfig,
+ CrossEntityReferenceLookup crossEntityReferenceLookup, OxmEntityLookup oxmEntityLookup,
+ SearchableEntityLookup searchableEntityLookup,
+ ElasticSearchSchemaFactory elasticSearchSchemaFactory) throws Exception {
+ super(syncControllerConfig);
+
+
+ // final String controllerName = "View and Inspect Entity Synchronizer";
+
+ this.aaiAdapter = aaiAdapter;
+ this.esAdapter = esAdapter;
+ this.schemaConfig = schemaConfig;
+ this.endpointConfig = endpointConfig;
+ IndexIntegrityValidator indexValidator = new IndexIntegrityValidator(esAdapter, schemaConfig,
+ endpointConfig, elasticSearchSchemaFactory.getIndexSchema(schemaConfig));
+
+ registerIndexValidator(indexValidator);
+
+
+ ViewInspectEntitySynchronizer ses = new ViewInspectEntitySynchronizer(schemaConfig,
+ syncControllerConfig.getNumInternalSyncWorkers(),
+ syncControllerConfig.getNumSyncActiveInventoryWorkers(),
+ syncControllerConfig.getNumSyncElasticWorkers(), aaiStatConfig, esStatConfig,
+ oxmEntityLookup, searchableEntityLookup);
+
+ ses.setAaiAdapter(aaiAdapter);
+ ses.setElasticSearchAdapter(esAdapter);
+
+ registerEntitySynchronizer(ses);
+
+ CrossEntityReferenceSynchronizer cers = new CrossEntityReferenceSynchronizer(schemaConfig,
+ syncControllerConfig.getNumInternalSyncWorkers(),
+ syncControllerConfig.getNumSyncActiveInventoryWorkers(),
+ syncControllerConfig.getNumSyncElasticWorkers(),aaiStatConfig,esStatConfig,
+ crossEntityReferenceLookup, oxmEntityLookup, searchableEntityLookup);
+
+ cers.setAaiAdapter(aaiAdapter);
+ cers.setElasticSearchAdapter(esAdapter);
+
+ registerEntitySynchronizer(cers);
+
+ IndexCleaner indexCleaner =
+ new ElasticSearchIndexCleaner(esAdapter, endpointConfig, schemaConfig);
+
+ registerIndexCleaner(indexCleaner);
+
+ }
+
+ public SyncControllerRegistry getSyncControllerRegistry() {
+ return syncControllerRegistry;
+ }
+
+ public void setSyncControllerRegistry(SyncControllerRegistry syncControllerRegistry) {
+ this.syncControllerRegistry = syncControllerRegistry;
+ }
+
+ @Override
+ public void registerController() {
+ if ( syncControllerRegistry != null ) {
+ if ( syncControllerConfig.isEnabled()) {
+ syncControllerRegistry.registerSyncController(this);
+ }
+ }
+
+ }
+}
diff --git a/sparkybe-onap-service/src/main/resources/logging/AAIUIMsgs.properties b/sparkybe-onap-service/src/main/resources/logging/AAIUIMsgs.properties
new file mode 100644
index 0000000..1843604
--- /dev/null
+++ b/sparkybe-onap-service/src/main/resources/logging/AAIUIMsgs.properties
@@ -0,0 +1,901 @@
+#Resource key=Error Code|Message text|Resolution text |Description text
+#######
+#Newlines can be utilized to add some clarity ensuring continuing line
+#has at least one leading space
+#ResourceKey=\
+# ERR0000E\
+# Sample error msg txt\
+# Sample resolution msg\
+# Sample description txt
+#
+######
+#Error code classification category
+#000 Info/Debug
+#100 Permission errors
+#200 Availability errors/Timeouts
+#300 Data errors
+#400 Schema Interface type/validation errors
+#500 Business process errors
+#900 Unknown errors
+#
+########################################################################
+
+#-------------------- 000 Series Info/Warning/Debug --------------------#
+
+DANGLING_NODE_WARNING=\
+ AAIUI0001W|\
+ Dangling node issue detected: {0}
+
+FILE_READ_IN_PROGRESS=\
+ AAIUI0002W|\
+ Attempting getFileContents() for file: {0}
+
+VISUALIZATION_GRAPH_OUTPUT=\
+ AAIUI0003I|\
+ Generated graph output has {0} node(s) and {1} link(s)
+
+NODE_INTEGRITY_ALREADY_PROCESSED=\
+ AAIUI0004I|\
+ Node integrity for nodeId, {0}, has already been processed
+
+SKIPPING_PROCESS_NODE_INTEGRITY=\
+ AAIUI0005I|\
+ Skipping processNodeIntegrity() for node, {0}, because node integrity overlay is disabled
+
+MAX_EVALUATION_ATTEMPTS_EXCEEDED=\
+ AAIUI0006I|\
+ Evaluate node depths exceeded max evaluation attempts
+
+SYNC_DURATION=\
+ AAIUI0007I|\
+ {0}
+
+SYNC_TO_BEGIN=\
+ AAIUI0008I|\
+ [{0}] next synchronization operation will begin at {1}
+
+WILL_RETRIEVE_TXN=\
+ AAIUI0009I|\
+ About to retrieve the txn {0}
+
+ALL_TRANSACTIONS_RESOLVED=\
+ AAIUI00010I|\
+ All transactions are resolved, total resolve time was, {0}, total links retrieved, {1}, with an opTime of, {2} ms
+
+OUTSTANDING_WORK_PENDING_NODES=\
+ AAIUI00011I|\
+ Method hasOutstandingWork: Number of pending nodes, {0}
+
+OPERATION_TIME=\
+ AAIUI00012I|\
+ Operation: {0} - Time taken: {1}
+
+NO_RELATIONSHIP_DISCOVERED=\
+ AAIUI00013I|\
+ No relationships discovered for entity: {0}
+
+ACTIVE_INV_NODE_CHANGE_DEPTH=\
+ AAIUI00014I|\
+ AIN - {0} - changing depth from {1} to {2}
+
+ACTIVE_INV_NODE_CHANGE_STATE=\
+ AAIUI00015I|\
+ [{0}], State change from {1} to {2}, caused by action {3}
+
+ACTIVE_INV_NODE_CHANGE_STATE_NO_NODE_ID=\
+ AAIUI00016I|\
+ Node state change from {0} => {1} caused by action = {2}
+
+INITIALIZE_OXM_MODEL_LOADER=\
+ AAIUI00017I|\
+ Initializing OXM Model Loader
+
+OXM_READ_ERROR_NONVERBOSE=\
+ AAIUI00018I|\
+ Unable to Read OXM File
+
+OXM_LOAD_SUCCESS=\
+ AAIUI00019I|\
+ OXM file version v{0} loaded successfully
+
+OXM_PARSE_ERROR_NONVERBOSE=\
+ AAIUI00020I|\
+ Unable to Parse OXM File
+
+ETAG_RETRY_SEQ=\
+ AAIUI00021D|\
+ doEdgeTagQueryWithRetries: attempt number = {0}
+
+QUERY_AAI_RETRY_SEQ=\
+ AAIUI00022D|\
+ queryActiveInventory: {0} attempt number = {1}
+
+QUERY_AAI_RETRY_DONE_SEQ=\
+ AAIUI00023D|\
+ queryActiveInventory: {0} after = {1} attempt(s).
+
+QUERY_AAI_RETRY_MAXED_OUT=\
+ AAIUI00024I|\
+ Failed to queryActiveInventory: {0} after max attempt(s).
+
+DATA_CACHE_SUCCESS=\
+ AAIUI00025D|\
+ InMemoryEntityCache cached data with key = {0}
+
+ATTRIBUTES_UPDATE_METHOD_CALLED=\
+ AAIUI00026I|\
+ updateObjectAttribute called for : {0} ATTUID : {1} Attributes : {2}
+
+ATTRIBUTES_HANDLING_EDIT=\
+ AAIUI00027I|\
+ Handling Edit Attributes: requestUri = {0} Body : {1}
+
+RESTFULL_OP_COMPLETE=\
+ AAIUI00028I|\
+ doRestfulOperation() operation for {0} execution time = {1} ms for link = {2}, ResultCode = {3}
+
+DI_MS_TIME_FOR_DATA_FETCH=\
+ AAIUI00029I|\
+ TabularService data fetch time: {0} ms. Status: {1}.
+
+COOKIE_FOUND=\
+ AAIUI00030I|\
+ attESHr cookie found in the request <{0}>
+
+INDEX_ALREADY_EXISTS=\
+ AAIUI00031I|\
+ [{0}] - Index Already Exists
+
+INDEX_RECREATED=\
+ AAIUI00032I|\
+ [{0}] - Index successfully re-created
+
+INDEX_EXISTS=\
+ AAIUI00033I|\
+ [{0}] - Index exists
+
+INDEX_INTEGRITY_CHECK_FAILED=\
+ AAIUI00034W|\
+ [{0}] - Index Integrity check failed, a failure occurred re-creating index. Aborting sync operation. Index Creation error = {1}
+
+INDEX_NOT_EXIST=\
+ AAIUI00035I|\
+ [{0}] - Index Does not Exist
+
+SYNC_INTERNAL_STATE_CHANGED=\
+ AAIUI00036I|\
+ [{0}] Changing from state = {1} -> {2} caused by {3}
+
+SYNC_START_TIME=\
+ AAIUI00037I|\
+ Scheduled synchronization will happen on default time '05:00:00 UTC'. Check value for 'synchronizer.syncTask.startTimestamp' parameter
+
+SKIP_PERIODIC_SYNC_AS_SYNC_DIDNT_FINISH=\
+ AAIUI00038I|\
+ Synchronization did not finish yet. Skipping periodic synchronization at {0}
+
+SEARCH_ENGINE_SYNC_STARTED=\
+ AAIUI00039I|\
+ Search Engine synchronization starting at {0}
+
+FAILED_TO_RESTORE_TXN_FILE_MISSING=\
+ AAIUI00040D|\
+ Failed to restore txn because {0} does not exist.
+
+ERROR_BUILDING_RESPONSE_FOR_TABLE_QUERY=\
+ AAIUI00041W|\
+ Caught an exception while building a search response for table query. Error: {0}
+
+ERROR_BUILDING_SEARCH_RESPONSE=\
+ AAIUI00042W|\
+ Caught an exception while building a search response. Error: {0}
+
+WAIT_FOR_ALL_SELFLINKS_TO_BE_COLLECTED=\
+ AAIUI00043D|\
+ Waiting for all self-link lists to be collected
+
+ES_SIMPLE_PUT=\
+ AAIUI00044I|\
+ Element {0} not discovered for merge. Simple put will be used.
+
+ES_OPERATION_RETURN_CODE=\
+ AAIUI00045I|\
+ Operation did not return 200, instead returned code : {0}
+
+ES_CROSS_REF_SYNC_VERSION_CONFLICT=\
+ AAIUI00046W|\
+ Store document failed during cross reference entity synchronization due to version conflict. Entity will be resynced.
+
+ES_PKEYVALUE_NULL=\
+ AAIUI00047W|\
+ getPopulatedDocument() pKeyValue is null for entityType : {1}
+
+ES_SYNC_CLEAN_UP=\
+ AAIUI00048I|\
+ ElasticSearchEntityPurger.performCleanup() for indexName : {0}
+
+ES_SYNC_CLEAN_UP_SIZE=\
+ AAIUI00049I|\
+ [ {0} ], performCleanup(), Pre-Sync Collection Size : {1} and Post-Sync Collection Size : {2}
+
+ES_SYNC_SELECTIVE_DELETE=\
+ AAIUI00050I|\
+ About to perform selective delete with indexName={0}, indexType {1}, numrecords= {2}
+
+ES_BULK_DELETE=\
+ AAIUI00051I|\
+ [ {0} ] - Sending bulk delete request with a total of {1} records
+
+COLLECT_TIME_WITH_SUCCESS=\
+ AAIUI00052I|\
+ retrieve {0}AllDocumentIdentifiers operation completed in {0} ms successfully
+
+SYNC_NUMBER_REQ_FETCHES=\
+ AAIUI00053D|\
+ numRequiredFetches : {0}
+
+SYNC_NUMBER_REQ_FETCHES=\
+ AAIUI00054D|\
+ Total fetched {0} of total available {1}
+
+COLLECT_TOTAL=\
+ AAIUI00055I|\
+ retrieve {0}: Total returned : {1}
+
+COLLECT_TOTAL_TIME=\
+ AAIUI00056I|\
+ retrieve {0}, took = {0}
+
+ES_SCROLL_CONTEXT_ERROR=\
+ AAIUI00057W|\
+ Failed to get results from elastic search scroll context. Error cause : {0}
+
+ES_BULK_DELETE_SKIP=\
+ AAIUI00058I|\
+ Skipping bulkDelete(); operation because docs to delete list is empty
+
+ES_BULK_DELETE_START=\
+ AAIUI00059I|\
+ bulkDelete: about to delete {0} docs
+
+GEO_SYNC_IGNORING_ENTITY=\
+ AAIUI00060I|\
+ GeoSynchronizer ignoring an entity of type {0} because of missing / invalid long/lat coordinates. Entity : {1}
+
+HISTORICAL_ENTITY_COUNT_SUMMARIZER_STARTING=\
+ AAIUI00061I|\
+ Historical Entity Count Summarizer starting at {0}
+
+HISTORICAL_SYNC_PENDING=\
+ AAIUI00062I|\
+ History Entity Summarizer is already running, skipping request for another doSync
+
+HISTORICAL_SYNC_TO_BEGIN=\
+ AAIUI00063I|\
+ Next historical entity summary will begin at {0}
+
+HISTORICAL_SYNC_DURATION=\
+ AAIUI00064I|\
+ {0} synchronization took {1} ms.
+
+DEBUG_GENERIC=\
+ AAIUI00065D|\
+ {0}
+
+INFO_GENERIC=\
+ AAIUI00066I|\
+ {0}
+
+WARN_GENERIC=\
+ AAIUI00067W|\
+ {0}
+
+VALID_REDIRECT_URL=\
+ AAIUI00070D|\
+ Redirecting to login URL: {0}
+
+LOGIN_FILTER_INFO=\
+ AAIUI00071I|\
+ {0}
+
+LOGIN_FILTER_DEBUG=\
+ AAIUI00072D|\
+ {0}
+
+DR_PROCESSING_FAILURE=\
+ AAIUI00073I|\
+ Failure to resolve proxied request. Response code: {0} for proxy payload: {1}
+
+DR_PROCESSING_TIME=\
+ AAIUI00074I|\
+ Time taken to resolve proxied request: {0} ms
+
+DR_PROXY_FROM_TO=\
+ AAIUI00075I|\
+ Proxying request from url: {0} to: {1}
+
+
+#-------------------- 300 Series Errors --------------------#
+
+ETAG_WAIT_INTERRUPTION=\
+ AAIUI3001E|\
+ doEdgeTagQueryWithRetries: interrupted while sleeping with cause = {0}
+
+QUERY_AAI_WAIT_INTERRUPTION=\
+ AAIUI3002E|\
+ queryActiveInventoryWithRetries: interrupted while sleeping with cause = {0}
+
+EXECUTOR_SERV_EXCEPTION=\
+ AAIUI3003E|\
+ Thread: {0}. The following exception has occurred: {1}
+
+ATTRIBUTES_NOT_UPDATED_EXCEPTION=\
+ AAIUI3004E|\
+ Attributes not updated. {0}
+
+ATTRIBUTES_NOT_UPDATED_MESSAGE=\
+ AAIUI3005E|\
+ {0}
+
+SYNC_NOT_VALID_STATE_DURING_REQUEST=\
+ AAIUI3006E|\
+ Sync requested while synchronizer not in valid state. Current internal state: {0}
+
+SYNC_SKIPPED_SYNCCONTROLLER_NOT_INITIALIZED=\
+ AAIUI3007E|\
+ SyncController has not been initialized. Synchronization skipped
+
+ENTITY_SYNC_FAILED_DESCRIPTOR_NOT_FOUND=\
+ AAIUI3008E|\
+ Entity sync failed because entity descriptor could not be located for entityType = {0}
+
+ENTITY_SYNC_FAILED_DURING_AAI_RESPONSE_CONVERSION=\
+ AAIUI3009E|\
+ Sync Entity Failure caused by error in converting AAI response into an object.
+
+ENTITY_SYNC_FAILED_QUERY_ERROR=\
+ AAIUI30010E|\
+ {0}
+
+ENTITY_SYNC_FAILED_SELFLINK_AMBIGUITY=\
+ AAIUI30011E|\
+ Entity sync failed due to self-link determination ambiguity. Unexpected number of links = {0}
+
+AGGREGATION_KEY_ERROR=\
+ AAIUI30012E|\
+ Failed to derive {0} for aggregation by {1}
+
+INTERRUPTED=\
+ AAIUI30013E|\
+ Interrupted {0} while waiting for elastic search tasks to be processed with error : {1}
+
+JSON_PROCESSING_ERROR=\
+ AAIUI30014E|\
+ Failed to process json with error : {0}
+
+HISTORICAL_COLLECT_ERROR=\
+ AAIUI30015E|\
+ Caught an error while collecting results for historical entity summary. Error : {0}
+
+HISTORICAL_ENTITY_COUNT_SUMMARIZER_NOT_STARTED=\
+ AAIUI30016E|\
+ HistoricalEntityCountSummaryTask has not been initialized. Synchronization skipped
+
+OXM_FAILED_RETRIEVAL=\
+ AAIUI30017E|\
+ Failed to load searchable entities for {0} in OXM file. Synchronizer stopped.
+
+SELF_LINK_GET_NO_RESPONSE=\
+ AAIUI30018E|\
+ AAI did not provide a response for self-link: {0}
+
+ES_BULK_DELETE=\
+ AAIUI30019E|\
+ [ {0} ] - An error occurred while attempting to perform selective delete to elastic search index with an error cause : {1}
+
+COLLECT_TIME_WITH_ERROR=\
+ AAIUI30020E|\
+ retrieve {0} operation completed in {1} ms with some errors
+
+ES_SEARCHABLE_ENTITY_SYNC_ERROR=\
+ AAIUI30021E|\
+ {0}
+
+ES_STORE_FAILURE=\
+ AAIUI30022E|\
+ There was an error storing the document into elastic search. Error : {0}
+
+ES_PRE_SYNC_FAILURE=\
+ AAIUI30023E|\
+ {0} An error occured while collecting the pre-sync object id collection. Error : {1}
+
+ES_CROSS_REF_SYNC_FAILURE=\
+ AAIUI30024E|\
+ Store document failed during cross reference entity synchronization with result code {0} and result message {1}
+
+ES_FAILED_TO_CONSTRUCT_URI=\
+ AAIUI30025E|\
+ Failed to construct an elastic search uri during re-sync, with error : {0}
+
+ES_RETRIEVAL_FAILED_RESYNC=\
+ AAIUI30026E|\
+ Elasticsearch retrieval failed for re-sync. Error : {0}
+
+ES_CROSS_ENTITY_RESYNC_LIMIT=\
+ AAIUI30027E|\
+ Cross entity re-sync limit reached for {0}, re-sync will no longer be attempted for this entity
+
+ES_CROSS_ENTITY_REF_PUT=\
+ AAIUI30028E|\
+ Cross entity reference sync UPDATE PUT error: {0}
+
+ES_ABORT_CROSS_ENTITY_REF_SYNC=\
+ AAIUI30029E|\
+ Error extracting {0} from response, aborting cross entity ref sync of {1}. Error : {2}
+
+MISSING_ENTITY_DESCRIPTOR=\
+ AAIUI30030E
+ Missing entity descriptor for type : {0}
+
+SELF_LINK_GET=\
+ AAIUI30031E|\
+ Failure during self link GET. Error : {0}
+
+SELF_LINK_CROSS_REF_SYNC=\
+ AAIUI30032E|\
+ Self link GET has returned null during cross entity reference sync
+
+ES_FAILED_TO_CONSTRUCT_QUERY=\
+ AAIUI30033E|\
+ Failed to construct an elastic search uri with error : {0}
+
+ES_RETRIEVAL_FAILED=\
+ AAIUI30034E|\
+ Elasticsearch retrieval failed. Error : {0}
+
+ES_LINK_UPSERT=\
+ AAIUI30035E|\
+ Error creating link for upsert. Error : {0}
+
+ERROR_GENERIC=\
+ AAIUI30036E|\
+ {0}
+
+ERROR_PROCESSING_REQUEST=\
+ AAIUI30037E\
+ Failure to process request with error: {1}
+
+ERROR_CSP_CONFIG_FILE=\
+ AAIUI30038E|\
+ Failed to load CSP filter configuration properties
+
+ERROR_SHUTDOWN_EXECUTORS=\
+ AAIUI30039E|\
+ Failure during shutdown of executors. Error : {0}
+
+ERROR_LOADING_OXM=\
+ AAIUI30040E|\
+ Failed to load searchable entities in OXM file. Synchronizer stopped.
+
+ERROR_GETTING_DATA_FROM_AAI=\
+ AAIUI30041E|\
+ An error occurred getting data from AAI. Error : {0}
+
+SOT_FILE_NOT_FOUND=\
+ AAIUI30042E|\
+ Error in reading source-of-truth configuration
+
+INVALID_REQUEST_PARAMS=\
+ AAIUI30043E|\
+ Invalid request parameters
+
+PEGGING_ERROR=\
+ AAIUI30044E|\
+ Pegging UNKNOWN_EXCEPTION due to unexpected exception = {0}
+
+ATTRIBUTES_ERROR_LOADING_MODEL_VERSION=\
+ AAIUI30045E|\
+ Model Version Error. {0} Not Found or not loaded successfully.
+
+INVALID_REQUEST=\
+ AAIUI30046E|\
+ {0}
+
+INVALID_URL_VERBOSE=\
+ AAIUI30047E|\
+ Invalid URL: {0}. Reason: {1}.
+
+DI_DATA_NOT_FOUND_NONVERBOSE=\
+ AAIUI30048E|\
+ No data integrity data found for rowID: {0}.
+
+DI_DATA_NOT_FOUND_VERBOSE=\
+ AAIUI30049E|\
+ No data integrity data found for rowID: {0} after {1} attempts.
+
+OXM_FILE_NOT_FOUND=\
+ AAIUI30050E|\
+ Unable to find any OXM file.
+
+OXM_READ_ERROR_VERBOSE=\
+ AAIUI30051E|\
+ Unable to read OXM file: {0}
+
+ERROR_PARSING_JSON_PAYLOAD_NONVERBOSE=\
+ AAIUI30052E|\
+ Error in parsing JSON payload for {0}
+
+ERROR_PARSING_JSON_PAYLOAD_VERBOSE=\
+ AAIUI30053E|\
+ Error in parsing JSON payload: {0}
+
+ERROR_FETCHING_JSON_VALUE=\
+ AAIUI30054E|\
+ Error in getting value for key: {0}. Data: {1}
+
+OXM_READ_PARSE_VERBOSE=\
+ AAIUI30055E|\
+ Unable to parse OXM file: {0}. The following exception has occurred: {1}
+
+OXM_PROP_DEF_ERR_CROSS_ENTITY_REF=\
+ AAIUI30056E|\
+ Invalid OXM definition of xml-property 'crossEntityReference' for entity : {0} with a value of : {1}
+
+SYNC_INVALID_CONFIG_PARAM=\
+ AAIUI30057E|\
+ {0}
+
+ERROR_PARSING_PARAMS=\
+ AAIUI30058E|\
+ Error parsing parameters. Error: {0}
+
+ERROR_SORTING_VIOLATION_DATA=\
+ AAIUI30059E|\
+ Error in sorting violation data based on key: {0}
+
+CONFIGURATION_ERROR=\
+ AAIUI30060E|\
+ Failed to load {0} configurations
+
+QUERY_AAI_RETRY_FAILURE_WITH_SEQ=\
+ AAIUI30062E|\
+ Failed to queryActiveInventory {0} attempt number = {1}
+
+DISK_CACHE_READ_IO_ERROR=\
+ AAIUI30063E|\
+ Failed to read from disk cache. Exception: {0}
+
+DISK_CREATE_DIR_IO_ERROR=\
+ AAIUI30064E|\
+ Failed to create directory in disk. Exception: {0}
+
+DISK_DATA_WRITE_IO_ERROR=\
+ AAIUI30065E|\
+ Failed to persist data in disk. Exception: {0}
+
+DISK_NAMED_DATA_WRITE_IO_ERROR=\
+ AAIUI30066E|\
+ Failed to persist data for {0} in disk. Exception: {1}
+
+DISK_NAMED_DATA_READ_IO_ERROR=\
+ AAIUI30067E|\
+ Failed to retrieve data for {0} from disk. Exception: {1}
+
+OFFLINE_STORAGE_PATH_ERROR=\
+ AAIUI30068E|\
+ Error in determining offline storage path for link: {0}. Exception: {1}
+
+RESTFULL_OP_ERROR_VERBOSE=\
+ AAIUI30069E|\
+ Error retrieving link: {0} from restful endpoint due to error: {1}
+
+ATTRIBUTES_ERROR_GETTING_AAI_CONFIG_OR_ADAPTER=\
+ AAIUI30070E|\
+ Error in getting AAI configuration or Adaptor: {0}
+
+USER_AUTHORIZATION_FILE_UNAVAILABLE=\
+ AAIUI30071E|\
+ User authorization file unavailable. User {0} cannot be authorized.
+
+COOKIE_NOT_FOUND=\
+ AAIUI30072E|\
+ No cookies found in the request
+
+CONFIG_NOT_FOUND_VERBOSE=\
+ AAIUI30073E|\
+ Error in loading configuration from file: {0}. Cause: {1}
+
+FILE_NOT_FOUND=\
+ AAIUI30074E|\
+ Failed to find file: {0}
+
+ATTRIBUTES_USER_NOT_AUTHORIZED_TO_UPDATE=\
+ AAIUI30075E|\
+ User {0} is not authorized for Attributes update
+
+SELF_LINK_NULL_EMPTY_RESPONSE=\
+ AAIUI30076E|\
+ AIN - Failed to process null or empty pathed self link response
+
+SELF_LINK_RELATIONSHIP_LIST_ERROR=\
+ AAIUI30077E|\
+ AIN - Caught an error processing the self-link relationship-list: {0}
+
+SEARCH_SERVLET_ERROR=\
+ AAIUI30078E|\
+ Search Servlet Error: {0}
+
+SEARCH_RESPONSE_BUILDING_EXCEPTION=\
+ AAIUI30079E|\
+ Caught an exception while building a search response. Error: {0}
+
+SEARCH_TAG_ANNOTATION_ERROR=\
+ AAIUI30080E|\
+ An error occurred annotating search tags. Search tags: {0} Error: {1}
+
+QUERY_FAILED_UNHANDLED_APP_TYPE=\
+ AAIUI30081E|\
+ Do-Query failed because of an unhandled application type: {0}
+
+ENTITY_NOT_FOUND_IN_OXM=\
+ AAIUI30082E|\
+ No {0} descriptors found in OXM file
+
+JSON_CONVERSION_ERROR=\
+ AAIUI30083E|\
+ An error occurred while converting JSON into {0}. Error: {1}
+
+ERROR_LOADING_OXM_SEARCHABLE_ENTITIES=\
+ AAIUI30084E|\
+ Failed to load searchable entities in OXM file. Synchronizer stopped.
+
+AAI_RETRIEVAL_FAILED_GENERIC=\
+ AAIUI30085E|\
+ Retrieving data from AAI failed with error = {0}
+
+AAI_RETRIEVAL_FAILED_FOR_SELF_LINK=\
+ AAIUI30086E|\
+ Failed to get result from AAI for link = {0}
+
+FAILED_TO_REGISTER_DUE_TO_NULL=\
+ AAIUI30087E|\
+ {0}
+
+FAILED_TO_ADD_SKELETON_NODE=\
+ AAIUI30088E|\
+ Failed to add skeleton node: {0}
+
+FAILED_TO_PROCESS_SKELETON_NODE=\
+ AAIUI30089E|\
+ Failed to process skeleton node: {0}
+
+INVALID_RESOLVE_STATE_DURING_INIT=\
+ AAIUI30090E|\
+ An error has occurred because Node in INIT state should not already have its self link resolved
+
+FAILED_TO_PROCESS_INITIAL_STATE=\
+ AAIUI30091E|\
+ Failed to process initial state: {0}
+
+SKIPPING_RELATIONSHIP=\
+ AAIUI30092E|\
+ Skipping relationship because failed to generate nodeId for relationship, {0}
+
+FAILED_TO_DETERMINE_NODE_ID=\
+ AAIUI30093E|\
+ Failed to determine node id: {0}
+
+EXTRACTION_ERROR=\
+ AAIUI30094E|\
+ Extraction failed: {0}
+
+SELF_LINK_NODE_PARSE_ERROR=\
+ AAIUI30095E|\
+ Self link node parsing error: {0}
+
+SELF_LINK_RETRIEVAL_FAILED=\
+ AAIUI30096E|\
+ Complex Entity Self link retrieval for link = {0} failed with error code = {1} and message = {2}
+
+SELF_LINK_DETERMINATION_FAILED_GENERIC=\
+ AAIUI30097E|\
+ Self link determination failed for entity with link = {0}
+
+SELF_LINK_DETERMINATION_FAILED_UNEXPECTED_LINKS=\
+ AAIUI30098E|\
+ Self link determination failed with an ambiguous result with an unexpected number of links = {0}
+
+ROOT_NODE_DISCOVERED=\
+ AAIUI30099E|\
+ Root node discovered for search target node ID = {0}
+
+SELF_LINK_PROCESS_NEIGHBORS_ERROR=\
+ AAIUI300100E|\
+ Self link node process neighbors error: {0}
+
+SELF_LINK_JSON_PARSE_ERROR=\
+ AAIUI300101E|\
+ Self link JSON parsing error: {0}
+
+SELF_LINK_PROCESSING_ERROR=\
+ AAIUI300102E|\
+ Self link processing error: {0}
+
+UNHANDLED_OBJ_TYPE_FOR_ENTITY_TYPE=\
+ AAIUI300103E|\
+ Error: Unhandled object type for entityType, {0}, which is not an array
+
+ATTRIBUTE_GROUP_FAILURE=\
+ AAIUI300104E|\
+ Failure to process attribute group field, fields is null for attribute group {0}
+
+EXCEPTION_CAUGHT=\
+ AAIUI300105E|\
+ Exception caught. {0} Exception: {1}
+
+ERROR_EXTRACTING_FROM_RESPONSE=\
+ AAIUI300106E|\
+ {0}
+
+PROCESSING_LOOP_INTERUPTED=\
+ AAIUI300107E|\
+ Processing loop interrupted: {0}
+
+IGNORING_SKELETON_NODE=\
+ AAIUI300108E|\
+ Ignoring skeleton node with unique ID, {0}, because of processing error
+
+VISUALIZATION_OUTPUT_ERROR=\
+ AAIUI300109E|\
+ An error occurred while preparing D3 visualization output: {0}
+
+FAILED_TO_PROCESS_NODE_INTEGRITY=\
+ AAIUI300110E|\
+ Failed to process node integrity: {0}
+
+FAILURE_TO_PROCESS_REQUEST=\
+ AAIUI300111E\
+ Failure to process request. {0}
+
+FAILED_TO_DETERMINE=\
+ AAIUI300112E\
+ Failed to determine {0}
+
+FAILED_TO_ANALYZE=\
+ AAIUI300113E|\
+ Failed to analyze {0}
+
+FAILED_TO_GET_NODES_QUERY_RESULT=\
+ AAIUI300114E|\
+ Failed to get nodes-query result from AAI with error {0}
+
+UNEXPECTED_NUMBER_OF_LINKS=\
+ AAIUI300115E|\
+ Unexpected number of links found. Expected {0}, but found {1}
+
+ITEM_TYPE_NULL=\
+ AAIUI300116E|\
+ Item type null for node, {0}
+
+UNEXPECTED_TOKEN_COUNT=\
+ AAIUI300117E|\
+ Unexpected number of tokens returned from splitting typeAndField by period delimiter. Field value: {0}
+
+ADD_SEARCH_TARGET_ATTRIBUTES_FAILED=\
+ AAIUI300118E|\
+ Add SearchTargetAttributes failure: {0}
+
+NODE_INTEGRITY_OVERLAY_ERROR=\
+ AAIUI300119E|\
+ Error processing node integrity overlay: {0}
+
+ERROR_LOADING_OXM_SUGGESTIBLE_ENTITIES=\
+ AAIUI300120E|\
+ Failed to load suggestible entities in OXM file. Synchronizer stopped.
+
+ES_SUGGESTION_SEARCH_ENTITY_SYNC_ERROR=\
+ AAIUI300121E|\
+ {0}
+
+ES_AGGREGATION_SUGGESTION_ENTITY_SYNC_ERROR=\
+ AAIUI300122E|\
+ {0}
+
+ENTITY_SYNC_SEARCH_TAG_ANNOTATION_FAILED=\
+ AAIUI300123E|\
+ {0}
+
+UNSUPPORTED_URL_ENCODING=\
+ AAIUI300124E|\
+ Unsupported URL encoding: {0}
+
+INVALID_REDIRECT_URL=\
+ AAIUI300125E|\
+ Cannot redirect to invalid URL: {0}
+
+ERROR_REMOVING_URL_PARAM=\
+ AAIUI300127E|\
+ Failed to remove query param from URL: {0}
+
+ERROR_INVALID_HASH=\
+ AAIUI300128E|\
+ Invalid hash value: {0}
+
+ERROR_HASH_NOT_FOUND=\
+ AAIUI300129E|\
+ Could not find hash value.
+
+ERROR_READING_HTTP_REQ_PARAMS=\
+ AAIUI300130E|\
+ Could not read HTTP header parameters.
+
+ERROR_D3_GRAPH_VISUALIZATION=\
+ AAIUI300129E|\
+ Failed to generate D3 graph visualization, due to a servlet exception with a cause: {0}
+
+ERROR_AAI_QUERY_WITH_RETRY=\
+ AAIUI300130E|\
+ Querying AAI with retry failed due to exception: {0}
+
+ERROR_READING_JSON_SCHEMA=\
+ AAIUI300131E|\
+ Error reading JSON schema from: {0}
+
+VIEW_NAME_NOT_SUPPORTED=\
+ AAIUI300132E|\
+ View name not supported: {0}
+
+ERROR_FETCHING_FILTER_VALUES=\
+ AAIUI300133E|\
+ Result {0} while fetching filter values for filter {1}.
+
+ERROR_PROCESSING_WIDGET_REQUEST=\
+ AAIUI300134E|\
+ Error processing for query: {0} in view: {1}
+
+
+ERROR_FILTERS_NOT_FOUND=\
+ AAIUI300135E|\
+ No filters were provided as part of request.
+
+DR_REQUEST_URI_FOR_PROXY_UNKNOWN=\
+ AAIUI300136E|\
+ Failure to generate routing service URL from: {0}
+
+OXM_LOADING_ERROR=\
+ AAIUI300137E|\
+ OXM loading error. Reason: {0}
+
+URI_DECODING_EXCEPTION=\
+ AAIUI300138E|\
+ Error decoding exception. {0}
+
+ENCRYPTION_ERROR=\
+ AAIUI300139E|\
+ Encryption error for value: {0}. Cause: {1}
+
+DECRYPTION_ERROR=\
+ AAIUI300140E|\
+ Decryption error for encrypted value: {0}. Cause: {1}
+
+RESOURCE_NOT_FOUND=\
+ AAIUI300141E|\
+ Unsupported request. Resource not found: {0}
+
+#-------------------- 900 Series Errors --------------------#
+
+UNKNOWN_SERVER_ERROR=\
+ AAIUI9001E|\
+ Unknown Server Error: {0}
+
+SEARCH_ADAPTER_ERROR=\
+ AAIUI9002E|\
+ Search Adapter Error: {0}
+
+QUERY_PARAM_EXTRACTION_ERROR=\
+ AAIUI9003E|\
+ Query Parameter Self-Link Extraction Error: {0}
+
+ERROR_EXTRACTING_RESOURCE_PATH_FROM_LINK=\
+ AAIUI9004E|\
+ Error extracting resource path from self-link. Error: {0}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/analytics/AveragingRingBufferTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/analytics/AveragingRingBufferTest.java
new file mode 100644
index 0000000..f64a0f5
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/analytics/AveragingRingBufferTest.java
@@ -0,0 +1,134 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+
+package org.onap.aai.sparky.analytics;
+
+import static org.junit.Assert.assertEquals;
+
+import java.security.SecureRandom;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.onap.aai.sparky.analytics.AveragingRingBuffer;
+
+/**
+ * The Class AveragingRingBufferTest.
+ */
+@RunWith(MockitoJUnitRunner.class)
+public class AveragingRingBufferTest {
+
+ protected SecureRandom random = new SecureRandom();
+
+ /**
+ * Inits the.
+ *
+ * @throws Exception the exception
+ */
+ @Before
+ public void init() throws Exception {
+ // nothing at the moment
+ }
+
+ /**
+ * Validate pre index roll averaging.
+ */
+ @Test
+ public void validatePreIndexRollAveraging() {
+
+ AveragingRingBuffer arb = new AveragingRingBuffer(5);
+ assertEquals(0, arb.getAvg());
+
+ /*
+ * On initial buffer fill, the average will be re-calculated on the fly for the first nth data
+ * points until the data buffer has been filled the first time, and then the buffer
+ * automatically recalculates the average every time the buffer index rolls over, to the keep
+ * the average relative to the last "nth" data points.
+ */
+
+ // [ 1, 0, 0, 0, 0 ], sum = 1, avg = 1/1 =1
+ arb.addSample(1);
+ assertEquals(1, arb.getAvg());
+
+ // [ 1, 2, 0, 0, 0 ], sum = 3, avg = 3/2 = 1
+ arb.addSample(2);
+ assertEquals(1, arb.getAvg());
+
+ // [ 1, 2, 3, 0, 0 ], sum = 6, avg = 6/3 = 2
+ arb.addSample(3);
+ assertEquals(2, arb.getAvg());
+
+ // [ 1, 2, 3, 4, 0 ], sum = 10, avg = 10/4 = 2
+ arb.addSample(4);
+ assertEquals(2, arb.getAvg());
+
+ // [ 1, 2, 3, 4, 5 ], sum = 15, avg = 15/5 = 3
+ arb.addSample(5);
+ assertEquals(3, arb.getAvg());
+
+ }
+
+ /**
+ * Validate post index roll averaging.
+ */
+ @Test
+ public void validatePostIndexRollAveraging() {
+
+ AveragingRingBuffer arb = new AveragingRingBuffer(5);
+ arb.addSample(1);
+ arb.addSample(2);
+ arb.addSample(3);
+ arb.addSample(4);
+ arb.addSample(5);
+
+ /*
+ * The behavior switches, and now doesn't re-calculate the average until each nth data point, to
+ * reduce the computational over-head of re-calculating on each value.
+ */
+
+ // [ 10, 2, 3, 4, 5 ],
+ arb.addSample(10);
+ assertEquals(3, arb.getAvg());
+
+ // [ 10, 20, 3, 4, 5 ],
+ arb.addSample(20);
+ assertEquals(3, arb.getAvg());
+
+ // [ 10, 20, 30, 4, 5 ],
+ arb.addSample(30);
+ assertEquals(3, arb.getAvg());
+
+ // [ 10, 20, 30, 40, 5 ],
+ arb.addSample(40);
+ assertEquals(3, arb.getAvg());
+
+ // [ 10, 20, 30, 40, 50 ], s=150, avg=150/5=30
+ arb.addSample(50);
+ assertEquals(30, arb.getAvg());
+
+ }
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/analytics/HistogramSamplerTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/analytics/HistogramSamplerTest.java
new file mode 100644
index 0000000..bba52a7
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/analytics/HistogramSamplerTest.java
@@ -0,0 +1,91 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+
+package org.onap.aai.sparky.analytics;
+
+import java.security.SecureRandom;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.onap.aai.sparky.analytics.HistogramSampler;
+
+/**
+ * The Class HistogramSamplerTest.
+ */
+@RunWith(MockitoJUnitRunner.class)
+public class HistogramSamplerTest {
+
+ protected SecureRandom random = new SecureRandom();
+
+ /**
+ * Inits the.
+ *
+ * @throws Exception the exception
+ */
+ @Before
+ public void init() throws Exception {
+ // nothing at the moment
+ }
+
+ /**
+ * Validate basic construction and delimited reporting.
+ */
+ @Test
+ public void validateBasicConstructionAndDelimitedReporting() {
+
+ HistogramSampler histoSampler = new HistogramSampler("[File byte size]", 500000, 22, 3);
+
+ SecureRandom random = new SecureRandom();
+
+ for (int x = 0; x < 100000; x++) {
+ histoSampler.track(random.nextInt(9999999));
+ }
+
+ System.out.println(histoSampler.getStats(false, " "));
+
+ }
+
+
+ /**
+ * Validate basic construction and formatted reporting.
+ */
+ @Test
+ public void validateBasicConstructionAndFormattedReporting() {
+
+ HistogramSampler histoSampler = new HistogramSampler("[Queue Length Samples]", 100000, 15, 3);
+
+ SecureRandom random = new SecureRandom();
+
+ for (int x = 0; x < 100000; x++) {
+ histoSampler.track(random.nextInt(9999999));
+ }
+
+ System.out.println(histoSampler.getStats(true, " "));
+
+ }
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/analytics/HistoricalCounterTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/analytics/HistoricalCounterTest.java
new file mode 100644
index 0000000..21899a9
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/analytics/HistoricalCounterTest.java
@@ -0,0 +1,70 @@
+package org.onap.aai.sparky.analytics;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.onap.aai.sparky.analytics.HistoricalCounter;
+
+public class HistoricalCounterTest {
+
+
+ private HistoricalCounter historicalCounter;
+ private HistoricalCounter historicalCount;
+ @Before
+ public void init() throws Exception {
+ historicalCounter = new HistoricalCounter(true);
+ historicalCount = new HistoricalCounter(false);
+ }
+
+ @Test
+ public void successfullInitialization() {
+ assertEquals(-1, historicalCounter.getMin(),0);
+ assertEquals(0, historicalCounter.getMax(),0);
+ assertEquals(0, historicalCounter.getNumSamples(),0);
+ assertEquals(0, historicalCounter.getNumSamples(),0);
+ assertEquals(0.0, historicalCounter.getValue(),0);
+ assertEquals(0, historicalCounter.getAvg(),0);
+ assertTrue(historicalCounter.isSingleValue());
+
+ }
+
+ @Test
+ public void updateValuesAndReset() {
+ historicalCounter.update(-1);
+ assertEquals(0, historicalCounter.getValue(),0);
+ historicalCounter.update(10);
+ assertEquals(10, historicalCounter.getValue(),0);
+ historicalCounter.reset();
+ assertEquals(-1, historicalCounter.getMin(),0);
+ assertEquals(0, historicalCounter.getMax(),0);
+ assertEquals(0, historicalCounter.getNumSamples(),0);
+ assertEquals(0, historicalCounter.getNumSamples(),0);
+ assertEquals(0.0, historicalCounter.getValue(),0);
+
+ }
+
+ @Test
+ public void updateValues() {
+ historicalCount.update(2);
+ assertEquals(2, historicalCount.getMin(),0);
+ historicalCount.setMin(10);
+ historicalCount.update(3);
+ assertEquals(3, historicalCount.getMin(),0);
+ historicalCount.setMax(1);
+ historicalCount.update(4);
+ assertEquals(4, historicalCount.getMax(),0);
+ historicalCount.setTotalOfSamples(10);
+ historicalCount.setNumSamples(2);
+ assertEquals(5, historicalCount.getAvg(),0);
+ historicalCount.setTotalOfSamples(10);
+ assertEquals(10, historicalCount.getTotalOfSamples(),0);
+ historicalCount.setMaintainSingleValue(true);
+ assertTrue(historicalCounter.isSingleValue());
+
+ }
+
+
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/analytics/TransactionRateControllerTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/analytics/TransactionRateControllerTest.java
new file mode 100644
index 0000000..881c9ab
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/analytics/TransactionRateControllerTest.java
@@ -0,0 +1,217 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+
+package org.onap.aai.sparky.analytics;
+
+import org.junit.Before;
+
+
+/**
+ * The Class TransactionRateControllerTest.
+ */
+public class TransactionRateControllerTest {
+
+ /**
+ * Inits the.
+ *
+ * @throws Exception the exception
+ */
+ @Before
+ public void init() throws Exception {
+ // nothing at the moment
+ }
+ /*
+ * @Test public void tenTPS_oneThread_validateRateEnforcementWhenAvgResposneTimeIsUnderBudget() {
+ *
+ * TransactionRateController trc = new TransactionRateController(10.0, 1, 5);
+ *
+ * trc.trackResponseTime(25); trc.trackResponseTime(35); trc.trackResponseTime(45);
+ * trc.trackResponseTime(55); trc.trackResponseTime(70);
+ *
+ * // avg should be 46 ms
+ *
+ * assertEquals(54, trc.getFixedDelayInMs());
+ *
+ * }
+ *
+ * @Test public void tenTPS_oneThread_validateRateEnforcementWhenAvgResposneTimeIsOverBudget() {
+ *
+ * TransactionRateController trc = new TransactionRateController(10.0, 1, 5);
+ *
+ * trc.trackResponseTime(75); trc.trackResponseTime(125); trc.trackResponseTime(250);
+ * trc.trackResponseTime(105); trc.trackResponseTime(23);
+ *
+ * // avg should be 115 ms
+ *
+ * assertEquals(0, trc.getFixedDelayInMs());
+ *
+ * }
+ *
+ * @Test public void oneTPS_oneThread_validateRateEnforcementWhenAvgResposneTimeIsUnderBudget() {
+ *
+ * TransactionRateController trc = new TransactionRateController(1.0, 1, 5);
+ *
+ * trc.trackResponseTime(25); trc.trackResponseTime(35); trc.trackResponseTime(45);
+ * trc.trackResponseTime(55); trc.trackResponseTime(70);
+ *
+ * // avg should be 46 ms
+ *
+ * assertEquals(954, trc.getFixedDelayInMs());
+ *
+ * }
+ *
+ * @Test public void oneTPS_oneThread_validateRateEnforcementWhenAvgResposneTimeIsOverBudget() {
+ *
+ * TransactionRateController trc = new TransactionRateController(1.0, 1, 5);
+ *
+ * trc.trackResponseTime(75); trc.trackResponseTime(125); trc.trackResponseTime(250);
+ * trc.trackResponseTime(105); trc.trackResponseTime(23);
+ *
+ * // avg should be 115 ms
+ *
+ * assertEquals(885, trc.getFixedDelayInMs());
+ *
+ * }
+ *
+ * @Test public void halfTPS_oneThread_validateRateEnforcementWhenAvgResposneTimeIsUnderBudget() {
+ *
+ * TransactionRateController trc = new TransactionRateController(0.5, 1, 5);
+ *
+ * trc.trackResponseTime(25); trc.trackResponseTime(35); trc.trackResponseTime(45);
+ * trc.trackResponseTime(55); trc.trackResponseTime(70);
+ *
+ * // avg should be 46 ms
+ *
+ * assertEquals(1954, trc.getFixedDelayInMs());
+ *
+ * }
+ *
+ * @Test public void halfTPS_oneThread_validateRateEnforcementWhenAvgResposneTimeIsOverBudget() {
+ *
+ * TransactionRateController trc = new TransactionRateController(0.5, 1, 5);
+ *
+ * trc.trackResponseTime(75); trc.trackResponseTime(125); trc.trackResponseTime(250);
+ * trc.trackResponseTime(105); trc.trackResponseTime(23);
+ *
+ * // avg should be 115 ms
+ *
+ * assertEquals(1885, trc.getFixedDelayInMs());
+ *
+ * }
+ *
+ * @Test public void tenTPS_tenThreads_validateRateEnforcementWhenAvgResposneTimeIsUnderBudget() {
+ *
+ * TransactionRateController trc = new TransactionRateController(10.0, 10, 5);
+ *
+ * trc.trackResponseTime(25); trc.trackResponseTime(35); trc.trackResponseTime(45);
+ * trc.trackResponseTime(55); trc.trackResponseTime(70);
+ *
+ * // avg should be 46 ms
+ *
+ * assertEquals(540, trc.getFixedDelayInMs());
+ *
+ * }
+ *
+ * @Test public void tenTPS_tenThreads_validateRateEnforcementWhenAvgResposneTimeIsOverBudget() {
+ *
+ * TransactionRateController trc = new TransactionRateController(10.0, 10, 5);
+ *
+ * trc.trackResponseTime(75); trc.trackResponseTime(125); trc.trackResponseTime(250);
+ * trc.trackResponseTime(105); trc.trackResponseTime(23);
+ *
+ * // avg should be 115 ms
+ *
+ * assertEquals(0, trc.getFixedDelayInMs());
+ *
+ * }
+ *
+ * @Test public void oneTPS_tenThreads_validateRateEnforcementWhenAvgResposneTimeIsUnderBudget() {
+ *
+ * TransactionRateController trc = new TransactionRateController(1.0, 10, 5);
+ *
+ * trc.trackResponseTime(25); trc.trackResponseTime(35); trc.trackResponseTime(45);
+ * trc.trackResponseTime(55); trc.trackResponseTime(70);
+ *
+ * // avg should be 46 ms
+ *
+ * assertEquals(9540, trc.getFixedDelayInMs());
+ *
+ * }
+ *
+ * @Test public void oneTPS_tenThreads_validateRateEnforcementWhenAvgResposneTimeIsOverBudget() {
+ *
+ * TransactionRateController trc = new TransactionRateController(1.0, 10, 5);
+ *
+ * trc.trackResponseTime(75); trc.trackResponseTime(125); trc.trackResponseTime(250);
+ * trc.trackResponseTime(105); trc.trackResponseTime(23);
+ *
+ * // avg should be 115 ms
+ *
+ * assertEquals(8850, trc.getFixedDelayInMs());
+ *
+ * }
+ *
+ * @Test public void halfTPS_tenThreads_validateRateEnforcementWhenAvgResposneTimeIsUnderBudget()
+ * {
+ *
+ * TransactionRateController trc = new TransactionRateController(0.5, 10, 5);
+ *
+ * trc.trackResponseTime(25); trc.trackResponseTime(35); trc.trackResponseTime(45);
+ * trc.trackResponseTime(55); trc.trackResponseTime(70);
+ *
+ * // avg should be 46 ms
+ *
+ * assertEquals(19540, trc.getFixedDelayInMs());
+ *
+ * }
+ *
+ * @Test public void halfTPS_tenThreads_validateRateEnforcementWhenAvgResposneTimeIsOverBudget() {
+ *
+ * TransactionRateController trc = new TransactionRateController(0.5, 10, 5);
+ *
+ * trc.trackResponseTime(75); trc.trackResponseTime(125); trc.trackResponseTime(250);
+ * trc.trackResponseTime(105); trc.trackResponseTime(23);
+ *
+ * // avg should be 115 ms
+ *
+ * assertEquals(18850, trc.getFixedDelayInMs());
+ *
+ * }
+ *
+ * @Test public void oneTPS_fiveThreads_validateRateEnforcementWhenAvgResposneTimeIsOverBudget() {
+ *
+ * TransactionRateController trc = new TransactionRateController(1, 5, 5);
+ *
+ * trc.trackResponseTime(0); trc.trackResponseTime(0); trc.trackResponseTime(0);
+ * trc.trackResponseTime(0); trc.trackResponseTime(0);
+ *
+ * // avg should be 0 ms
+ *
+ * assertEquals(5000, trc.getFixedDelayInMs());
+ *
+ * }
+ */
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/autosuggestion/sync/AutosuggestionSynchronizerTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/autosuggestion/sync/AutosuggestionSynchronizerTest.java
new file mode 100644
index 0000000..dd6f1c7
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/autosuggestion/sync/AutosuggestionSynchronizerTest.java
@@ -0,0 +1,387 @@
+package org.onap.aai.sparky.autosuggestion.sync;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Matchers;
+import org.mockito.Mockito;
+import org.onap.aai.restclient.client.OperationResult;
+import org.onap.aai.sparky.config.oxm.OxmEntityDescriptor;
+import org.onap.aai.sparky.config.oxm.OxmEntityLookup;
+import org.onap.aai.sparky.config.oxm.OxmModelLoader;
+import org.onap.aai.sparky.config.oxm.OxmModelProcessor;
+import org.onap.aai.sparky.config.oxm.SuggestionEntityDescriptor;
+import org.onap.aai.sparky.config.oxm.SuggestionEntityLookup;
+import org.onap.aai.sparky.dal.ActiveInventoryAdapter;
+import org.onap.aai.sparky.dal.ElasticSearchAdapter;
+import org.onap.aai.sparky.search.filters.config.FiltersConfig;
+import org.onap.aai.sparky.search.filters.config.FiltersDetailsConfig;
+import org.onap.aai.sparky.search.filters.config.FiltersForViewsConfig;
+import org.onap.aai.sparky.sync.config.ElasticSearchSchemaConfig;
+import org.onap.aai.sparky.sync.config.NetworkStatisticsConfig;
+import org.onap.aai.sparky.sync.enumeration.OperationState;
+import org.onap.aai.sparky.util.TestResourceLoader;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+public class AutosuggestionSynchronizerTest {
+
+ private static ObjectMapper mapper = new ObjectMapper();
+
+ private AutosuggestionSynchronizer suggestionSynchronizer;
+
+ private ElasticSearchSchemaConfig esSchemaConfig;
+ private NetworkStatisticsConfig aaiStatConfig;
+ private NetworkStatisticsConfig esStatConfig;
+ private OxmEntityLookup oxmEntityLookup;
+ private SuggestionEntityLookup suggestionEntityLookup;
+ private ElasticSearchAdapter esAdapter;
+ private ActiveInventoryAdapter aaiAdapter;
+
+
+ private FiltersConfig filtersConfig;
+
+
+
+ @Before
+ public void init() throws Exception {
+
+ esSchemaConfig = new ElasticSearchSchemaConfig();
+ esSchemaConfig.setIndexDocType("default");
+ esSchemaConfig.setIndexMappingsFileName(null);
+ esSchemaConfig.setIndexName("aggregation-index-name");
+ esSchemaConfig.setIndexSettingsFileName(null);
+
+
+ aaiStatConfig = new NetworkStatisticsConfig();
+
+ aaiStatConfig.setNumSamplesPerThreadForRunningAverage(100);
+
+ aaiStatConfig.setBytesHistogramLabel("[Response Size In Bytes]");
+ aaiStatConfig.setBytesHistogramMaxYAxis(1000000L);
+ aaiStatConfig.setBytesHistogramNumBins(20);
+ aaiStatConfig.setBytesHistogramNumDecimalPoints(2);
+
+ aaiStatConfig.setQueueLengthHistogramLabel("[Queue Item Length]");
+ aaiStatConfig.setQueueLengthHistogramMaxYAxis(20000);
+ aaiStatConfig.setQueueLengthHistogramNumBins(20);
+ aaiStatConfig.setQueueLengthHistogramNumDecimalPoints(2);
+
+ aaiStatConfig.setTaskAgeHistogramLabel("[Task Age In Ms]");
+ aaiStatConfig.setTaskAgeHistogramMaxYAxis(600000L);
+ aaiStatConfig.setTaskAgeHistogramNumBins(20);
+ aaiStatConfig.setTaskAgeHistogramNumDecimalPoints(2);
+
+ aaiStatConfig.setResponseTimeHistogramLabel("[Response Time In Ms]");
+ aaiStatConfig.setResponseTimeHistogramMaxYAxis(1000L);
+ aaiStatConfig.setResponseTimeHistogramNumBins(20);
+ aaiStatConfig.setResponseTimeHistogramNumDecimalPoints(2);
+
+ aaiStatConfig.setTpsHistogramLabel("[Transactions Per Second]");
+ aaiStatConfig.setTpsHistogramMaxYAxis(100);
+ aaiStatConfig.setTpsHistogramNumBins(20);
+ aaiStatConfig.setTpsHistogramNumDecimalPoints(2);
+
+ esStatConfig = new NetworkStatisticsConfig();
+
+ esStatConfig.setNumSamplesPerThreadForRunningAverage(100);
+
+ esStatConfig.setBytesHistogramLabel("[Response Size In Bytes]");
+ esStatConfig.setBytesHistogramMaxYAxis(1000000L);
+ esStatConfig.setBytesHistogramNumBins(20);
+ esStatConfig.setBytesHistogramNumDecimalPoints(2);
+
+ esStatConfig.setQueueLengthHistogramLabel("[Queue Item Length]");
+ esStatConfig.setQueueLengthHistogramMaxYAxis(20000);
+ esStatConfig.setQueueLengthHistogramNumBins(20);
+ esStatConfig.setQueueLengthHistogramNumDecimalPoints(2);
+
+ esStatConfig.setTaskAgeHistogramLabel("[Task Age In Ms]");
+ esStatConfig.setTaskAgeHistogramMaxYAxis(600000L);
+ esStatConfig.setTaskAgeHistogramNumBins(20);
+ esStatConfig.setTaskAgeHistogramNumDecimalPoints(2);
+
+ esStatConfig.setResponseTimeHistogramLabel("[Response Time In Ms]");
+ esStatConfig.setResponseTimeHistogramMaxYAxis(10000L);
+ esStatConfig.setResponseTimeHistogramNumBins(20);
+ esStatConfig.setResponseTimeHistogramNumDecimalPoints(2);
+
+ esStatConfig.setTpsHistogramLabel("[Transactions Per Second]");
+ esStatConfig.setTpsHistogramMaxYAxis(100);
+ esStatConfig.setTpsHistogramNumBins(20);
+ esStatConfig.setTpsHistogramNumDecimalPoints(2);
+
+ oxmEntityLookup = new OxmEntityLookup();
+
+ esAdapter = Mockito.mock(ElasticSearchAdapter.class);
+ aaiAdapter = Mockito.mock(ActiveInventoryAdapter.class);
+
+
+ Set<OxmModelProcessor> processors = new HashSet<OxmModelProcessor>();
+
+ processors.add(oxmEntityLookup);
+
+
+
+ Map<String, OxmEntityDescriptor> oxmEntityDescriptors =
+ new HashMap<String, OxmEntityDescriptor>();
+
+ OxmEntityDescriptor genericVnfDescriptor = new OxmEntityDescriptor();
+ genericVnfDescriptor.setEntityName("generic-vnf");
+ List<String> pkeyNames = new ArrayList<String>();
+ pkeyNames.add("vnf-name");
+
+ genericVnfDescriptor.setPrimaryKeyAttributeNames(pkeyNames);
+
+ oxmEntityDescriptors.put("generic-vnf", genericVnfDescriptor);
+
+
+ oxmEntityLookup.setEntityDescriptors(oxmEntityDescriptors);
+
+
+ Map<String, SuggestionEntityDescriptor> suggestionEntityDescriptors =
+ new HashMap<String, SuggestionEntityDescriptor>();
+
+ SuggestionEntityDescriptor genericVnfSuggestionDescriptor = new SuggestionEntityDescriptor();
+ genericVnfSuggestionDescriptor.setEntityName("generic-vnf");
+ genericVnfSuggestionDescriptor.setPrimaryKeyAttributeNames(pkeyNames);
+
+ filtersConfig = new FiltersConfig(null, null, null);
+
+ FiltersDetailsConfig filtersDetailsConfig = mapper.readValue(
+ TestResourceLoader.getTestResourceDataJson("/filters/aaiui_filters_testConfig.json"),
+ FiltersDetailsConfig.class);
+ FiltersForViewsConfig filtersForViewsConfig = mapper.readValue(
+ TestResourceLoader.getTestResourceDataJson("/filters/aaiui_views_testConfig.json"),
+ FiltersForViewsConfig.class);
+
+ filtersConfig.setFiltersConfig(filtersDetailsConfig);
+ filtersConfig.setViewsConfig(filtersForViewsConfig);
+
+ /*
+ * SuggestionSearchEntity sse = new SuggestionSearchEntity(filtersConfig);
+ *
+ * sse.setEntityType("generic-vnf"); sse.setSuggestionPropertyTypes( Arrays.asList("vnf-name"));
+ *
+ * genericVnfSuggestionDescriptor.setSuggestionSearchEntity(sse);
+ *
+ * suggestionEntityDescriptors.put("generic-vnf", genericVnfSuggestionDescriptor);
+ */
+
+ suggestionEntityLookup = new SuggestionEntityLookup(filtersConfig);
+
+ processors.add(suggestionEntityLookup);
+
+ OxmModelLoader oxmModelLoader = new OxmModelLoader(-1, processors);
+ oxmModelLoader.loadLatestOxmModel();
+
+ // suggestionEntityLookup.setSuggestionSearchEntityDescriptors(suggestionEntityDescriptors);
+ }
+
+ @Test
+ public void validateBasicConstruction() throws Exception {
+
+ suggestionSynchronizer = new AutosuggestionSynchronizer(esSchemaConfig, 5, 5, 5, aaiStatConfig,
+ esStatConfig, oxmEntityLookup, suggestionEntityLookup, filtersConfig);
+
+ suggestionSynchronizer.setAaiAdapter(aaiAdapter);
+ suggestionSynchronizer.setElasticSearchAdapter(esAdapter);
+
+ assertNotNull(suggestionSynchronizer.getAaiAdapter());
+ assertNotNull(suggestionSynchronizer.getElasticSearchAdapter());
+
+ }
+
+ @Test
+ public void validateSmallSync() throws Exception {
+
+ suggestionSynchronizer = new AutosuggestionSynchronizer(esSchemaConfig, 5, 5, 5, aaiStatConfig,
+ esStatConfig, oxmEntityLookup, suggestionEntityLookup, filtersConfig);
+
+
+ suggestionSynchronizer.setAaiAdapter(aaiAdapter);
+ suggestionSynchronizer.setElasticSearchAdapter(esAdapter);
+
+ String nodesQueryResponse = TestResourceLoader
+ .getTestResourceDataJson("/sync/aai/activeInventory_generic-vnf_nodesQuery_response.json");
+
+ OperationResult genericVnfSelfLinks = new OperationResult();
+
+ genericVnfSelfLinks.setResultCode(200);
+ genericVnfSelfLinks.setResult(nodesQueryResponse);
+
+ Mockito.when(aaiAdapter.getSelfLinksByEntityType("generic-vnf"))
+ .thenReturn(genericVnfSelfLinks);
+
+ Mockito
+ .when(aaiAdapter.repairSelfLink(Matchers.contains("generic-vnf-1"),
+ Mockito.anyString()))
+ .thenReturn(
+ "https://server.proxy:8443/aai/v11/network/generic-vnfs/generic-vnf/generic-vnf-1");
+
+ Mockito
+ .when(aaiAdapter.repairSelfLink(Matchers.contains("generic-vnf-2"),
+ Mockito.anyString()))
+ .thenReturn(
+ "https://server.proxy:8443/aai/v11/network/generic-vnfs/generic-vnf/generic-vnf-2");
+
+ Mockito
+ .when(
+ aaiAdapter.repairSelfLink(Matchers.contains("generic-vnf-3"), Mockito.anyString()))
+ .thenReturn(
+ "https://server.proxy:8443/aai/v11/network/generic-vnfs/generic-vnf/generic-vnf-3");
+
+ Mockito
+ .when(aaiAdapter.queryActiveInventoryWithRetries(
+ Matchers.contains("generic-vnf-1"), Mockito.anyString(),
+ Mockito.anyInt()))
+ .thenReturn(new OperationResult(200, TestResourceLoader.getTestResourceDataJson(
+ "/sync/aai/generic-vnf-generic-vnf-1_full_depth.json")));
+
+ Mockito
+ .when(aaiAdapter.queryActiveInventoryWithRetries(
+ Matchers.contains("generic-vnf-2"), Mockito.anyString(),
+ Mockito.anyInt()))
+ .thenReturn(new OperationResult(200, TestResourceLoader.getTestResourceDataJson(
+ "/sync/aai/generic-vnf-generic-vnf-2_full_depth.json")));
+
+ Mockito
+ .when(aaiAdapter.queryActiveInventoryWithRetries(Matchers.contains("generic-vnf-3"),
+ Mockito.anyString(), Mockito.anyInt()))
+ .thenReturn(new OperationResult(200, TestResourceLoader
+ .getTestResourceDataJson("/sync/aai/generic-vnf-generic-vnf-3_full_depth.json")));
+
+ Mockito.when(esAdapter.buildElasticSearchGetDocUrl(Mockito.anyString(), Mockito.anyString()))
+ .thenReturn("http://localhost:9200/myindex/mytype/doc1",
+ "http://localhost:9200/myindex/mytype/doc2",
+ "http://localhost:9200/myindex/mytype/doc3");
+
+ /*
+ * Our initial gets from elastic search should be record-not-found
+ */
+ Mockito.when(esAdapter.doGet(Matchers.contains("doc1"), Mockito.any()))
+ .thenReturn(new OperationResult(404, null));
+ Mockito.when(esAdapter.doGet(Matchers.contains("doc2"), Mockito.any()))
+ .thenReturn(new OperationResult(404, null));
+ Mockito.when(esAdapter.doGet(Matchers.contains("doc3"), Mockito.any()))
+ .thenReturn(new OperationResult(404, null));
+
+
+ Mockito.when(esAdapter.doPut(Matchers.contains("doc"), Mockito.any(), Mockito.any()))
+ .thenReturn(new OperationResult(200, null));
+
+ OperationState syncState = suggestionSynchronizer.doSync();
+ assertEquals(OperationState.OK, syncState);
+
+ assertNotNull(suggestionSynchronizer.getStatReport(false));
+ assertNotNull(suggestionSynchronizer.getStatReport(true));
+
+ suggestionSynchronizer.clearCache();
+ suggestionSynchronizer.shutdown();
+
+
+ }
+
+ @Test
+ public void validateSmallSyncWithRetries() throws Exception {
+
+ suggestionSynchronizer = new AutosuggestionSynchronizer(esSchemaConfig, 5, 5, 5, aaiStatConfig,
+ esStatConfig, oxmEntityLookup, suggestionEntityLookup, filtersConfig);
+
+
+ suggestionSynchronizer.setAaiAdapter(aaiAdapter);
+ suggestionSynchronizer.setElasticSearchAdapter(esAdapter);
+
+ String nodesQueryResponse = TestResourceLoader
+ .getTestResourceDataJson("/sync/aai/activeInventory_generic-vnf_nodesQuery_response.json");
+
+ OperationResult genericVnfSelfLinks = new OperationResult();
+
+ genericVnfSelfLinks.setResultCode(200);
+ genericVnfSelfLinks.setResult(nodesQueryResponse);
+
+ Mockito.when(aaiAdapter.getSelfLinksByEntityType("generic-vnf"))
+ .thenReturn(genericVnfSelfLinks);
+
+ Mockito
+ .when(aaiAdapter.repairSelfLink(Matchers.contains("generic-vnf-1"),
+ Mockito.anyString()))
+ .thenReturn(
+ "https://server.proxy:8443/aai/v11/network/generic-vnfs/generic-vnf/generic-vnf-1");
+
+ Mockito
+ .when(aaiAdapter.repairSelfLink(Matchers.contains("generic-vnf-2"),
+ Mockito.anyString()))
+ .thenReturn(
+ "https://server.proxy:8443/aai/v11/network/generic-vnfs/generic-vnf/generic-vnf-2");
+
+ Mockito
+ .when(
+ aaiAdapter.repairSelfLink(Matchers.contains("generic-vnf-3"), Mockito.anyString()))
+ .thenReturn(
+ "https://server.proxy:8443/aai/v11/network/generic-vnfs/generic-vnf/generic-vnf-3");
+
+ Mockito
+ .when(aaiAdapter.queryActiveInventoryWithRetries(
+ Matchers.contains("generic-vnf-1"), Mockito.anyString(),
+ Mockito.anyInt()))
+ .thenReturn(new OperationResult(200, TestResourceLoader.getTestResourceDataJson(
+ "/sync/aai/generic-vnf-generic-vnf-1_full_depth.json")));
+
+ Mockito
+ .when(aaiAdapter.queryActiveInventoryWithRetries(
+ Matchers.contains("generic-vnf-2"), Mockito.anyString(),
+ Mockito.anyInt()))
+ .thenReturn(new OperationResult(200, TestResourceLoader.getTestResourceDataJson(
+ "/sync/aai/generic-vnf-generic-vnf-2_full_depth.json")));
+
+ Mockito
+ .when(aaiAdapter.queryActiveInventoryWithRetries(Matchers.contains("generic-vnf-3"),
+ Mockito.anyString(), Mockito.anyInt()))
+ .thenReturn(new OperationResult(200, TestResourceLoader
+ .getTestResourceDataJson("/sync/aai/generic-vnf-generic-vnf-3_full_depth.json")));
+
+ Mockito.when(esAdapter.buildElasticSearchGetDocUrl(Mockito.anyString(), Mockito.anyString()))
+ .thenReturn("http://localhost:9200/myindex/mytype/doc1",
+ "http://localhost:9200/myindex/mytype/doc2",
+ "http://localhost:9200/myindex/mytype/doc3");
+
+ /*
+ * Our initial gets from elastic search should be record-not-found
+ */
+ Mockito.when(esAdapter.doGet(Matchers.contains("doc1"), Mockito.any()))
+ .thenReturn(new OperationResult(404, null));
+ Mockito.when(esAdapter.doGet(Matchers.contains("doc2"), Mockito.any()))
+ .thenReturn(new OperationResult(404, null));
+ Mockito.when(esAdapter.doGet(Matchers.contains("doc3"), Mockito.any()))
+ .thenReturn(new OperationResult(404, null));
+
+
+ /*
+ * Elastic Search puts always fail with a version conflict = 409
+ */
+
+ Mockito.when(esAdapter.doPut(Matchers.contains("doc"), Mockito.any(), Mockito.any()))
+ .thenReturn(new OperationResult(409, null));
+
+ OperationState syncState = suggestionSynchronizer.doSync();
+ assertEquals(OperationState.OK, syncState);
+
+ assertNotNull(suggestionSynchronizer.getStatReport(false));
+ assertNotNull(suggestionSynchronizer.getStatReport(true));
+
+ suggestionSynchronizer.clearCache();
+ suggestionSynchronizer.shutdown();
+
+
+ }
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/common/search/CommonSearchSuggestionTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/common/search/CommonSearchSuggestionTest.java
new file mode 100644
index 0000000..abe31a3
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/common/search/CommonSearchSuggestionTest.java
@@ -0,0 +1,55 @@
+package org.onap.aai.sparky.common.search;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import java.util.ArrayList;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.onap.aai.sparky.search.filters.entity.UiFilterValueEntity;
+
+
+public class CommonSearchSuggestionTest {
+
+ private CommonSearchSuggestion commonSearchSuggestions;
+ private CommonSearchSuggestion commonSearchSuggestion;
+ private ArrayList<UiFilterValueEntity> filterValues;
+
+ @Before
+ public void init() throws Exception {
+
+ filterValues = new ArrayList<UiFilterValueEntity>();
+ commonSearchSuggestions = new CommonSearchSuggestion("627dfa28b","schema","generic-vnf called sdwanfwdemo_vnf1_under_fw-si1","VNF-Stack",filterValues);
+ commonSearchSuggestion = new CommonSearchSuggestion("627dfa28b","schema","generic-vnf called sdwanfwdemo_vnf1_under_fw-si1","VNF-Stack",null);
+
+ }
+
+
+ @Test
+ public void updateValues() {
+
+ commonSearchSuggestions.setHashId("4a83c197ffa19ec4a1");
+ assertNotNull(commonSearchSuggestions.getHashId());
+ commonSearchSuggestions.setRoute("structuredView");
+ assertNotNull(commonSearchSuggestions.getRoute());
+ commonSearchSuggestions.setText("generic-vnf called fp_vnf1_under_fw-si1 called fp_vnf1_under_fw-si1 -- Schema");
+ assertNotNull(commonSearchSuggestions.getText());
+ assertNotNull(commonSearchSuggestions.getFilterValues());
+ assertNotNull(commonSearchSuggestions.toString());
+
+
+ commonSearchSuggestion.setHashId(null);
+ assertNull(commonSearchSuggestion.getHashId());
+ commonSearchSuggestion.setRoute(null);
+ assertNull(commonSearchSuggestion.getRoute());
+ commonSearchSuggestion.setText(null);
+ assertNull(commonSearchSuggestion.getText());
+ assertNull(commonSearchSuggestion.getFilterValues());
+ assertNotNull(commonSearchSuggestion.toString());
+
+ }
+
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/config/oxm/CrossEntityReferenceDescriptorTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/config/oxm/CrossEntityReferenceDescriptorTest.java
new file mode 100644
index 0000000..0b506df
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/config/oxm/CrossEntityReferenceDescriptorTest.java
@@ -0,0 +1,34 @@
+package org.onap.aai.sparky.config.oxm;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class CrossEntityReferenceDescriptorTest {
+
+ private CrossEntityReferenceDescriptor crossEntityReferenceDescriptor;
+ private CrossEntityReference crossEntityReference;
+
+ @Before
+ public void init() throws Exception {
+
+ crossEntityReference = new CrossEntityReference();
+ crossEntityReferenceDescriptor = new CrossEntityReferenceDescriptor();
+
+ }
+
+ @Test
+ public void updateValues() {
+
+ crossEntityReferenceDescriptor.setCrossEntityReference(crossEntityReference);
+ assertNotNull(crossEntityReferenceDescriptor.getCrossEntityReference());
+ crossEntityReferenceDescriptor.hasCrossEntityReferences();
+ assertFalse(crossEntityReferenceDescriptor.hasCrossEntityReferences());
+ assertNotNull(crossEntityReferenceDescriptor.toString());
+
+
+ }
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/config/oxm/CrossEntityReferenceTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/config/oxm/CrossEntityReferenceTest.java
new file mode 100644
index 0000000..c403213
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/config/oxm/CrossEntityReferenceTest.java
@@ -0,0 +1,36 @@
+package org.onap.aai.sparky.config.oxm;
+
+import static org.junit.Assert.assertNotNull;
+
+import java.util.ArrayList;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class CrossEntityReferenceTest {
+
+ private CrossEntityReference crossEntityReference;
+ private ArrayList<String> refAttribute;
+
+ @Before
+ public void init() throws Exception {
+
+ crossEntityReference = new CrossEntityReference();
+ refAttribute = new ArrayList<String>();
+
+ }
+
+ @Test
+ public void updateValues() {
+
+ crossEntityReference.setTargetEntityType("");
+ assertNotNull(crossEntityReference.getTargetEntityType());
+ crossEntityReference.setReferenceAttributes(refAttribute);
+ assertNotNull(crossEntityReference.getReferenceAttributes());
+ crossEntityReference.addReferenceAttribute("");
+ assertNotNull(crossEntityReference.toString());
+
+
+ }
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/config/oxm/GeoEntityDescriptorTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/config/oxm/GeoEntityDescriptorTest.java
new file mode 100644
index 0000000..dffda5c
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/config/oxm/GeoEntityDescriptorTest.java
@@ -0,0 +1,37 @@
+package org.onap.aai.sparky.config.oxm;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class GeoEntityDescriptorTest {
+
+ private GeoEntityDescriptor geoEntityDescriptor;
+
+ @Before
+ public void init() throws Exception {
+ geoEntityDescriptor = new GeoEntityDescriptor();
+
+ }
+
+ @Test
+ public void updateValues() {
+
+ geoEntityDescriptor.setGeoLatName("");
+ assertNotNull(geoEntityDescriptor.getGeoLatName());
+ geoEntityDescriptor.setGeoLongName("");
+ assertNotNull(geoEntityDescriptor.getGeoLongName());
+ assertNotNull(geoEntityDescriptor.toString());
+ geoEntityDescriptor.setGeoLatName(null);
+ assertNull(geoEntityDescriptor.getGeoLatName());
+ geoEntityDescriptor.setGeoLongName(null);
+ assertNull(geoEntityDescriptor.getGeoLongName());
+ assertNotNull(geoEntityDescriptor.toString());
+
+
+ }
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/config/oxm/GeoOxmEntityDescriptorTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/config/oxm/GeoOxmEntityDescriptorTest.java
new file mode 100644
index 0000000..2324194
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/config/oxm/GeoOxmEntityDescriptorTest.java
@@ -0,0 +1,40 @@
+package org.onap.aai.sparky.config.oxm;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class GeoOxmEntityDescriptorTest {
+
+ private GeoOxmEntityDescriptor geoOxmEntityDescriptor;
+
+ @Before
+ public void init() throws Exception {
+ geoOxmEntityDescriptor = new GeoOxmEntityDescriptor();
+
+ }
+
+ @Test
+ public void updateValues() {
+
+ geoOxmEntityDescriptor.setGeoLatName("");
+ assertNotNull(geoOxmEntityDescriptor.getGeoLatName());
+ geoOxmEntityDescriptor.setGeoLongName("");
+ assertNotNull(geoOxmEntityDescriptor.getGeoLongName());
+ assertTrue(geoOxmEntityDescriptor.hasGeoEntity());
+ assertNotNull(geoOxmEntityDescriptor.toString());
+ geoOxmEntityDescriptor.setGeoLatName(null);
+ assertNull(geoOxmEntityDescriptor.getGeoLatName());
+ geoOxmEntityDescriptor.setGeoLongName(null);
+ assertNull(geoOxmEntityDescriptor.getGeoLongName());
+ assertFalse(geoOxmEntityDescriptor.hasGeoEntity());
+ assertNotNull(geoOxmEntityDescriptor.toString());
+
+
+ }
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/config/oxm/OxmEntityContainerLookup.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/config/oxm/OxmEntityContainerLookup.java
new file mode 100644
index 0000000..7d55e4d
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/config/oxm/OxmEntityContainerLookup.java
@@ -0,0 +1,99 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.config.oxm;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.persistence.dynamic.DynamicType;
+import org.eclipse.persistence.internal.oxm.mappings.Descriptor;
+import org.eclipse.persistence.jaxb.dynamic.DynamicJAXBContext;
+
+public class OxmEntityContainerLookup implements OxmModelProcessor {
+
+ private Collection<String> searchableEntityGroups;
+ private Collection<String> entityContainers;
+
+ public OxmEntityContainerLookup() {
+ searchableEntityGroups = new ArrayList<String>();
+ entityContainers = new ArrayList<String>();
+ }
+
+ @Override
+ public void processOxmModel(DynamicJAXBContext jaxbContext) {
+
+ @SuppressWarnings("rawtypes")
+ List<Descriptor> descriptorsList = jaxbContext.getXMLContext().getDescriptors();
+
+ for (@SuppressWarnings("rawtypes")
+ Descriptor desc : descriptorsList) {
+
+ DynamicType entity = jaxbContext.getDynamicType(desc.getAlias());
+
+ @SuppressWarnings("unchecked")
+ Map<String, String> properties = entity.getDescriptor().getProperties();
+
+ if (properties != null) {
+
+ String container = properties.get("container");
+
+ if (container != null && !entityContainers.contains(container)) {
+
+ entityContainers.add(container);
+
+ if (properties.containsKey("searchable")) {
+ if (!searchableEntityGroups.contains(container)) {
+ searchableEntityGroups.add(container);
+ }
+ }
+ }
+
+ }
+
+ }
+
+ }
+
+ public Collection<String> getSearchableEntityGroups() {
+ return searchableEntityGroups;
+ }
+
+ public void setSearchableEntityGroups(Collection<String> searchableEntityGroups) {
+ this.searchableEntityGroups = searchableEntityGroups;
+ }
+
+ public Collection<String> getEntityContainers() {
+ return entityContainers;
+ }
+
+ public void setEntityContainers(Collection<String> entityContainers) {
+ this.entityContainers = entityContainers;
+ }
+
+ public boolean isEntityContainer(String entityType) {
+ return entityContainers.contains(entityType);
+ }
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/config/oxm/OxmEntityDescriptorTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/config/oxm/OxmEntityDescriptorTest.java
new file mode 100644
index 0000000..dea5d79
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/config/oxm/OxmEntityDescriptorTest.java
@@ -0,0 +1,41 @@
+package org.onap.aai.sparky.config.oxm;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import java.util.ArrayList;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class OxmEntityDescriptorTest {
+
+ private OxmEntityDescriptor oxmEntityDescriptor;
+ private ArrayList<String> primaryKeyAttributeNames;
+
+ @Before
+ public void init() throws Exception {
+ oxmEntityDescriptor = new OxmEntityDescriptor();
+ primaryKeyAttributeNames = new ArrayList<String>();
+
+ }
+
+ @Test
+ public void updateValues() {
+
+ oxmEntityDescriptor.setEntityName("");
+ assertNotNull(oxmEntityDescriptor.getEntityName());
+ oxmEntityDescriptor.setPrimaryKeyAttributeNames(primaryKeyAttributeNames);
+ assertNotNull(oxmEntityDescriptor.getPrimaryKeyAttributeNames());
+ oxmEntityDescriptor.addPrimaryKeyName("");
+ assertNotNull(oxmEntityDescriptor.toString());
+ oxmEntityDescriptor.setEntityName(null);
+ assertNull(oxmEntityDescriptor.getEntityName());
+ oxmEntityDescriptor.setPrimaryKeyAttributeNames(null);
+ assertNull(oxmEntityDescriptor.getPrimaryKeyAttributeNames());
+ assertNotNull(oxmEntityDescriptor.toString());
+
+
+ }
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/crossentityreference/sync/CrossEntityReferenceSynchronizerTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/crossentityreference/sync/CrossEntityReferenceSynchronizerTest.java
new file mode 100644
index 0000000..c6c999a
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/crossentityreference/sync/CrossEntityReferenceSynchronizerTest.java
@@ -0,0 +1,1035 @@
+package org.onap.aai.sparky.crossentityreference.sync;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.hamcrest.Matcher;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Matchers;
+import org.mockito.Mockito;
+import org.onap.aai.restclient.client.OperationResult;
+import org.onap.aai.sparky.config.oxm.CrossEntityReferenceLookup;
+import org.onap.aai.sparky.config.oxm.OxmEntityDescriptor;
+import org.onap.aai.sparky.config.oxm.OxmEntityLookup;
+import org.onap.aai.sparky.config.oxm.OxmModelLoader;
+import org.onap.aai.sparky.config.oxm.OxmModelProcessor;
+import org.onap.aai.sparky.config.oxm.SearchableEntityLookup;
+import org.onap.aai.sparky.dal.ActiveInventoryAdapter;
+import org.onap.aai.sparky.dal.ElasticSearchAdapter;
+import org.onap.aai.sparky.dal.rest.config.RestEndpointConfig;
+import org.onap.aai.sparky.sync.config.ElasticSearchSchemaConfig;
+import org.onap.aai.sparky.sync.config.NetworkStatisticsConfig;
+import org.onap.aai.sparky.sync.enumeration.OperationState;
+import org.onap.aai.sparky.util.StringCollectionContainsMatcher;
+import org.onap.aai.sparky.util.TestResourceLoader;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+public class CrossEntityReferenceSynchronizerTest {
+
+ private static ObjectMapper mapper = new ObjectMapper();
+
+ private CrossEntityReferenceSynchronizer cerSynchronizer;
+
+ private ElasticSearchSchemaConfig esSchemaConfig;
+ private NetworkStatisticsConfig aaiStatConfig;
+ private NetworkStatisticsConfig esStatConfig;
+ private OxmEntityLookup oxmEntityLookup;
+ private SearchableEntityLookup searchableEntityLookup;
+ private ElasticSearchAdapter esAdapter;
+ private ActiveInventoryAdapter aaiAdapter;
+ private CrossEntityReferenceLookup cerLookup;
+ private RestEndpointConfig aaiRestEndPointConfig;
+
+ @Before
+ public void init() throws Exception {
+
+ esSchemaConfig = new ElasticSearchSchemaConfig();
+ esSchemaConfig.setIndexDocType("default");
+ esSchemaConfig.setIndexMappingsFileName(null);
+ esSchemaConfig.setIndexName("aggregation-index-name");
+ esSchemaConfig.setIndexSettingsFileName(null);
+
+
+ aaiStatConfig = new NetworkStatisticsConfig();
+
+ aaiStatConfig.setNumSamplesPerThreadForRunningAverage(100);
+
+ aaiStatConfig.setBytesHistogramLabel("[Response Size In Bytes]");
+ aaiStatConfig.setBytesHistogramMaxYAxis(1000000L);
+ aaiStatConfig.setBytesHistogramNumBins(20);
+ aaiStatConfig.setBytesHistogramNumDecimalPoints(2);
+
+ aaiStatConfig.setQueueLengthHistogramLabel("[Queue Item Length]");
+ aaiStatConfig.setQueueLengthHistogramMaxYAxis(20000);
+ aaiStatConfig.setQueueLengthHistogramNumBins(20);
+ aaiStatConfig.setQueueLengthHistogramNumDecimalPoints(2);
+
+ aaiStatConfig.setTaskAgeHistogramLabel("[Task Age In Ms]");
+ aaiStatConfig.setTaskAgeHistogramMaxYAxis(600000L);
+ aaiStatConfig.setTaskAgeHistogramNumBins(20);
+ aaiStatConfig.setTaskAgeHistogramNumDecimalPoints(2);
+
+ aaiStatConfig.setResponseTimeHistogramLabel("[Response Time In Ms]");
+ aaiStatConfig.setResponseTimeHistogramMaxYAxis(1000L);
+ aaiStatConfig.setResponseTimeHistogramNumBins(20);
+ aaiStatConfig.setResponseTimeHistogramNumDecimalPoints(2);
+
+ aaiStatConfig.setTpsHistogramLabel("[Transactions Per Second]");
+ aaiStatConfig.setTpsHistogramMaxYAxis(100);
+ aaiStatConfig.setTpsHistogramNumBins(20);
+ aaiStatConfig.setTpsHistogramNumDecimalPoints(2);
+
+ esStatConfig = new NetworkStatisticsConfig();
+
+ esStatConfig.setNumSamplesPerThreadForRunningAverage(100);
+
+ esStatConfig.setBytesHistogramLabel("[Response Size In Bytes]");
+ esStatConfig.setBytesHistogramMaxYAxis(1000000L);
+ esStatConfig.setBytesHistogramNumBins(20);
+ esStatConfig.setBytesHistogramNumDecimalPoints(2);
+
+ esStatConfig.setQueueLengthHistogramLabel("[Queue Item Length]");
+ esStatConfig.setQueueLengthHistogramMaxYAxis(20000);
+ esStatConfig.setQueueLengthHistogramNumBins(20);
+ esStatConfig.setQueueLengthHistogramNumDecimalPoints(2);
+
+ esStatConfig.setTaskAgeHistogramLabel("[Task Age In Ms]");
+ esStatConfig.setTaskAgeHistogramMaxYAxis(600000L);
+ esStatConfig.setTaskAgeHistogramNumBins(20);
+ esStatConfig.setTaskAgeHistogramNumDecimalPoints(2);
+
+ esStatConfig.setResponseTimeHistogramLabel("[Response Time In Ms]");
+ esStatConfig.setResponseTimeHistogramMaxYAxis(10000L);
+ esStatConfig.setResponseTimeHistogramNumBins(20);
+ esStatConfig.setResponseTimeHistogramNumDecimalPoints(2);
+
+ esStatConfig.setTpsHistogramLabel("[Transactions Per Second]");
+ esStatConfig.setTpsHistogramMaxYAxis(100);
+ esStatConfig.setTpsHistogramNumBins(20);
+ esStatConfig.setTpsHistogramNumDecimalPoints(2);
+
+ oxmEntityLookup = new OxmEntityLookup();
+
+ esAdapter = Mockito.mock(ElasticSearchAdapter.class);
+ aaiAdapter = Mockito.mock(ActiveInventoryAdapter.class);
+
+
+ Set<OxmModelProcessor> processors = new HashSet<OxmModelProcessor>();
+
+ processors.add(oxmEntityLookup);
+
+
+ Map<String, OxmEntityDescriptor> oxmEntityDescriptors =
+ new HashMap<String, OxmEntityDescriptor>();
+
+ OxmEntityDescriptor genericVnfDescriptor = new OxmEntityDescriptor();
+ genericVnfDescriptor.setEntityName("generic-vnf");
+ List<String> pkeyNames = new ArrayList<String>();
+ pkeyNames.add("vnf-name");
+
+ genericVnfDescriptor.setPrimaryKeyAttributeNames(pkeyNames);
+
+ oxmEntityDescriptors.put("generic-vnf", genericVnfDescriptor);
+
+
+ oxmEntityLookup.setEntityDescriptors(oxmEntityDescriptors);
+
+ cerLookup = new CrossEntityReferenceLookup();
+ processors.add(cerLookup);
+
+ searchableEntityLookup = new SearchableEntityLookup();
+ processors.add(searchableEntityLookup);
+
+ OxmModelLoader oxmModelLoader = new OxmModelLoader(-1, processors);
+ oxmModelLoader.loadLatestOxmModel();
+
+ aaiRestEndPointConfig = new RestEndpointConfig();
+ aaiRestEndPointConfig.setNumRequestRetries(5);
+
+ Mockito.when(aaiAdapter.getEndpointConfig()).thenReturn(aaiRestEndPointConfig);
+
+ }
+
+ @Test
+ public void validateBasicConstruction() throws Exception {
+
+ cerSynchronizer = new CrossEntityReferenceSynchronizer(esSchemaConfig, 5, 5, 5, aaiStatConfig,
+ esStatConfig, cerLookup, oxmEntityLookup, searchableEntityLookup);
+
+ cerSynchronizer.setAaiAdapter(aaiAdapter);
+ cerSynchronizer.setElasticSearchAdapter(esAdapter);
+
+ assertNotNull(cerSynchronizer.getAaiAdapter());
+ assertNotNull(cerSynchronizer.getElasticSearchAdapter());
+
+ }
+
+ private Matcher<List<String>> listContainsValue(String expectedValue) {
+ return new StringCollectionContainsMatcher(expectedValue);
+ }
+
+ @Test
+ public void validateSmallSync() throws Exception {
+
+ cerSynchronizer = new CrossEntityReferenceSynchronizer(esSchemaConfig, 5, 5, 5, aaiStatConfig,
+ esStatConfig, cerLookup, oxmEntityLookup, searchableEntityLookup);
+
+ cerSynchronizer.setAaiAdapter(aaiAdapter);
+ cerSynchronizer.setElasticSearchAdapter(esAdapter);
+
+ String nodesQueryResponse = TestResourceLoader
+ .getTestResourceDataJson("/sync/aai/activeInventory_service-subscription_nodesQuery_response.json");
+
+ OperationResult entitySelfLinks = new OperationResult();
+
+ entitySelfLinks.setResultCode(200);
+ entitySelfLinks.setResult(nodesQueryResponse);
+
+ Mockito.when(aaiAdapter.getSelfLinksByEntityType("service-subscription"))
+ .thenReturn(entitySelfLinks);
+
+ Mockito
+ .when(aaiAdapter.repairSelfLink(Matchers.contains("service-subscription-1"),
+ Mockito.anyString()))
+ .thenReturn(
+ "https://server.proxy:8443/aai/v11/business/customers/customer/customer-1/service-subscriptions/service-subscription/service-subscription-1");
+
+ Mockito
+ .when(aaiAdapter.repairSelfLink(Matchers.contains("service-subscription-2"),
+ Mockito.anyString()))
+ .thenReturn(
+ "https://server.proxy:8443/aai/v11/business/customers/customer/customer-2/service-subscriptions/service-subscription/service-subscription-2");
+
+ Mockito
+ .when(
+ aaiAdapter.repairSelfLink(Matchers.contains("service-subscription-3"), Mockito.anyString()))
+ .thenReturn(
+ "https://server.proxy:8443/aai/v11/business/customers/customer/customer-3/service-subscriptions/service-subscription/service-subscription-3");
+
+ Mockito
+ .when(aaiAdapter.queryActiveInventoryWithRetries(
+ Matchers.contains("service-subscription-2"), Mockito.anyString(),
+ Mockito.anyInt()))
+ .thenReturn(new OperationResult(200, TestResourceLoader.getTestResourceDataJson(
+ "/sync/aai/service-subscription-service-subscription-2.json")));
+
+ Mockito
+ .when(aaiAdapter.queryActiveInventoryWithRetries(
+ Matchers.contains("service-subscription-1"), Mockito.anyString(),
+ Mockito.anyInt()))
+ .thenReturn(new OperationResult(200, TestResourceLoader.getTestResourceDataJson(
+ "/sync/aai/service-subscription-service-subscription-1.json")));
+
+ Mockito
+ .when(aaiAdapter.queryActiveInventoryWithRetries(Matchers.contains("service-subscription-3"),
+ Mockito.anyString(), Mockito.anyInt()))
+ .thenReturn(new OperationResult(200, TestResourceLoader
+ .getTestResourceDataJson("/sync/aai/service-subscription-service-subscription-3.json")));
+
+ Mockito
+ .when(aaiAdapter.getGenericQueryForSelfLink(Matchers.contains("service-instance"),
+ Matchers.argThat(listContainsValue("service-instance-59"))))
+ .thenReturn("https://server.proxy:8443/aai/v11/search/generic-query/service-instance-59");
+
+ Mockito
+ .when(aaiAdapter.getGenericQueryForSelfLink(Matchers.contains("service-instance"),
+ Matchers.argThat(listContainsValue("service-instance-54"))))
+ .thenReturn(
+ "https://server.proxy:8443/aai/v11/search/generic-query/service-instance-54");
+
+ Mockito
+ .when(aaiAdapter.getGenericQueryForSelfLink(Matchers.contains("service-instance"),
+ Matchers.argThat(listContainsValue("service-instance-55"))))
+ .thenReturn(
+ "https://server.proxy:8443/aai/v11/search/generic-query/service-instance-55");
+
+ Mockito
+ .when(aaiAdapter.getGenericQueryForSelfLink(Matchers.contains("service-instance"),
+ Matchers.argThat(listContainsValue("service-instance-50"))))
+ .thenReturn(
+ "https://server.proxy:8443/aai/v11/search/generic-query/service-instance-50");
+
+ Mockito
+ .when(aaiAdapter.getGenericQueryForSelfLink(Matchers.contains("service-instance"),
+ Matchers.argThat(listContainsValue("service-instance-52"))))
+ .thenReturn(
+ "https://server.proxy:8443/aai/v11/search/generic-query/service-instance-52");
+
+ Mockito
+ .when(aaiAdapter.getGenericQueryForSelfLink(Matchers.contains("service-instance"),
+ Matchers.argThat(listContainsValue("service-instance-57"))))
+ .thenReturn(
+ "https://server.proxy:8443/aai/v11/search/generic-query/service-instance-57");
+
+ Mockito
+ .when(aaiAdapter.getGenericQueryForSelfLink(Matchers.contains("service-instance"),
+ Matchers.argThat(listContainsValue("service-instance-53"))))
+ .thenReturn(
+ "https://server.proxy:8443/aai/v11/search/generic-query/service-instance-53");
+
+ Mockito
+ .when(aaiAdapter.getGenericQueryForSelfLink(Matchers.contains("service-instance"),
+ Matchers.argThat(listContainsValue("service-instance-58"))))
+ .thenReturn(
+ "https://server.proxy:8443/aai/v11/search/generic-query/service-instance-58");
+
+ Mockito
+ .when(aaiAdapter.getGenericQueryForSelfLink(Matchers.contains("service-instance"),
+ Matchers.argThat(listContainsValue("service-instance-51"))))
+ .thenReturn(
+ "https://server.proxy:8443/aai/v11/search/generic-query/service-instance-51");
+
+ Mockito
+ .when(aaiAdapter.getGenericQueryForSelfLink(Matchers.contains("service-instance"),
+ Matchers.argThat(listContainsValue("service-instance-56"))))
+ .thenReturn(
+ "https://server.proxy:8443/aai/v11/search/generic-query/service-instance-56");
+
+
+
+
+ Mockito
+ .when(aaiAdapter.queryActiveInventoryWithRetries(
+ Matchers.contains("generic-query/service-instance-59"), Mockito.anyString(),
+ Mockito.anyInt()))
+ .thenReturn(new OperationResult(200, TestResourceLoader.getTestResourceDataJson(
+ "/sync/aai/aai-traversal/generic-query/service-instance-59.json")));
+
+ Mockito
+ .when(aaiAdapter.queryActiveInventoryWithRetries(
+ Matchers.contains("generic-query/service-instance-54"), Mockito.anyString(),
+ Mockito.anyInt()))
+ .thenReturn(new OperationResult(200, TestResourceLoader.getTestResourceDataJson(
+ "/sync/aai/aai-traversal/generic-query/service-instance-54.json")));
+
+ Mockito
+ .when(aaiAdapter.queryActiveInventoryWithRetries(
+ Matchers.contains("generic-query/service-instance-55"), Mockito.anyString(),
+ Mockito.anyInt()))
+ .thenReturn(new OperationResult(200, TestResourceLoader.getTestResourceDataJson(
+ "/sync/aai/aai-traversal/generic-query/service-instance-55.json")));
+
+ Mockito
+ .when(aaiAdapter.queryActiveInventoryWithRetries(
+ Matchers.contains("generic-query/service-instance-50"), Mockito.anyString(),
+ Mockito.anyInt()))
+ .thenReturn(new OperationResult(200, TestResourceLoader.getTestResourceDataJson(
+ "/sync/aai/aai-traversal/generic-query/service-instance-50.json")));
+
+ Mockito
+ .when(aaiAdapter.queryActiveInventoryWithRetries(
+ Matchers.contains("generic-query/service-instance-52"), Mockito.anyString(),
+ Mockito.anyInt()))
+ .thenReturn(new OperationResult(200, TestResourceLoader.getTestResourceDataJson(
+ "/sync/aai/aai-traversal/generic-query/service-instance-52.json")));
+
+ Mockito
+ .when(aaiAdapter.queryActiveInventoryWithRetries(
+ Matchers.contains("generic-query/service-instance-57"), Mockito.anyString(),
+ Mockito.anyInt()))
+ .thenReturn(new OperationResult(200, TestResourceLoader.getTestResourceDataJson(
+ "/sync/aai/aai-traversal/generic-query/service-instance-57.json")));
+
+ Mockito
+ .when(aaiAdapter.queryActiveInventoryWithRetries(
+ Matchers.contains("generic-query/service-instance-53"), Mockito.anyString(),
+ Mockito.anyInt()))
+ .thenReturn(new OperationResult(200, TestResourceLoader.getTestResourceDataJson(
+ "/sync/aai/aai-traversal/generic-query/service-instance-53.json")));
+
+ Mockito
+ .when(aaiAdapter.queryActiveInventoryWithRetries(
+ Matchers.contains("generic-query/service-instance-58"), Mockito.anyString(),
+ Mockito.anyInt()))
+ .thenReturn(new OperationResult(200, TestResourceLoader.getTestResourceDataJson(
+ "/sync/aai/aai-traversal/generic-query/service-instance-58.json")));
+
+ Mockito
+ .when(aaiAdapter.queryActiveInventoryWithRetries(
+ Matchers.contains("generic-query/service-instance-51"), Mockito.anyString(),
+ Mockito.anyInt()))
+ .thenReturn(new OperationResult(200, TestResourceLoader.getTestResourceDataJson(
+ "/sync/aai/aai-traversal/generic-query/service-instance-51.json")));
+
+ Mockito
+ .when(aaiAdapter.queryActiveInventoryWithRetries(
+ Matchers.contains("generic-query/service-instance-56"), Mockito.anyString(),
+ Mockito.anyInt()))
+ .thenReturn(new OperationResult(200, TestResourceLoader.getTestResourceDataJson(
+ "/sync/aai/aai-traversal/generic-query/service-instance-56.json")));
+
+
+
+
+
+
+ /*
+
+ Mockito
+ .when(aaiAdapter.queryActiveInventoryWithRetries(
+ Matchers.contains("service-instance-59"), Mockito.anyString(),
+ Mockito.anyInt()))
+ .thenReturn(new OperationResult(200, TestResourceLoader.getTestResourceDataJson(
+ "/sync/aai/aai-resources/service-instance/service-instance-59.json")));
+
+ Mockito
+ .when(aaiAdapter.queryActiveInventoryWithRetries(
+ Matchers.contains("service-instance-54"), Mockito.anyString(),
+ Mockito.anyInt()))
+ .thenReturn(new OperationResult(200, TestResourceLoader.getTestResourceDataJson(
+ "/sync/aai/aai-resources/service-instance/service-instance-54.json")));
+
+ Mockito
+ .when(aaiAdapter.queryActiveInventoryWithRetries(
+ Matchers.contains("service-instance-55"), Mockito.anyString(),
+ Mockito.anyInt()))
+ .thenReturn(new OperationResult(200, TestResourceLoader.getTestResourceDataJson(
+ "/sync/aai/aai-resources/service-instance/service-instance-55.json")));
+
+ Mockito
+ .when(aaiAdapter.queryActiveInventoryWithRetries(
+ Matchers.contains("service-instance-50"), Mockito.anyString(),
+ Mockito.anyInt()))
+ .thenReturn(new OperationResult(200, TestResourceLoader.getTestResourceDataJson(
+ "/sync/aai/aai-resources/service-instance/service-instance-50.json")));
+
+ Mockito
+ .when(aaiAdapter.queryActiveInventoryWithRetries(
+ Matchers.contains("service-instance-52"), Mockito.anyString(),
+ Mockito.anyInt()))
+ .thenReturn(new OperationResult(200, TestResourceLoader.getTestResourceDataJson(
+ "/sync/aai/aai-resources/service-instance/service-instance-52.json")));
+
+ Mockito
+ .when(aaiAdapter.queryActiveInventoryWithRetries(
+ Matchers.contains("service-instance-57"), Mockito.anyString(),
+ Mockito.anyInt()))
+ .thenReturn(new OperationResult(200, TestResourceLoader.getTestResourceDataJson(
+ "/sync/aai/aai-resources/service-instance/service-instance-57.json")));
+
+ Mockito
+ .when(aaiAdapter.queryActiveInventoryWithRetries(
+ Matchers.contains("service-instance-53"), Mockito.anyString(),
+ Mockito.anyInt()))
+ .thenReturn(new OperationResult(200, TestResourceLoader.getTestResourceDataJson(
+ "/sync/aai/aai-resources/service-instance/service-instance-53.json")));
+
+ Mockito
+ .when(aaiAdapter.queryActiveInventoryWithRetries(
+ Matchers.contains("service-instance-58"), Mockito.anyString(),
+ Mockito.anyInt()))
+ .thenReturn(new OperationResult(200, TestResourceLoader.getTestResourceDataJson(
+ "/sync/aai/aai-resources/service-instance/service-instance-58.json")));
+
+ Mockito
+ .when(aaiAdapter.queryActiveInventoryWithRetries(
+ Matchers.contains("service-instance-51"), Mockito.anyString(),
+ Mockito.anyInt()))
+ .thenReturn(new OperationResult(200, TestResourceLoader.getTestResourceDataJson(
+ "/sync/aai/aai-resources/service-instance/service-instance-51.json")));
+
+ Mockito
+ .when(aaiAdapter.queryActiveInventoryWithRetries(
+ Matchers.contains("service-instance-56"), Mockito.anyString(),
+ Mockito.anyInt()))
+ .thenReturn(new OperationResult(200, TestResourceLoader.getTestResourceDataJson(
+ "/sync/aai/aai-resources/service-instance/service-instance-56.json")));
+
+
+ */
+
+
+
+
+ Mockito.when(esAdapter.buildElasticSearchGetDocUrl(Mockito.anyString(), Mockito.anyString()))
+ .thenReturn("http://localhost:9200/myindex/mytype/doc1",
+ "http://localhost:9200/myindex/mytype/doc2",
+ "http://localhost:9200/myindex/mytype/doc3");
+
+ /*
+ * Our initial gets from elastic search should be record-not-found
+ */
+ Mockito.when(esAdapter.doGet(Matchers.contains("doc1"), Mockito.any()))
+ .thenReturn(new OperationResult(404, null));
+ Mockito.when(esAdapter.doGet(Matchers.contains("doc2"), Mockito.any()))
+ .thenReturn(new OperationResult(404, null));
+ Mockito.when(esAdapter.doGet(Matchers.contains("doc3"), Mockito.any()))
+ .thenReturn(new OperationResult(404, null));
+
+
+ Mockito.when(esAdapter.doPut(Matchers.contains("doc"), Mockito.any(), Mockito.any()))
+ .thenReturn(new OperationResult(200, null));
+
+ OperationState syncState = cerSynchronizer.doSync();
+ assertEquals(OperationState.OK, syncState);
+
+ assertNotNull(cerSynchronizer.getStatReport(false));
+ assertNotNull(cerSynchronizer.getStatReport(true));
+
+ cerSynchronizer.clearCache();
+ cerSynchronizer.shutdown();
+
+
+ }
+
+ @Test
+ public void validateSmallSyncWithRetries() throws Exception {
+
+ cerSynchronizer = new CrossEntityReferenceSynchronizer(esSchemaConfig, 5, 5, 5, aaiStatConfig,
+ esStatConfig, cerLookup, oxmEntityLookup, searchableEntityLookup);
+
+ cerSynchronizer.setAaiAdapter(aaiAdapter);
+ cerSynchronizer.setElasticSearchAdapter(esAdapter);
+
+ String nodesQueryResponse = TestResourceLoader
+ .getTestResourceDataJson("/sync/aai/activeInventory_service-subscription_nodesQuery_response.json");
+
+ OperationResult entitySelfLinks = new OperationResult();
+
+ entitySelfLinks.setResultCode(200);
+ entitySelfLinks.setResult(nodesQueryResponse);
+
+ Mockito.when(aaiAdapter.getSelfLinksByEntityType("service-subscription"))
+ .thenReturn(entitySelfLinks);
+
+ Mockito
+ .when(aaiAdapter.repairSelfLink(Matchers.contains("service-subscription-1"),
+ Mockito.anyString()))
+ .thenReturn(
+ "https://server.proxy:8443/aai/v11/business/customers/customer/customer-1/service-subscriptions/service-subscription/service-subscription-1");
+
+ Mockito
+ .when(aaiAdapter.repairSelfLink(Matchers.contains("service-subscription-2"),
+ Mockito.anyString()))
+ .thenReturn(
+ "https://server.proxy:8443/aai/v11/business/customers/customer/customer-2/service-subscriptions/service-subscription/service-subscription-2");
+
+ Mockito
+ .when(
+ aaiAdapter.repairSelfLink(Matchers.contains("service-subscription-3"), Mockito.anyString()))
+ .thenReturn(
+ "https://server.proxy:8443/aai/v11/business/customers/customer/customer-3/service-subscriptions/service-subscription/service-subscription-3");
+
+ Mockito
+ .when(aaiAdapter.queryActiveInventoryWithRetries(
+ Matchers.contains("service-subscription-2"), Mockito.anyString(),
+ Mockito.anyInt()))
+ .thenReturn(new OperationResult(200, TestResourceLoader.getTestResourceDataJson(
+ "/sync/aai/service-subscription-service-subscription-2.json")));
+
+ Mockito
+ .when(aaiAdapter.queryActiveInventoryWithRetries(
+ Matchers.contains("service-subscription-1"), Mockito.anyString(),
+ Mockito.anyInt()))
+ .thenReturn(new OperationResult(200, TestResourceLoader.getTestResourceDataJson(
+ "/sync/aai/service-subscription-service-subscription-1.json")));
+
+ Mockito
+ .when(aaiAdapter.queryActiveInventoryWithRetries(Matchers.contains("service-subscription-3"),
+ Mockito.anyString(), Mockito.anyInt()))
+ .thenReturn(new OperationResult(200, TestResourceLoader
+ .getTestResourceDataJson("/sync/aai/service-subscription-service-subscription-3.json")));
+
+ Mockito
+ .when(aaiAdapter.getGenericQueryForSelfLink(Matchers.contains("service-instance"),
+ Matchers.argThat(listContainsValue("service-instance-59"))))
+ .thenReturn("https://server.proxy:8443/aai/v11/search/generic-query/service-instance-59");
+
+ Mockito
+ .when(aaiAdapter.getGenericQueryForSelfLink(Matchers.contains("service-instance"),
+ Matchers.argThat(listContainsValue("service-instance-54"))))
+ .thenReturn(
+ "https://server.proxy:8443/aai/v11/search/generic-query/service-instance-54");
+
+ Mockito
+ .when(aaiAdapter.getGenericQueryForSelfLink(Matchers.contains("service-instance"),
+ Matchers.argThat(listContainsValue("service-instance-55"))))
+ .thenReturn(
+ "https://server.proxy:8443/aai/v11/search/generic-query/service-instance-55");
+
+ Mockito
+ .when(aaiAdapter.getGenericQueryForSelfLink(Matchers.contains("service-instance"),
+ Matchers.argThat(listContainsValue("service-instance-50"))))
+ .thenReturn(
+ "https://server.proxy:8443/aai/v11/search/generic-query/service-instance-50");
+
+ Mockito
+ .when(aaiAdapter.getGenericQueryForSelfLink(Matchers.contains("service-instance"),
+ Matchers.argThat(listContainsValue("service-instance-52"))))
+ .thenReturn(
+ "https://server.proxy:8443/aai/v11/search/generic-query/service-instance-52");
+
+ Mockito
+ .when(aaiAdapter.getGenericQueryForSelfLink(Matchers.contains("service-instance"),
+ Matchers.argThat(listContainsValue("service-instance-57"))))
+ .thenReturn(
+ "https://server.proxy:8443/aai/v11/search/generic-query/service-instance-57");
+
+ Mockito
+ .when(aaiAdapter.getGenericQueryForSelfLink(Matchers.contains("service-instance"),
+ Matchers.argThat(listContainsValue("service-instance-53"))))
+ .thenReturn(
+ "https://server.proxy:8443/aai/v11/search/generic-query/service-instance-53");
+
+ Mockito
+ .when(aaiAdapter.getGenericQueryForSelfLink(Matchers.contains("service-instance"),
+ Matchers.argThat(listContainsValue("service-instance-58"))))
+ .thenReturn(
+ "https://server.proxy:8443/aai/v11/search/generic-query/service-instance-58");
+
+ Mockito
+ .when(aaiAdapter.getGenericQueryForSelfLink(Matchers.contains("service-instance"),
+ Matchers.argThat(listContainsValue("service-instance-51"))))
+ .thenReturn(
+ "https://server.proxy:8443/aai/v11/search/generic-query/service-instance-51");
+
+ Mockito
+ .when(aaiAdapter.getGenericQueryForSelfLink(Matchers.contains("service-instance"),
+ Matchers.argThat(listContainsValue("service-instance-56"))))
+ .thenReturn(
+ "https://server.proxy:8443/aai/v11/search/generic-query/service-instance-56");
+
+
+
+
+ Mockito
+ .when(aaiAdapter.queryActiveInventoryWithRetries(
+ Matchers.contains("generic-query/service-instance-59"), Mockito.anyString(),
+ Mockito.anyInt()))
+ .thenReturn(new OperationResult(200, TestResourceLoader.getTestResourceDataJson(
+ "/sync/aai/aai-traversal/generic-query/service-instance-59.json")));
+
+ Mockito
+ .when(aaiAdapter.queryActiveInventoryWithRetries(
+ Matchers.contains("generic-query/service-instance-54"), Mockito.anyString(),
+ Mockito.anyInt()))
+ .thenReturn(new OperationResult(200, TestResourceLoader.getTestResourceDataJson(
+ "/sync/aai/aai-traversal/generic-query/service-instance-54.json")));
+
+ Mockito
+ .when(aaiAdapter.queryActiveInventoryWithRetries(
+ Matchers.contains("generic-query/service-instance-55"), Mockito.anyString(),
+ Mockito.anyInt()))
+ .thenReturn(new OperationResult(200, TestResourceLoader.getTestResourceDataJson(
+ "/sync/aai/aai-traversal/generic-query/service-instance-55.json")));
+
+ Mockito
+ .when(aaiAdapter.queryActiveInventoryWithRetries(
+ Matchers.contains("generic-query/service-instance-50"), Mockito.anyString(),
+ Mockito.anyInt()))
+ .thenReturn(new OperationResult(200, TestResourceLoader.getTestResourceDataJson(
+ "/sync/aai/aai-traversal/generic-query/service-instance-50.json")));
+
+ Mockito
+ .when(aaiAdapter.queryActiveInventoryWithRetries(
+ Matchers.contains("generic-query/service-instance-52"), Mockito.anyString(),
+ Mockito.anyInt()))
+ .thenReturn(new OperationResult(200, TestResourceLoader.getTestResourceDataJson(
+ "/sync/aai/aai-traversal/generic-query/service-instance-52.json")));
+
+ Mockito
+ .when(aaiAdapter.queryActiveInventoryWithRetries(
+ Matchers.contains("generic-query/service-instance-57"), Mockito.anyString(),
+ Mockito.anyInt()))
+ .thenReturn(new OperationResult(200, TestResourceLoader.getTestResourceDataJson(
+ "/sync/aai/aai-traversal/generic-query/service-instance-57.json")));
+
+ Mockito
+ .when(aaiAdapter.queryActiveInventoryWithRetries(
+ Matchers.contains("generic-query/service-instance-53"), Mockito.anyString(),
+ Mockito.anyInt()))
+ .thenReturn(new OperationResult(200, TestResourceLoader.getTestResourceDataJson(
+ "/sync/aai/aai-traversal/generic-query/service-instance-53.json")));
+
+ Mockito
+ .when(aaiAdapter.queryActiveInventoryWithRetries(
+ Matchers.contains("generic-query/service-instance-58"), Mockito.anyString(),
+ Mockito.anyInt()))
+ .thenReturn(new OperationResult(200, TestResourceLoader.getTestResourceDataJson(
+ "/sync/aai/aai-traversal/generic-query/service-instance-58.json")));
+
+ Mockito
+ .when(aaiAdapter.queryActiveInventoryWithRetries(
+ Matchers.contains("generic-query/service-instance-51"), Mockito.anyString(),
+ Mockito.anyInt()))
+ .thenReturn(new OperationResult(200, TestResourceLoader.getTestResourceDataJson(
+ "/sync/aai/aai-traversal/generic-query/service-instance-51.json")));
+
+ Mockito
+ .when(aaiAdapter.queryActiveInventoryWithRetries(
+ Matchers.contains("generic-query/service-instance-56"), Mockito.anyString(),
+ Mockito.anyInt()))
+ .thenReturn(new OperationResult(200, TestResourceLoader.getTestResourceDataJson(
+ "/sync/aai/aai-traversal/generic-query/service-instance-56.json")));
+
+
+
+
+
+
+ /*
+
+ Mockito
+ .when(aaiAdapter.queryActiveInventoryWithRetries(
+ Matchers.contains("service-instance-59"), Mockito.anyString(),
+ Mockito.anyInt()))
+ .thenReturn(new OperationResult(200, TestResourceLoader.getTestResourceDataJson(
+ "/sync/aai/aai-resources/service-instance/service-instance-59.json")));
+
+ Mockito
+ .when(aaiAdapter.queryActiveInventoryWithRetries(
+ Matchers.contains("service-instance-54"), Mockito.anyString(),
+ Mockito.anyInt()))
+ .thenReturn(new OperationResult(200, TestResourceLoader.getTestResourceDataJson(
+ "/sync/aai/aai-resources/service-instance/service-instance-54.json")));
+
+ Mockito
+ .when(aaiAdapter.queryActiveInventoryWithRetries(
+ Matchers.contains("service-instance-55"), Mockito.anyString(),
+ Mockito.anyInt()))
+ .thenReturn(new OperationResult(200, TestResourceLoader.getTestResourceDataJson(
+ "/sync/aai/aai-resources/service-instance/service-instance-55.json")));
+
+ Mockito
+ .when(aaiAdapter.queryActiveInventoryWithRetries(
+ Matchers.contains("service-instance-50"), Mockito.anyString(),
+ Mockito.anyInt()))
+ .thenReturn(new OperationResult(200, TestResourceLoader.getTestResourceDataJson(
+ "/sync/aai/aai-resources/service-instance/service-instance-50.json")));
+
+ Mockito
+ .when(aaiAdapter.queryActiveInventoryWithRetries(
+ Matchers.contains("service-instance-52"), Mockito.anyString(),
+ Mockito.anyInt()))
+ .thenReturn(new OperationResult(200, TestResourceLoader.getTestResourceDataJson(
+ "/sync/aai/aai-resources/service-instance/service-instance-52.json")));
+
+ Mockito
+ .when(aaiAdapter.queryActiveInventoryWithRetries(
+ Matchers.contains("service-instance-57"), Mockito.anyString(),
+ Mockito.anyInt()))
+ .thenReturn(new OperationResult(200, TestResourceLoader.getTestResourceDataJson(
+ "/sync/aai/aai-resources/service-instance/service-instance-57.json")));
+
+ Mockito
+ .when(aaiAdapter.queryActiveInventoryWithRetries(
+ Matchers.contains("service-instance-53"), Mockito.anyString(),
+ Mockito.anyInt()))
+ .thenReturn(new OperationResult(200, TestResourceLoader.getTestResourceDataJson(
+ "/sync/aai/aai-resources/service-instance/service-instance-53.json")));
+
+ Mockito
+ .when(aaiAdapter.queryActiveInventoryWithRetries(
+ Matchers.contains("service-instance-58"), Mockito.anyString(),
+ Mockito.anyInt()))
+ .thenReturn(new OperationResult(200, TestResourceLoader.getTestResourceDataJson(
+ "/sync/aai/aai-resources/service-instance/service-instance-58.json")));
+
+ Mockito
+ .when(aaiAdapter.queryActiveInventoryWithRetries(
+ Matchers.contains("service-instance-51"), Mockito.anyString(),
+ Mockito.anyInt()))
+ .thenReturn(new OperationResult(200, TestResourceLoader.getTestResourceDataJson(
+ "/sync/aai/aai-resources/service-instance/service-instance-51.json")));
+
+ Mockito
+ .when(aaiAdapter.queryActiveInventoryWithRetries(
+ Matchers.contains("service-instance-56"), Mockito.anyString(),
+ Mockito.anyInt()))
+ .thenReturn(new OperationResult(200, TestResourceLoader.getTestResourceDataJson(
+ "/sync/aai/aai-resources/service-instance/service-instance-56.json")));
+
+
+ */
+
+
+
+
+ Mockito.when(esAdapter.buildElasticSearchGetDocUrl(Mockito.anyString(), Mockito.anyString()))
+ .thenReturn("http://localhost:9200/myindex/mytype/doc1",
+ "http://localhost:9200/myindex/mytype/doc2",
+ "http://localhost:9200/myindex/mytype/doc3");
+
+ /*
+ * Our initial gets from elastic search should be record-not-found
+ */
+ Mockito.when(esAdapter.doGet(Matchers.contains("doc1"), Mockito.any()))
+ .thenReturn(new OperationResult(404, null));
+ Mockito.when(esAdapter.doGet(Matchers.contains("doc2"), Mockito.any()))
+ .thenReturn(new OperationResult(404, null));
+ Mockito.when(esAdapter.doGet(Matchers.contains("doc3"), Mockito.any()))
+ .thenReturn(new OperationResult(404, null));
+
+
+ /*
+ * Cause version conflict errors on every put to test retry flow
+ */
+
+ Mockito.when(esAdapter.doPut(Matchers.contains("doc"), Mockito.any(), Mockito.any()))
+ .thenReturn(new OperationResult(409, null));
+
+ OperationState syncState = cerSynchronizer.doSync();
+ assertEquals(OperationState.OK, syncState);
+
+ assertNotNull(cerSynchronizer.getStatReport(false));
+ assertNotNull(cerSynchronizer.getStatReport(true));
+
+ cerSynchronizer.clearCache();
+ cerSynchronizer.shutdown();
+
+
+
+
+ }
+
+
+
+ @Test
+ public void validateSmallSyncWithEntityMerges() throws Exception {
+
+ cerSynchronizer = new CrossEntityReferenceSynchronizer(esSchemaConfig, 5, 5, 5, aaiStatConfig,
+ esStatConfig, cerLookup, oxmEntityLookup, searchableEntityLookup);
+
+ cerSynchronizer.setAaiAdapter(aaiAdapter);
+ cerSynchronizer.setElasticSearchAdapter(esAdapter);
+
+ String nodesQueryResponse = TestResourceLoader
+ .getTestResourceDataJson("/sync/aai/activeInventory_service-subscription_nodesQuery_response.json");
+
+ OperationResult entitySelfLinks = new OperationResult();
+
+ entitySelfLinks.setResultCode(200);
+ entitySelfLinks.setResult(nodesQueryResponse);
+
+ Mockito.when(aaiAdapter.getSelfLinksByEntityType("service-subscription"))
+ .thenReturn(entitySelfLinks);
+
+ Mockito
+ .when(aaiAdapter.repairSelfLink(Matchers.contains("service-subscription-1"),
+ Mockito.anyString()))
+ .thenReturn(
+ "https://server.proxy:8443/aai/v11/business/customers/customer/customer-1/service-subscriptions/service-subscription/service-subscription-1");
+
+ Mockito
+ .when(aaiAdapter.repairSelfLink(Matchers.contains("service-subscription-2"),
+ Mockito.anyString()))
+ .thenReturn(
+ "https://server.proxy:8443/aai/v11/business/customers/customer/customer-2/service-subscriptions/service-subscription/service-subscription-2");
+
+ Mockito
+ .when(
+ aaiAdapter.repairSelfLink(Matchers.contains("service-subscription-3"), Mockito.anyString()))
+ .thenReturn(
+ "https://server.proxy:8443/aai/v11/business/customers/customer/customer-3/service-subscriptions/service-subscription/service-subscription-3");
+
+ Mockito
+ .when(aaiAdapter.queryActiveInventoryWithRetries(
+ Matchers.contains("service-subscription-2"), Mockito.anyString(),
+ Mockito.anyInt()))
+ .thenReturn(new OperationResult(200, TestResourceLoader.getTestResourceDataJson(
+ "/sync/aai/service-subscription-service-subscription-2.json")));
+
+ Mockito
+ .when(aaiAdapter.queryActiveInventoryWithRetries(
+ Matchers.contains("service-subscription-1"), Mockito.anyString(),
+ Mockito.anyInt()))
+ .thenReturn(new OperationResult(200, TestResourceLoader.getTestResourceDataJson(
+ "/sync/aai/service-subscription-service-subscription-1.json")));
+
+ Mockito
+ .when(aaiAdapter.queryActiveInventoryWithRetries(Matchers.contains("service-subscription-3"),
+ Mockito.anyString(), Mockito.anyInt()))
+ .thenReturn(new OperationResult(200, TestResourceLoader
+ .getTestResourceDataJson("/sync/aai/service-subscription-service-subscription-3.json")));
+
+ Mockito
+ .when(aaiAdapter.getGenericQueryForSelfLink(Matchers.contains("service-instance"),
+ Matchers.argThat(listContainsValue("service-instance-59"))))
+ .thenReturn("https://server.proxy:8443/aai/v11/search/generic-query/service-instance-59");
+
+ Mockito
+ .when(aaiAdapter.getGenericQueryForSelfLink(Matchers.contains("service-instance"),
+ Matchers.argThat(listContainsValue("service-instance-54"))))
+ .thenReturn(
+ "https://server.proxy:8443/aai/v11/search/generic-query/service-instance-54");
+
+ Mockito
+ .when(aaiAdapter.getGenericQueryForSelfLink(Matchers.contains("service-instance"),
+ Matchers.argThat(listContainsValue("service-instance-55"))))
+ .thenReturn(
+ "https://server.proxy:8443/aai/v11/search/generic-query/service-instance-55");
+
+ Mockito
+ .when(aaiAdapter.getGenericQueryForSelfLink(Matchers.contains("service-instance"),
+ Matchers.argThat(listContainsValue("service-instance-50"))))
+ .thenReturn(
+ "https://server.proxy:8443/aai/v11/search/generic-query/service-instance-50");
+
+ Mockito
+ .when(aaiAdapter.getGenericQueryForSelfLink(Matchers.contains("service-instance"),
+ Matchers.argThat(listContainsValue("service-instance-52"))))
+ .thenReturn(
+ "https://server.proxy:8443/aai/v11/search/generic-query/service-instance-52");
+
+ Mockito
+ .when(aaiAdapter.getGenericQueryForSelfLink(Matchers.contains("service-instance"),
+ Matchers.argThat(listContainsValue("service-instance-57"))))
+ .thenReturn(
+ "https://server.proxy:8443/aai/v11/search/generic-query/service-instance-57");
+
+ Mockito
+ .when(aaiAdapter.getGenericQueryForSelfLink(Matchers.contains("service-instance"),
+ Matchers.argThat(listContainsValue("service-instance-53"))))
+ .thenReturn(
+ "https://server.proxy:8443/aai/v11/search/generic-query/service-instance-53");
+
+ Mockito
+ .when(aaiAdapter.getGenericQueryForSelfLink(Matchers.contains("service-instance"),
+ Matchers.argThat(listContainsValue("service-instance-58"))))
+ .thenReturn(
+ "https://server.proxy:8443/aai/v11/search/generic-query/service-instance-58");
+
+ Mockito
+ .when(aaiAdapter.getGenericQueryForSelfLink(Matchers.contains("service-instance"),
+ Matchers.argThat(listContainsValue("service-instance-51"))))
+ .thenReturn(
+ "https://server.proxy:8443/aai/v11/search/generic-query/service-instance-51");
+
+ Mockito
+ .when(aaiAdapter.getGenericQueryForSelfLink(Matchers.contains("service-instance"),
+ Matchers.argThat(listContainsValue("service-instance-56"))))
+ .thenReturn(
+ "https://server.proxy:8443/aai/v11/search/generic-query/service-instance-56");
+
+
+
+
+ Mockito
+ .when(aaiAdapter.queryActiveInventoryWithRetries(
+ Matchers.contains("generic-query/service-instance-59"), Mockito.anyString(),
+ Mockito.anyInt()))
+ .thenReturn(new OperationResult(200, TestResourceLoader.getTestResourceDataJson(
+ "/sync/aai/aai-traversal/generic-query/service-instance-59.json")));
+
+ Mockito
+ .when(aaiAdapter.queryActiveInventoryWithRetries(
+ Matchers.contains("generic-query/service-instance-54"), Mockito.anyString(),
+ Mockito.anyInt()))
+ .thenReturn(new OperationResult(200, TestResourceLoader.getTestResourceDataJson(
+ "/sync/aai/aai-traversal/generic-query/service-instance-54.json")));
+
+ Mockito
+ .when(aaiAdapter.queryActiveInventoryWithRetries(
+ Matchers.contains("generic-query/service-instance-55"), Mockito.anyString(),
+ Mockito.anyInt()))
+ .thenReturn(new OperationResult(200, TestResourceLoader.getTestResourceDataJson(
+ "/sync/aai/aai-traversal/generic-query/service-instance-55.json")));
+
+ Mockito
+ .when(aaiAdapter.queryActiveInventoryWithRetries(
+ Matchers.contains("generic-query/service-instance-50"), Mockito.anyString(),
+ Mockito.anyInt()))
+ .thenReturn(new OperationResult(200, TestResourceLoader.getTestResourceDataJson(
+ "/sync/aai/aai-traversal/generic-query/service-instance-50.json")));
+
+ Mockito
+ .when(aaiAdapter.queryActiveInventoryWithRetries(
+ Matchers.contains("generic-query/service-instance-52"), Mockito.anyString(),
+ Mockito.anyInt()))
+ .thenReturn(new OperationResult(200, TestResourceLoader.getTestResourceDataJson(
+ "/sync/aai/aai-traversal/generic-query/service-instance-52.json")));
+
+ Mockito
+ .when(aaiAdapter.queryActiveInventoryWithRetries(
+ Matchers.contains("generic-query/service-instance-57"), Mockito.anyString(),
+ Mockito.anyInt()))
+ .thenReturn(new OperationResult(200, TestResourceLoader.getTestResourceDataJson(
+ "/sync/aai/aai-traversal/generic-query/service-instance-57.json")));
+
+ Mockito
+ .when(aaiAdapter.queryActiveInventoryWithRetries(
+ Matchers.contains("generic-query/service-instance-53"), Mockito.anyString(),
+ Mockito.anyInt()))
+ .thenReturn(new OperationResult(200, TestResourceLoader.getTestResourceDataJson(
+ "/sync/aai/aai-traversal/generic-query/service-instance-53.json")));
+
+ Mockito
+ .when(aaiAdapter.queryActiveInventoryWithRetries(
+ Matchers.contains("generic-query/service-instance-58"), Mockito.anyString(),
+ Mockito.anyInt()))
+ .thenReturn(new OperationResult(200, TestResourceLoader.getTestResourceDataJson(
+ "/sync/aai/aai-traversal/generic-query/service-instance-58.json")));
+
+ Mockito
+ .when(aaiAdapter.queryActiveInventoryWithRetries(
+ Matchers.contains("generic-query/service-instance-51"), Mockito.anyString(),
+ Mockito.anyInt()))
+ .thenReturn(new OperationResult(200, TestResourceLoader.getTestResourceDataJson(
+ "/sync/aai/aai-traversal/generic-query/service-instance-51.json")));
+
+ Mockito
+ .when(aaiAdapter.queryActiveInventoryWithRetries(
+ Matchers.contains("generic-query/service-instance-56"), Mockito.anyString(),
+ Mockito.anyInt()))
+ .thenReturn(new OperationResult(200, TestResourceLoader.getTestResourceDataJson(
+ "/sync/aai/aai-traversal/generic-query/service-instance-56.json")));
+
+
+ Mockito.when(esAdapter.buildElasticSearchGetDocUrl(Mockito.anyString(), Mockito.anyString()))
+ .thenReturn("http://localhost:9200/myindex/mytype/doc1",
+ "http://localhost:9200/myindex/mytype/doc2",
+ "http://localhost:9200/myindex/mytype/doc3");
+
+ /*
+ * Our initial gets from elastic search return 200 ok with a found entity document requiring a doc update
+ */
+ Mockito.when(esAdapter.doGet(Matchers.contains("doc1"), Mockito.any())).thenReturn(new OperationResult(200,
+ TestResourceLoader.getTestResourceDataJson("/sync/ElasticSearch/docEntityFromElasticSearch1.json")));
+
+ Mockito.when(esAdapter.doGet(Matchers.contains("doc2"), Mockito.any())).thenReturn(new OperationResult(200,
+ TestResourceLoader.getTestResourceDataJson("/sync/ElasticSearch/docEntityFromElasticSearch2.json")));
+
+ Mockito.when(esAdapter.doGet(Matchers.contains("doc3"), Mockito.any())).thenReturn(new OperationResult(200,
+ TestResourceLoader.getTestResourceDataJson("/sync/ElasticSearch/docEntityFromElasticSearch3.json")));
+
+ Mockito.when(esAdapter.doGet(Matchers.contains("doc4"), Mockito.any())).thenReturn(new OperationResult(200,
+ TestResourceLoader.getTestResourceDataJson("/sync/ElasticSearch/docEntityFromElasticSearch4.json")));
+
+ Mockito.when(esAdapter.doGet(Matchers.contains("doc5"), Mockito.any())).thenReturn(new OperationResult(200,
+ TestResourceLoader.getTestResourceDataJson("/sync/ElasticSearch/docEntityFromElasticSearch5.json")));
+
+ Mockito.when(esAdapter.doPut(Matchers.contains("doc"), Mockito.any(), Mockito.any()))
+ .thenReturn(new OperationResult(200, null));
+
+
+
+ Mockito.when(esAdapter.doPut(Matchers.contains("doc"), Mockito.any(), Mockito.any()))
+ .thenReturn(new OperationResult(200, null));
+
+ OperationState syncState = cerSynchronizer.doSync();
+ assertEquals(OperationState.OK, syncState);
+
+ assertNotNull(cerSynchronizer.getStatReport(false));
+ assertNotNull(cerSynchronizer.getStatReport(true));
+
+ cerSynchronizer.clearCache();
+ cerSynchronizer.shutdown();
+
+
+
+
+ }
+
+
+
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/ActiveInventoryAdapterTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/ActiveInventoryAdapterTest.java
new file mode 100644
index 0000000..1273e80
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/ActiveInventoryAdapterTest.java
@@ -0,0 +1,63 @@
+package org.onap.aai.sparky.dal;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import java.util.ArrayList;
+
+
+import org.junit.Before;
+import org.junit.Test;
+import org.onap.aai.restclient.enums.RestAuthenticationMode;
+import org.onap.aai.sparky.config.oxm.OxmEntityLookup;
+import org.onap.aai.sparky.config.oxm.OxmModelLoader;
+import org.onap.aai.sparky.dal.rest.config.RestEndpointConfig;
+
+public class ActiveInventoryAdapterTest {
+
+ private OxmModelLoader oxmModelLoader;
+ private OxmEntityLookup oxmEntityLookup;
+ private RestEndpointConfig endpointConfig;
+ private ActiveInventoryAdapter aaiAdapter;
+ private ArrayList<String> queryParams;
+
+ @Before
+ public void init() throws Exception {
+
+ oxmModelLoader = new OxmModelLoader();
+ oxmEntityLookup = new OxmEntityLookup();
+ endpointConfig = new RestEndpointConfig();
+ queryParams = new ArrayList<String>();
+ endpointConfig.setRestAuthenticationMode(RestAuthenticationMode.SSL_BASIC);
+ aaiAdapter = new ActiveInventoryAdapter(oxmModelLoader,oxmEntityLookup,endpointConfig);
+ }
+
+
+ @SuppressWarnings("static-access")
+ @Test
+ public void updateValues()throws Exception {
+
+ assertNotNull(aaiAdapter.getMessageHeaders());
+ assertNotNull(aaiAdapter.getBasicAuthenticationCredentials());
+ assertNotNull(aaiAdapter.getResourceBasePath());
+ assertNotNull(aaiAdapter.extractResourcePath(""));
+ assertNotNull(aaiAdapter.getGenericQueryForSelfLink("",queryParams));
+ assertNull(aaiAdapter.getSelfLinkForEntity("","",""));
+ assertNotNull(aaiAdapter.queryActiveInventory("",""));
+ assertNotNull(aaiAdapter.queryActiveInventoryWithRetries("","",4));
+ aaiAdapter.setOxmEntityLookup(oxmEntityLookup);
+ assertNotNull(aaiAdapter.getOxmEntityLookup());
+ aaiAdapter.setEndpointConfig(endpointConfig);
+ assertNotNull(aaiAdapter.getEndpointConfig());
+
+ //assertNull(aaiAdapter.repairSelfLink("",""));
+ //assertNotNull(aaiAdapter.repairSelfLink(null,""));
+ //assertNotNull(aaiAdapter.getSelfLinkForEntity(null,"",""));
+ //assertNull(aaiAdapter.getSelfLinkForEntity("",null,""));
+ //assertNotNull(aaiAdapter.getSelfLinkForEntity("","",null));
+ //assertNotNull(aaiAdapter.getSelfLinksByEntityType(""));
+ //assertNotNull(aaiAdapter.getSelfLinksByEntityType(null));
+ }
+
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/ElasticSearchAdapterTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/ElasticSearchAdapterTest.java
new file mode 100644
index 0000000..84fc515
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/ElasticSearchAdapterTest.java
@@ -0,0 +1,50 @@
+package org.onap.aai.sparky.dal;
+
+import static org.junit.Assert.assertNotNull;
+
+import javax.ws.rs.core.MediaType;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.onap.aai.restclient.enums.RestAuthenticationMode;
+import org.onap.aai.sparky.dal.rest.config.RestEndpointConfig;
+import org.onap.aai.sparky.dal.ElasticSearchAdapter;
+
+public class ElasticSearchAdapterTest {
+
+
+ private ElasticSearchAdapter elasticSearchAdapter;
+ private RestEndpointConfig endpointConfig;
+
+ @Before
+ public void init() throws Exception {
+
+ endpointConfig = new RestEndpointConfig();
+ endpointConfig.setRestAuthenticationMode(RestAuthenticationMode.SSL_BASIC);
+ elasticSearchAdapter = new ElasticSearchAdapter(endpointConfig);
+ }
+
+
+ @Test
+ public void updateValues() {
+
+ assertNotNull(elasticSearchAdapter.doPost("https://10.247.40.25:8000","{maxResults:10, queryStr: f}",MediaType.APPLICATION_JSON_TYPE));
+ assertNotNull(elasticSearchAdapter.doGet("https://10.247.40.25:8000",MediaType.APPLICATION_JSON_TYPE));
+ assertNotNull(elasticSearchAdapter.doHead("https://10.247.40.25:8000",MediaType.APPLICATION_JSON_TYPE));
+ assertNotNull(elasticSearchAdapter.doPut("https://10.247.40.25:8000","{maxResults:10, queryStr: f}",MediaType.APPLICATION_JSON_TYPE));
+ assertNotNull(elasticSearchAdapter.doPatch("https://10.247.40.25:8000","{maxResults:10, queryStr: f}",MediaType.APPLICATION_JSON_TYPE));
+ assertNotNull(elasticSearchAdapter.doDelete("https://10.247.40.25:8000",MediaType.APPLICATION_JSON_TYPE));
+ assertNotNull(elasticSearchAdapter.doBulkOperation("https://10.247.40.25:8000","{maxResults:10, queryStr: f}"));
+ assertNotNull(elasticSearchAdapter.buildBulkImportOperationRequest("","","","",""));
+ assertNotNull(elasticSearchAdapter.retrieveEntityById("","","","",""));
+ assertNotNull(elasticSearchAdapter.buildElasticSearchUrlForApi("",""));
+ assertNotNull(elasticSearchAdapter.buildElasticSearchUrl("",""));
+ assertNotNull(elasticSearchAdapter.buildElasticSearchGetDocUrl("","",""));
+ assertNotNull(elasticSearchAdapter.buildElasticSearchGetDocUrl("",""));
+ assertNotNull(elasticSearchAdapter.buildElasticSearchPostUrl(""));
+ assertNotNull(elasticSearchAdapter.getBulkUrl());
+
+ }
+
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/NetworkTransactionTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/NetworkTransactionTest.java
new file mode 100644
index 0000000..3852a8f
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/NetworkTransactionTest.java
@@ -0,0 +1,59 @@
+package org.onap.aai.sparky.dal;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.ArrayList;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.onap.aai.restclient.client.OperationResult;
+import org.onap.aai.sparky.config.oxm.OxmEntityDescriptor;
+import org.onap.aai.sparky.dal.rest.HttpMethod;
+
+public class NetworkTransactionTest {
+
+
+ private NetworkTransaction networkTransaction;
+ private NetworkTransaction networkTransactions;
+ private OxmEntityDescriptor descriptor;
+ private OperationResult opResult;
+
+ @Before
+ public void init() throws Exception {
+ opResult = new OperationResult();
+ descriptor = new OxmEntityDescriptor();
+ networkTransaction = new NetworkTransaction();
+ networkTransactions = new NetworkTransaction(HttpMethod.POST,"",opResult);
+
+
+
+ }
+
+
+ @Test
+ public void updateValues() {
+
+ networkTransaction.setOperationResult(opResult);
+ assertNotNull(networkTransaction.getOperationResult());
+ networkTransaction.setOperationType(HttpMethod.PUT);
+ assertNotNull(networkTransaction.getOperationType());
+ networkTransaction.setTaskAgeInMs();
+ assertNotNull(networkTransaction.getTaskAgeInMs());
+ networkTransaction.setEntityType("searchedNodeClass");
+ assertNotNull(networkTransaction.getEntityType());
+ networkTransaction.setLink("/etc/aaiEntityNodeDescriptors.json");
+ assertNotNull(networkTransaction.getLink());
+ networkTransaction.setQueryParameters("/etc/aaiEntityNodeDescriptors.json");
+ assertNotNull(networkTransaction.getQueryParameters());
+ networkTransaction.setDescriptor(descriptor);
+ assertNotNull(networkTransaction.getDescriptor());
+ networkTransaction.setOpTimeInMs(3);
+ assertEquals(3,networkTransaction.getOpTimeInMs());
+ assertNotNull(networkTransaction.toString());
+
+ }
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/elasticsearch/entity/AutoSuggestDocumentEntity.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/elasticsearch/entity/AutoSuggestDocumentEntity.java
new file mode 100644
index 0000000..d01a98e
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/elasticsearch/entity/AutoSuggestDocumentEntity.java
@@ -0,0 +1,44 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.dal.elasticsearch.entity;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+public class AutoSuggestDocumentEntity {
+
+ @JsonProperty("entity_suggest")
+ AutoSuggestDocumentEntityFields fields;
+
+ public AutoSuggestDocumentEntityFields getFields() {
+ return fields;
+ }
+
+ public void setFields(AutoSuggestDocumentEntityFields fields) {
+ this.fields = fields;
+ }
+
+
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/elasticsearch/entity/AutoSuggestDocumentEntityFields.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/elasticsearch/entity/AutoSuggestDocumentEntityFields.java
new file mode 100644
index 0000000..a4b7370
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/elasticsearch/entity/AutoSuggestDocumentEntityFields.java
@@ -0,0 +1,81 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.dal.elasticsearch.entity;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonInclude.Include;
+
+@JsonInclude(Include.NON_NULL)
+public class AutoSuggestDocumentEntityFields {
+
+ private String output;
+ private List<String> input;
+ private PayloadEntity payload;
+ private int weight;
+
+ public AutoSuggestDocumentEntityFields() {
+ input = new ArrayList<String>();
+ }
+
+ public String getOutput() {
+ return output;
+ }
+
+ public void setOutput(String output) {
+ this.output = output;
+ }
+
+ public List<String> getInput() {
+ return input;
+ }
+
+ public void setInput(List<String> input) {
+ this.input = input;
+ }
+
+ public PayloadEntity getPayload() {
+ return payload;
+ }
+
+ public void setPayload(PayloadEntity payload) {
+ this.payload = payload;
+ }
+
+ public int getWeight() {
+ return weight;
+ }
+
+ public void setWeight(int weight) {
+ this.weight = weight;
+ }
+
+ public void addInput(String input) {
+ this.input.add(input);
+ }
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/elasticsearch/entity/AutoSuggestElasticHitEntity.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/elasticsearch/entity/AutoSuggestElasticHitEntity.java
new file mode 100644
index 0000000..33ad604
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/elasticsearch/entity/AutoSuggestElasticHitEntity.java
@@ -0,0 +1,87 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.dal.elasticsearch.entity;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+public class AutoSuggestElasticHitEntity {
+
+ @JsonProperty("_index")
+ private String index;
+
+ @JsonProperty("_type")
+ private String type;
+
+ @JsonProperty("_id")
+ private String id;
+
+ @JsonProperty("_score")
+ private String score;
+
+ @JsonProperty("_source")
+ private AutoSuggestDocumentEntity source;
+
+ public String getIndex() {
+ return index;
+ }
+
+ public void setIndex(String index) {
+ this.index = index;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public String getScore() {
+ return score;
+ }
+
+ public void setScore(String score) {
+ this.score = score;
+ }
+
+ public AutoSuggestDocumentEntity getSource() {
+ return source;
+ }
+
+ public void setSource(AutoSuggestDocumentEntity source) {
+ this.source = source;
+ }
+
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/elasticsearch/entity/AutoSuggestElasticHitsEntity.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/elasticsearch/entity/AutoSuggestElasticHitsEntity.java
new file mode 100644
index 0000000..7efe4a4
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/elasticsearch/entity/AutoSuggestElasticHitsEntity.java
@@ -0,0 +1,50 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.dal.elasticsearch.entity;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class AutoSuggestElasticHitsEntity {
+
+ private List<AutoSuggestElasticHitEntity> hits;
+
+ public AutoSuggestElasticHitsEntity() {
+ hits = new ArrayList<AutoSuggestElasticHitEntity>();
+ }
+
+ public List<AutoSuggestElasticHitEntity> getHits() {
+ return hits;
+ }
+
+ public void setHits(List<AutoSuggestElasticHitEntity> hits) {
+ this.hits = hits;
+ }
+
+ public void addHit(AutoSuggestElasticHitEntity hit) {
+ this.hits.add(hit);
+ }
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/elasticsearch/entity/AutoSuggestElasticSearchResponse.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/elasticsearch/entity/AutoSuggestElasticSearchResponse.java
new file mode 100644
index 0000000..1b096cd
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/elasticsearch/entity/AutoSuggestElasticSearchResponse.java
@@ -0,0 +1,85 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.dal.elasticsearch.entity;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+public class AutoSuggestElasticSearchResponse {
+
+ private int took;
+
+ @JsonProperty("timed_out")
+ private boolean timedOut;
+
+ @JsonProperty("_shards")
+ private Map<String,String> shards;
+
+ private AutoSuggestElasticHitsEntity hits;
+
+ public AutoSuggestElasticSearchResponse(){
+ this.shards = new HashMap<String,String>();
+ }
+
+ public int getTook() {
+ return took;
+ }
+
+ public void setTook(int took) {
+ this.took = took;
+ }
+
+ public boolean isTimedOut() {
+ return timedOut;
+ }
+
+ public void setTimedOut(boolean timedOut) {
+ this.timedOut = timedOut;
+ }
+
+ public Map<String, String> getShards() {
+ return shards;
+ }
+
+ public void setShards(Map<String, String> shards) {
+ this.shards = shards;
+ }
+
+ public void addShard(String name, String value) {
+ shards.put(name, value);
+ }
+
+ public AutoSuggestElasticHitsEntity getHits() {
+ return hits;
+ }
+
+ public void setHits(AutoSuggestElasticHitsEntity hits) {
+ this.hits = hits;
+ }
+
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/elasticsearch/entity/BucketEntity.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/elasticsearch/entity/BucketEntity.java
new file mode 100644
index 0000000..69285a2
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/elasticsearch/entity/BucketEntity.java
@@ -0,0 +1,61 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.dal.elasticsearch.entity;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+public class BucketEntity {
+ private String key;
+
+ @JsonProperty("doc_count")
+ private int docCount;
+
+ public BucketEntity() {
+
+ }
+
+ public BucketEntity(String name, int value) {
+ this.key = name;
+ this.docCount = value;
+ }
+
+ public String getKey() {
+ return key;
+ }
+
+ public void setKey(String key) {
+ this.key = key;
+ }
+
+ public int getDocCount() {
+ return docCount;
+ }
+
+ public void setDocCount(int docCount) {
+ this.docCount = docCount;
+ }
+
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/elasticsearch/entity/ElasticHit.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/elasticsearch/entity/ElasticHit.java
new file mode 100644
index 0000000..e9409af
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/elasticsearch/entity/ElasticHit.java
@@ -0,0 +1,29 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.dal.elasticsearch.entity;
+
+public class ElasticHit {
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/elasticsearch/entity/ElasticHitsEntity.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/elasticsearch/entity/ElasticHitsEntity.java
new file mode 100644
index 0000000..a5a71b8
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/elasticsearch/entity/ElasticHitsEntity.java
@@ -0,0 +1,74 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.dal.elasticsearch.entity;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+public class ElasticHitsEntity {
+
+ private int total;
+ @JsonProperty("max_score")
+ private int maxScore;
+
+ private List<ElasticHit> hits;
+
+ public ElasticHitsEntity() {
+ this.hits = new ArrayList<ElasticHit>();
+ }
+
+ public void addHit(ElasticHit hit) {
+ this.hits.add(hit);
+ }
+
+ public int getTotal() {
+ return total;
+ }
+
+ public void setTotal(int total) {
+ this.total = total;
+ }
+
+ public int getMaxScore() {
+ return maxScore;
+ }
+
+ public void setMaxScore(int maxScore) {
+ this.maxScore = maxScore;
+ }
+
+ public List<ElasticHit> getHits() {
+ return hits;
+ }
+
+ public void setHits(List<ElasticHit> hits) {
+ this.hits = hits;
+ }
+
+
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/elasticsearch/entity/ElasticSearchAggegrationResponse.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/elasticsearch/entity/ElasticSearchAggegrationResponse.java
new file mode 100644
index 0000000..8e1b5f1
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/elasticsearch/entity/ElasticSearchAggegrationResponse.java
@@ -0,0 +1,109 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.dal.elasticsearch.entity;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+public class ElasticSearchAggegrationResponse {
+
+ private int took;
+
+ @JsonProperty("timed_out")
+ private boolean timedOut;
+
+ @JsonProperty("_shards")
+ private Map<String, String> shards;
+
+ private ElasticHitsEntity hits;
+
+ private Map<String, ElasticSearchAggregation> aggregations;
+
+ public ElasticSearchAggegrationResponse() {
+ this.shards = new HashMap<String, String>();
+ this.aggregations = new HashMap<String,ElasticSearchAggregation>();
+ }
+
+
+ public int getTook() {
+ return took;
+ }
+
+
+ public void setTook(int took) {
+ this.took = took;
+ }
+
+
+ public boolean isTimedOut() {
+ return timedOut;
+ }
+
+
+ public void setTimedOut(boolean timedOut) {
+ this.timedOut = timedOut;
+ }
+
+
+ public Map<String, String> getShards() {
+ return shards;
+ }
+
+
+ public void setShards(Map<String, String> shards) {
+ this.shards = shards;
+ }
+
+
+ public ElasticHitsEntity getHits() {
+ return hits;
+ }
+
+
+ public void setHits(ElasticHitsEntity hits) {
+ this.hits = hits;
+ }
+
+ public void addShard(String key, String value) {
+ this.shards.put(key,value);
+ }
+
+
+ public Map<String, ElasticSearchAggregation> getAggregations() {
+ return aggregations;
+ }
+
+
+ public void setAggregations(Map<String, ElasticSearchAggregation> aggregations) {
+ this.aggregations = aggregations;
+ }
+
+ public void addAggregation(String key, ElasticSearchAggregation agg) {
+ this.aggregations.put(key, agg);
+ }
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/elasticsearch/entity/ElasticSearchAggregation.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/elasticsearch/entity/ElasticSearchAggregation.java
new file mode 100644
index 0000000..a7d9ce7
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/elasticsearch/entity/ElasticSearchAggregation.java
@@ -0,0 +1,74 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.dal.elasticsearch.entity;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+public class ElasticSearchAggregation {
+
+ @JsonProperty("doc_count_error_upper_bound")
+ private int docCountErrorUpperBound;
+
+ @JsonProperty("sum_other_doc_count")
+ private int sumOtherDocCount;
+
+ private List<BucketEntity> buckets;
+
+ public ElasticSearchAggregation() {
+ buckets = new ArrayList<BucketEntity>();
+ }
+
+ public int getDocCountErrorUpperBound() {
+ return docCountErrorUpperBound;
+ }
+
+ public void setDocCountErrorUpperBound(int docCountErrorUpperBound) {
+ this.docCountErrorUpperBound = docCountErrorUpperBound;
+ }
+
+ public int getSumOtherDocCount() {
+ return sumOtherDocCount;
+ }
+
+ public void setSumOtherDocCount(int sumOtherDocCount) {
+ this.sumOtherDocCount = sumOtherDocCount;
+ }
+
+ public List<BucketEntity> getBuckets() {
+ return buckets;
+ }
+
+ public void setBuckets(List<BucketEntity> buckets) {
+ this.buckets = buckets;
+ }
+
+ public void addBucket(BucketEntity bucket) {
+ buckets.add(bucket);
+ }
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/elasticsearch/entity/ElasticSearchCountResponse.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/elasticsearch/entity/ElasticSearchCountResponse.java
new file mode 100644
index 0000000..0d165f3
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/elasticsearch/entity/ElasticSearchCountResponse.java
@@ -0,0 +1,60 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.dal.elasticsearch.entity;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class ElasticSearchCountResponse {
+
+ private int count;
+ private Map<String, String> shards;
+
+ public ElasticSearchCountResponse() {
+ this.shards = new HashMap<String,String>();
+ }
+
+ public int getCount() {
+ return count;
+ }
+
+ public void setCount(int count) {
+ this.count = count;
+ }
+
+ public Map<String, String> getShards() {
+ return shards;
+ }
+
+ public void setShards(Map<String, String> shards) {
+ this.shards = shards;
+ }
+
+ public void addShard(String key, String value) {
+ this.shards.put(key, value);
+ }
+
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/elasticsearch/entity/PayloadEntity.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/elasticsearch/entity/PayloadEntity.java
new file mode 100644
index 0000000..a74ac0f
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/elasticsearch/entity/PayloadEntity.java
@@ -0,0 +1,32 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.dal.elasticsearch.entity;
+
+public class PayloadEntity {
+
+ public PayloadEntity() {
+ }
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/proxy/processor/AaiUiProxyProcessorTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/proxy/processor/AaiUiProxyProcessorTest.java
new file mode 100644
index 0000000..e710338
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/proxy/processor/AaiUiProxyProcessorTest.java
@@ -0,0 +1,145 @@
+/**
+ * ============LICENSE_START=======================================================
+ * SPARKY (AAI UI service)
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.dal.proxy.processor;
+
+import static org.junit.Assert.assertEquals;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.core.MediaType;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.Message;
+import org.json.JSONObject;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.AdditionalMatchers;
+import org.mockito.Matchers;
+import org.mockito.Mockito;
+import org.onap.aai.restclient.client.OperationResult;
+import org.onap.aai.restclient.client.RestClient;
+import org.onap.aai.restclient.enums.RestAuthenticationMode;
+import org.onap.aai.sparky.dal.rest.RestClientConstructionException;
+import org.onap.aai.sparky.dal.rest.config.RestEndpointConfig;
+import org.restlet.data.Status;
+
+public class AaiUiProxyProcessorTest {
+
+ private RestClient client = null;
+ private OperationResult successResult = null;
+ OperationResult failureResult = null;
+ private Exchange mockExchange;
+ private Message mockRequestMessage;
+ private Message mockResponseMessage;
+
+ private HttpServletRequest mockHttpServletRequest;
+
+ private AaiUiProxyProcessor aaiUiProxyProcessor;
+
+ private String goodBeTargetUrl = "https://0.0.0.0:8000/services/routerService/servicegraph";
+ private String badBeTargetUrl = "https://0.0.0.0:8000/aservicegraph";
+ private String goodDrTargetUrl = "https://0.0.0.0:9502/ui-request/servicegraph";
+
+ String successResponsePayload = "good-payload";
+ String failureResponsePayload = "Server Error";
+
+ @Before
+ public void init()throws RestClientConstructionException {
+ client = Mockito.mock(RestClient.class);
+ mockExchange = Mockito.mock(Exchange.class);
+ mockRequestMessage = Mockito.mock(Message.class);
+ mockResponseMessage = Mockito.mock(Message.class);
+ mockHttpServletRequest = Mockito.mock(HttpServletRequest.class);
+
+
+ RestEndpointConfig config = new RestEndpointConfig();
+ config.setRestAuthenticationMode(RestAuthenticationMode.SSL_BASIC);
+ aaiUiProxyProcessor = new AaiUiProxyProcessor(config,"ui-request");
+
+ initializeMocks(getProxyRequestJson("someHashValue"));
+ aaiUiProxyProcessor.setClient(client);
+ }
+
+ @Test
+ public void testProxyMessage_successPath() {
+ OperationResult successResultSpy = Mockito.spy(successResult);
+ Mockito.when(client.post(Mockito.eq(goodDrTargetUrl), Mockito.anyString(), Mockito.anyMap(),
+ Mockito.eq(MediaType.APPLICATION_JSON_TYPE), Mockito.eq(MediaType.APPLICATION_JSON_TYPE)))
+ .thenReturn(successResultSpy);
+
+ Mockito.when(mockExchange.getIn().getHeader(Exchange.HTTP_URI)).thenReturn(goodBeTargetUrl);
+ Mockito.when(mockExchange.getIn().getBody(HttpServletRequest.class)).thenReturn(mockHttpServletRequest);
+ aaiUiProxyProcessor.proxyMessage(mockExchange);
+
+ //Mockito.verify(successResultSpy).getResult();
+ //assertEquals(Status.SUCCESS_OK.getCode(), aaiUiProxyProcessor.getOperationResult().getResultCode());
+ }
+
+ @Test
+ public void testProxyMessage_failurePath() {
+ OperationResult failureResultSpy = Mockito.spy(failureResult);
+ Mockito.when(client.post(AdditionalMatchers.not(Matchers.eq(goodDrTargetUrl)),
+ Mockito.anyString(), Mockito.anyMap(), Mockito.eq(MediaType.APPLICATION_JSON_TYPE),
+ Mockito.eq(MediaType.APPLICATION_JSON_TYPE))).thenReturn(failureResultSpy);
+
+ Mockito.when(mockExchange.getIn().getHeader(Exchange.HTTP_URI)).thenReturn(badBeTargetUrl);
+ Mockito.when(mockExchange.getIn().getBody(HttpServletRequest.class)).thenReturn(mockHttpServletRequest);
+ aaiUiProxyProcessor.proxyMessage(mockExchange);
+
+ Mockito.verify(failureResultSpy).getFailureCause();
+ assertEquals(Status.SERVER_ERROR_INTERNAL.getCode(), aaiUiProxyProcessor.getOperationResult().getResultCode());
+ }
+
+ private String getProxyRequestJson(String hashId) {
+ JSONObject root = new JSONObject();
+ root.put("hashId", hashId);
+ return root.toString();
+
+ }
+
+ @SuppressWarnings("unchecked")
+ private void initializeMocks(String requestPayload) {
+
+ client = Mockito.mock(RestClient.class);
+ successResult = new OperationResult(200, successResponsePayload);
+ failureResult = new OperationResult(500, failureResponsePayload);
+ failureResult.setFailureCause(failureResponsePayload);
+
+ Mockito.when(client.post(Mockito.eq(goodDrTargetUrl), Mockito.anyString(), Mockito.anyMap(),
+ Mockito.eq(MediaType.APPLICATION_JSON_TYPE), Mockito.eq(MediaType.APPLICATION_JSON_TYPE)))
+ .thenReturn(successResult);
+
+ Mockito.when(client.post(AdditionalMatchers.not(Matchers.eq(goodDrTargetUrl)),
+ Mockito.anyString(), Mockito.anyMap(), Mockito.eq(MediaType.APPLICATION_JSON_TYPE),
+ Mockito.eq(MediaType.APPLICATION_JSON_TYPE))).thenReturn(failureResult);
+
+ Mockito.when(mockHttpServletRequest.getRequestURI()).thenReturn("fakeUri");
+ Mockito.when(mockHttpServletRequest.getLocalPort()).thenReturn(8001);
+
+ Mockito.when(mockExchange.getIn()).thenReturn(mockRequestMessage);
+ Mockito.when(mockExchange.getOut()).thenReturn(mockResponseMessage);
+ }
+
+}
+
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/rest/config/RestEndpointConfigTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/rest/config/RestEndpointConfigTest.java
new file mode 100644
index 0000000..eb1e3f8
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/rest/config/RestEndpointConfigTest.java
@@ -0,0 +1,76 @@
+package org.onap.aai.sparky.dal.rest.config;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import org.onap.aai.restclient.enums.RestAuthenticationMode;
+
+public class RestEndpointConfigTest {
+
+ private RestEndpointConfig restEndpointConfig;
+ @Before
+ public void init() throws Exception{
+
+ restEndpointConfig = new RestEndpointConfig();
+
+
+ }
+
+ @Test
+ public void updateValues(){
+ restEndpointConfig.setValidateServerCertChain(true);
+ assertTrue(restEndpointConfig.isValidateServerCertChain());
+ restEndpointConfig.setValidateServerHostname(true);
+ assertTrue(restEndpointConfig.isValidateServerHostname());
+ restEndpointConfig.setEndpointIpAddress("10.147.110.199");
+ assertNotNull(restEndpointConfig.getEndpointIpAddress());
+ restEndpointConfig.setEndpointServerPort("9885");
+ assertNotNull(restEndpointConfig.getEndpointServerPort());
+ restEndpointConfig.setNumRequestRetries(5);
+ assertEquals(restEndpointConfig.getNumRequestRetries(),5);
+ restEndpointConfig.setBasicAuthUserName("sparky");
+ assertNotNull(restEndpointConfig.getBasicAuthUserName());
+ restEndpointConfig.setBasicAuthPassword("sparky");
+ assertNotNull(restEndpointConfig.getBasicAuthPassword());
+ restEndpointConfig.setRestAuthenticationMode(RestAuthenticationMode.SSL_BASIC);
+ assertEquals(restEndpointConfig.getRestAuthenticationMode(),RestAuthenticationMode.SSL_BASIC);
+ restEndpointConfig.setConnectTimeoutInMs(6000);
+ assertEquals(restEndpointConfig.getConnectTimeoutInMs(),6000);
+ restEndpointConfig.setCertFileName("aai-client-cert.p12");
+ assertNotNull(restEndpointConfig.getCertFileName());
+ restEndpointConfig.setReadTimeoutInMs(4000);
+ assertEquals(restEndpointConfig.getReadTimeoutInMs(),4000);
+ restEndpointConfig.setCertPassword("1i9a1u2a1unz1lr61wn51wn11lss1unz1u301i6o");
+ assertNotNull(restEndpointConfig.getCertPassword());
+ restEndpointConfig.setTruststoreFileName("synchronizer.jks");
+ assertNotNull(restEndpointConfig.getTruststoreFileName());
+ assertNotNull(restEndpointConfig.toString());
+
+ restEndpointConfig.setEndpointIpAddress(null);
+ assertNull(restEndpointConfig.getEndpointIpAddress());
+ restEndpointConfig.setEndpointServerPort(null);
+ assertNull(restEndpointConfig.getEndpointServerPort());
+ restEndpointConfig.setCertFileName(null);
+ assertNull(restEndpointConfig.getCertFileName());
+ restEndpointConfig.setTruststoreFileName(null);
+ assertNull(restEndpointConfig.getTruststoreFileName());
+ restEndpointConfig.setRestAuthenticationMode(null);
+ assertNull(restEndpointConfig.getRestAuthenticationMode());
+ restEndpointConfig.setCertPassword(null);
+ assertNull(restEndpointConfig.getCertPassword());
+ restEndpointConfig.setBasicAuthUserName(null);
+ assertNull(restEndpointConfig.getBasicAuthUserName());
+ restEndpointConfig.setBasicAuthPassword(null);
+ assertNull(restEndpointConfig.getBasicAuthPassword());
+ assertNotNull(restEndpointConfig.toString());
+
+
+
+ }
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/sas/config/SearchServiceConfigTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/sas/config/SearchServiceConfigTest.java
new file mode 100644
index 0000000..712ae30
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/sas/config/SearchServiceConfigTest.java
@@ -0,0 +1,21 @@
+package org.onap.aai.sparky.dal.sas.config;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class SearchServiceConfigTest {
+
+ @Before
+ public void init() throws Exception{
+
+ }
+
+ @Test
+ public void updateValues(){
+
+ }
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/sas/entity/DocumentEntity.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/sas/entity/DocumentEntity.java
new file mode 100644
index 0000000..b9349a9
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/sas/entity/DocumentEntity.java
@@ -0,0 +1,68 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.dal.sas.entity;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class DocumentEntity {
+ private String etag;
+ private String url;
+ private Map<String,String> content;
+
+ public DocumentEntity() {
+ content = new HashMap<String,String>();
+ }
+
+
+ public String getEtag() {
+ return etag;
+ }
+
+ public void setEtag(String etag) {
+ this.etag = etag;
+ }
+
+ public String getUrl() {
+ return url;
+ }
+
+ public void setUrl(String url) {
+ this.url = url;
+ }
+
+ public Map<String, String> getContent() {
+ return content;
+ }
+
+ public void setContent(Map<String, String> content) {
+ this.content = content;
+ }
+
+ public void addContent(String key, String value) {
+ content.put(key, value);
+ }
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/sas/entity/EntityCountResponse.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/sas/entity/EntityCountResponse.java
new file mode 100644
index 0000000..20002d2
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/sas/entity/EntityCountResponse.java
@@ -0,0 +1,55 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.dal.sas.entity;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class EntityCountResponse {
+
+ private Map<String,String> shards;
+ private int count;
+
+ public EntityCountResponse() {
+ this.shards = new HashMap<String,String>();
+ }
+
+ public Map<String, String> getShards() {
+ return shards;
+ }
+
+ public void setShards(Map<String, String> shards) {
+ this.shards = shards;
+ }
+
+ public int getCount() {
+ return count;
+ }
+
+ public void setCount(int count) {
+ this.count = count;
+ }
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/sas/entity/GroupByAggregationEntity.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/sas/entity/GroupByAggregationEntity.java
new file mode 100644
index 0000000..4a3bbf4
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/sas/entity/GroupByAggregationEntity.java
@@ -0,0 +1,60 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.dal.sas.entity;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.onap.aai.sparky.dal.elasticsearch.entity.BucketEntity;
+
+public class GroupByAggregationEntity {
+ private int totalChartHits;
+ List<BucketEntity> buckets;
+
+ public GroupByAggregationEntity() {
+ this.buckets = new ArrayList<BucketEntity>();
+ }
+
+ public int getTotalChartHits() {
+ return totalChartHits;
+ }
+
+ public void setTotalChartHits(int totalChartHits) {
+ this.totalChartHits = totalChartHits;
+ }
+
+ public List<BucketEntity> getBuckets() {
+ return buckets;
+ }
+
+ public void setBuckets(List<BucketEntity> buckets) {
+ this.buckets = buckets;
+ }
+
+ public void addBucket(BucketEntity bucket) {
+ this.buckets.add(bucket);
+ }
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/sas/entity/GroupByAggregationResponseEntity.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/sas/entity/GroupByAggregationResponseEntity.java
new file mode 100644
index 0000000..fd2e17d
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/sas/entity/GroupByAggregationResponseEntity.java
@@ -0,0 +1,48 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.dal.sas.entity;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+public class GroupByAggregationResponseEntity {
+
+ @JsonProperty("groupby_aggregation")
+ private GroupByAggregationEntity aggEntity;
+
+ public GroupByAggregationResponseEntity() {
+
+ }
+
+ public GroupByAggregationEntity getAggEntity() {
+ return aggEntity;
+ }
+
+ public void setAggEntity(GroupByAggregationEntity aggEntity) {
+ this.aggEntity = aggEntity;
+ }
+
+
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/sas/entity/HitEntity.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/sas/entity/HitEntity.java
new file mode 100644
index 0000000..73b2d12
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/sas/entity/HitEntity.java
@@ -0,0 +1,48 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.dal.sas.entity;
+
+public class HitEntity {
+
+ private String score;
+ private DocumentEntity document;
+
+ public String getScore() {
+ return score;
+ }
+
+ public void setScore(String score) {
+ this.score = score;
+ }
+
+ public DocumentEntity getDocument() {
+ return document;
+ }
+
+ public void setDocument(DocumentEntity document) {
+ this.document = document;
+ }
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/sas/entity/SearchAbstractionEntityBuilder.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/sas/entity/SearchAbstractionEntityBuilder.java
new file mode 100644
index 0000000..88dff42
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/sas/entity/SearchAbstractionEntityBuilder.java
@@ -0,0 +1,294 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.dal.sas.entity;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class SearchAbstractionEntityBuilder {
+
+
+ public static HitEntity getHitSample1() {
+
+ HitEntity hitEntity = new HitEntity();
+ DocumentEntity doc = new DocumentEntity();
+
+ hitEntity.setDocument(doc);
+ hitEntity.setScore("17.073963");
+
+ doc.addContent("entityPrimaryKeyValue", "example-vnf-id-val-4394");
+ doc.addContent("entityType", "vpe");
+ doc.addContent("searchTags", "example-vnf-id-val-4394;example-vnf-name-val-4394;example-vnf-name2-val-4394");
+ doc.addContent("link", "https://ext1.test.onap.com:8443/aai/v9/network/vpes/vpe/example-vnf-id-val-4394");
+ doc.addContent("searchTagIDs", "0;1;2");
+ doc.addContent("lastmodTimestamp", "2017-04-18T17:20:48.072-0400");
+
+ doc.setUrl("services/search-data-service/v1/search/indexes/entitysearchindex-localhost-ist-apr18/documents/e317a35256717f10e88d1b2c995efcdddfc911bf350c73e37e8afca6dfb11553");
+ doc.setEtag("1");
+
+
+ return hitEntity;
+
+ }
+
+ public static HitEntity getHitSample2() {
+
+ HitEntity hitEntity = new HitEntity();
+ DocumentEntity doc = new DocumentEntity();
+
+ hitEntity.setDocument(doc);
+ hitEntity.setScore("17.073963");
+
+ doc.addContent("entityPrimaryKeyValue", "vpe-vnf-id-team4-11");
+ doc.addContent("entityType", "vpe");
+ doc.addContent("searchTags", "vpe-vnf-id-team4-11;example-vnf-name-val-9512;example-vnf-name2-val-9512");
+ doc.addContent("link", "https://ext1.test.onap.com:8443/aai/v9/network/vpes/vpe/vpe-vnf-id-team4-11");
+ doc.addContent("searchTagIDs", "0;1;2");
+ doc.addContent("lastmodTimestamp", "2017-04-18T17:20:48.175-0400");
+
+ doc.setUrl("services/search-data-service/v1/search/indexes/entitysearchindex-localhost-ist-apr18/documents/80f6d1a252e047e50e0adbeb90ad30876bb5b63cf70c9dd53f3fe46aeb50c74b");
+ doc.setEtag("1");
+
+
+ return hitEntity;
+
+ }
+
+ public static HitEntity getHitSample3() {
+
+ HitEntity hitEntity = new HitEntity();
+ DocumentEntity doc = new DocumentEntity();
+
+ hitEntity.setDocument(doc);
+ hitEntity.setScore("17.030035");
+
+ doc.addContent("entityPrimaryKeyValue", "example-vnf-id-val-6176");
+ doc.addContent("entityType", "generic-vnf");
+ doc.addContent("searchTags", "example-vnf-id-val-6176;example-vnf-name-val-6176;example-vnf-name2-val-6176");
+ doc.addContent("link", "https://ext1.test.onap.com:8443/aai/v9/network/generic-vnfs/generic-vnf/example-vnf-id-val-6176");
+ doc.addContent("searchTagIDs", "0;1;2");
+ doc.addContent("lastmodTimestamp", "2017-04-18T17:29:39.889-0400");
+
+ doc.setUrl("services/search-data-service/v1/search/indexes/entitysearchindex-localhost-ist-apr18/documents/8dfd1136f943296508fee11efcda35a0719aa490aa60e9abffecce0b220d8c94");
+ doc.setEtag("1");
+
+
+ return hitEntity;
+
+ }
+
+ public static HitEntity getHitSample4() {
+
+ HitEntity hitEntity = new HitEntity();
+ DocumentEntity doc = new DocumentEntity();
+
+ hitEntity.setDocument(doc);
+ hitEntity.setScore("17.01174");
+
+ doc.addContent("entityPrimaryKeyValue", "vnf-id-team4-11");
+ doc.addContent("entityType", "newvce");
+ doc.addContent("searchTags", "vnf-id-team4-11;example-vnf-name-val-5313;example-vnf-name2-val-5313");
+ doc.addContent("link", "https://ext1.test.onap.com:8443/aai/v9/network/newvces/newvce/vnf-id-team4-11");
+ doc.addContent("searchTagIDs", "0;1;2");
+ doc.addContent("lastmodTimestamp", "2017-04-18T17:21:08.142-0400");
+
+ doc.setUrl("services/search-data-service/v1/search/indexes/entitysearchindex-localhost-ist-apr18/documents/83dcab92d75b20eb94578039c8cec5e7b6b4717791e3c367d8af5069ce76dc90");
+ doc.setEtag("1");
+
+
+ return hitEntity;
+
+ }
+
+ public static HitEntity getHitSample5() {
+
+ HitEntity hitEntity = new HitEntity();
+ DocumentEntity doc = new DocumentEntity();
+
+ hitEntity.setDocument(doc);
+ hitEntity.setScore("17.01174");
+
+ doc.addContent("entityPrimaryKeyValue", "example-vnf-id2-val-9501");
+ doc.addContent("entityType", "newvce");
+ doc.addContent("searchTags", "example-vnf-id2-val-9501;example-vnf-name-val-9501;example-vnf-name2-val-9501");
+ doc.addContent("link", "https://ext1.test.onap.com:8443/aai/v9/network/newvces/newvce/example-vnf-id2-val-9501");
+ doc.addContent("searchTagIDs", "0;1;2");
+ doc.addContent("lastmodTimestamp", "2017-04-18T17:21:23.323-0400");
+
+ doc.setUrl("services/search-data-service/v1/search/indexes/entitysearchindex-localhost-ist-apr18/documents/461816ba8aa94d01f2c978999b843dbaf10e0509db58d1945d6f5999d6db8f5e");
+ doc.setEtag("1");
+
+
+ return hitEntity;
+
+ }
+
+ public static HitEntity getHitSample6() {
+
+ HitEntity hitEntity = new HitEntity();
+ DocumentEntity doc = new DocumentEntity();
+
+ hitEntity.setDocument(doc);
+ hitEntity.setScore("17.01174");
+
+ doc.addContent("entityPrimaryKeyValue", "vnf-id-dm-auto-10");
+ doc.addContent("entityType", "vce");
+ doc.addContent("searchTags", "vpe-id-dm-auto-10;vnf-id-dm-auto-10;vnf-name-dm-auto-10;vnf-name2-dm-auto-10");
+ doc.addContent("link", "https://ext1.test.onap.com:8443/aai/v9/network/vces/vce/vnf-id-dm-auto-10");
+ doc.addContent("searchTagIDs", "0;1;2;3");
+ doc.addContent("lastmodTimestamp", "2017-04-18T17:24:57.209-0400");
+
+ doc.setUrl("services/search-data-service/v1/search/indexes/entitysearchindex-localhost-ist-apr18/documents/1ead4512e65ee0eafb24e0156cc1abdf97368f08dfe065f02580aa09661bbcd8");
+ doc.setEtag("1");
+
+
+ return hitEntity;
+
+ }
+
+ public static HitEntity getHitSample7() {
+
+ HitEntity hitEntity = new HitEntity();
+ DocumentEntity doc = new DocumentEntity();
+
+ hitEntity.setDocument(doc);
+ hitEntity.setScore("13.940832");
+
+ doc.addContent("entityPrimaryKeyValue", "e3e59c5b-ad48-44d0-b3e4-80eacdcee4c7");
+ doc.addContent("entityType", "generic-vnf");
+ doc.addContent("searchTags", "e3e59c5b-ad48-44d0-b3e4-80eacdcee4c7;VNF_Test_vNF_modules_01");
+ doc.addContent("link", "https://ext1.test.onap.com:8443/aai/v9/network/generic-vnfs/generic-vnf/e3e59c5b-ad48-44d0-b3e4-80eacdcee4c7");
+ doc.addContent("searchTagIDs", "0;1");
+ doc.addContent("lastmodTimestamp", "2017-04-18T17:26:34.603-0400");
+
+ doc.setUrl("services/search-data-service/v1/search/indexes/entitysearchindex-localhost-ist-apr18/documents/1462582e8fd7786f72f26548e4247b72ab6cd101cca0bbb68a60dd3ad16500d0");
+ doc.setEtag("1");
+
+
+ return hitEntity;
+
+ }
+
+ public static HitEntity getHitSample8() {
+
+ HitEntity hitEntity = new HitEntity();
+ DocumentEntity doc = new DocumentEntity();
+
+ hitEntity.setDocument(doc);
+ hitEntity.setScore("13.940832");
+
+ doc.addContent("entityPrimaryKeyValue", "fusion-jitsi-vnf-001");
+ doc.addContent("entityType", "generic-vnf");
+ doc.addContent("searchTags", "fusion-jitsi-vnf-001;fusion-jitsi-vnf");
+ doc.addContent("link", "https://ext1.test.onap.com:8443/aai/v9/network/generic-vnfs/generic-vnf/fusion-jitsi-vnf-001");
+ doc.addContent("searchTagIDs", "0;1");
+ doc.addContent("lastmodTimestamp", "2017-04-18T17:28:14.293-0400");
+
+ doc.setUrl("services/search-data-service/v1/search/indexes/entitysearchindex-localhost-ist-apr18/documents/b79ddfec9a00184445174c91e7490a0d407f351983bba4ae53bfec0584f73ee3");
+ doc.setEtag("1");
+
+
+ return hitEntity;
+
+ }
+
+ public static HitEntity getHitSample9() {
+
+ HitEntity hitEntity = new HitEntity();
+ DocumentEntity doc = new DocumentEntity();
+
+ hitEntity.setDocument(doc);
+ hitEntity.setScore("13.940832");
+
+ doc.addContent("entityPrimaryKeyValue", "vnfm0003v");
+ doc.addContent("entityType", "generic-vnf");
+ doc.addContent("searchTags", "vnfm0003v;vnfm0003v");
+ doc.addContent("link", "https://ext1.test.onap.com:8443/aai/v9/network/generic-vnfs/generic-vnf/vnfm0003v");
+ doc.addContent("searchTagIDs", "0;1");
+ doc.addContent("lastmodTimestamp", "2017-04-18T17:29:39.594-0400");
+
+ doc.setUrl("services/search-data-service/v1/search/indexes/entitysearchindex-localhost-ist-apr18/documents/52ae232ea5506d6de8ef35c4f46a1ceafe35f3717ff578b83531bc7615870b12");
+ doc.setEtag("1");
+
+
+ return hitEntity;
+
+ }
+
+ public static HitEntity getHitSample10() {
+
+ HitEntity hitEntity = new HitEntity();
+ DocumentEntity doc = new DocumentEntity();
+
+ hitEntity.setDocument(doc);
+ hitEntity.setScore("13.928098");
+
+ doc.addContent("entityPrimaryKeyValue", "amist456vnf");
+ doc.addContent("entityType", "generic-vnf");
+ doc.addContent("searchTags", "amist456vnf;amist456vnf");
+ doc.addContent("link", "https://ext1.test.onap.com:8443/aai/v9/network/generic-vnfs/generic-vnf/amist456vnf");
+ doc.addContent("searchTagIDs", "0;1");
+ doc.addContent("lastmodTimestamp", "2017-04-18T17:28:28.163-0400");
+
+ doc.setUrl("services/search-data-service/v1/search/indexes/entitysearchindex-localhost-ist-apr18/documents/3424afea5963696380a0fdc78ee5320cf5fa9bc0459f1f9376db208d31196434");
+ doc.setEtag("1");
+
+
+ return hitEntity;
+
+ }
+
+
+
+ public static SearchAbstractionResponse getSuccessfulEntitySearchResponse() {
+
+ SearchAbstractionResponse sasResponse = new SearchAbstractionResponse();
+
+ SearchResult searchResult = new SearchResult();
+ sasResponse.setSearchResult(searchResult);
+
+ searchResult.setTotalHits(3257);
+
+ List<HitEntity> hits = new ArrayList<HitEntity>();
+
+ hits.add(getHitSample1());
+ hits.add(getHitSample2());
+ hits.add(getHitSample3());
+ hits.add(getHitSample4());
+ hits.add(getHitSample5());
+ hits.add(getHitSample6());
+ hits.add(getHitSample7());
+ hits.add(getHitSample8());
+ hits.add(getHitSample9());
+ hits.add(getHitSample10());
+
+ searchResult.setHits(hits);
+
+ return sasResponse;
+
+ }
+
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/sas/entity/SearchAbstractionResponse.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/sas/entity/SearchAbstractionResponse.java
new file mode 100644
index 0000000..b937f66
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/sas/entity/SearchAbstractionResponse.java
@@ -0,0 +1,39 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.dal.sas.entity;
+
+public class SearchAbstractionResponse {
+
+ private SearchResult searchResult;
+
+ public SearchResult getSearchResult() {
+ return searchResult;
+ }
+
+ public void setSearchResult(SearchResult searchResult) {
+ this.searchResult = searchResult;
+ }
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/sas/entity/SearchResult.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/sas/entity/SearchResult.java
new file mode 100644
index 0000000..a656491
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/sas/entity/SearchResult.java
@@ -0,0 +1,49 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.dal.sas.entity;
+
+import java.util.List;
+
+public class SearchResult {
+
+ private int totalHits;
+ private List<HitEntity> hits;
+
+ public int getTotalHits() {
+ return totalHits;
+ }
+ public void setTotalHits(int totalHits) {
+ this.totalHits = totalHits;
+ }
+ public List<HitEntity> getHits() {
+ return hits;
+ }
+ public void setHits(List<HitEntity> hits) {
+ this.hits = hits;
+ }
+
+
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/editattributes/AttributeUpdaterTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/editattributes/AttributeUpdaterTest.java
new file mode 100644
index 0000000..63b3ff4
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/editattributes/AttributeUpdaterTest.java
@@ -0,0 +1,164 @@
+package org.onap.aai.sparky.editattributes;
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+/*
+package org.openecomp.sparky.editattributes;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.ws.rs.core.Response.Status;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.onap.aai.restclient.client.OperationResult;
+import org.onap.aai.sparky.config.oxm.OxmEntityDescriptor;
+import org.onap.aai.sparky.config.oxm.OxmEntityLookup;
+import org.onap.aai.sparky.config.oxm.OxmModelLoader;
+import org.onap.aai.sparky.dal.aai.config.ActiveInventoryConfig;
+import org.onap.aai.sparky.editattributes.AttributeUpdater;
+import org.openecomp.sparky.dal.aai.config.ActiveInventoryConfigUtil;
+
+
+/**
+ * The Class AttributeUpdaterTest.
+ *
+public class AttributeUpdaterTest {
+
+ /**
+ * Sets the up.
+ *
+ * @throws Exception the exception
+ *
+ @Before
+ public void setUp() throws Exception {}
+
+ /**
+ * @throws Exception
+ */
+ /*
+ @Test
+ public void testUpdateObjectAttribute() throws Exception {
+
+ OxmEntityDescriptor desc = new OxmEntityDescriptor();
+ desc.addPrimaryKeyName("hostname");
+ desc.setEntityName("pserver");
+
+ OxmEntityLookup entityLookup = OxmEntityLookup.getInstance();
+ entityLookup.addEntityDescriptor("pserver", desc);
+
+ AttributeUpdater updater = new AttributeUpdater(new OxmModelLoader(), entityLookup,
+ new ActiveInventoryConfig(ActiveInventoryConfigUtil.getValidTestProperties()));
+ Map<String, Object> attributes = new HashMap<>();
+ attributes.put("prov-status", "PREPROV");
+ attributes.put("in-maint", "true");
+ OperationResult result = updater.updateObjectAttribute(
+ "cloud-infrastructure/pservers/pserver/something", attributes, "someid");
+ assertEquals(Status.FORBIDDEN.getStatusCode(), result.getResultCode());
+ }
+ */
+
+ // This needs the OXM file in place to work.
+ /**
+ * Test get edit object from uri.
+ *
+ * @throws Exception the exception
+ */
+ //@Test
+ /*public void testGetEditObjectFromUri() throws Exception {
+
+ OxmModelLoader loader = new OxmModelLoader();
+ loader.setLatestVersionNum(11);
+
+ OxmEntityDescriptor desc = new OxmEntityDescriptor();
+ desc.addPrimaryKeyName("hostname");
+ desc.setEntityName("pserver");
+
+ OxmEntityLookup entityLookup = OxmEntityLookup.getInstance();
+ entityLookup.addEntityDescriptor("pserver", desc);
+
+
+ DynamicType mockType = Mockito.mock(DynamicType.class);
+ Class<? extends DynamicEntity> mockDynamicEntity = Mockito.mock(DynamicEntity.class);
+
+ Mockito.when(mockType.getJavaClass()).thenReturn(mockDynamicEntity);
+
+
+
+
+ HashMap<String, DynamicType> typeLookup = new HashMap<String,DynamicType>();
+ typeLookup.put("pserver", mockType);
+
+ entityLookup.setEntityTypeLookup(typeLookup);
+
+
+ AttributeUpdater updater = new AttributeUpdater(new OxmModelLoader(), entityLookup,
+ new ActiveInventoryConfig(ActiveInventoryConfigUtil.getValidTestProperties()));
+ AaiEditObject result =
+ updater.getEditObjectFromUri("cloud-infrastructure/pservers/pserver/mtznjtax101");
+ assertEquals("Pserver", result.getObjectType());
+ assertEquals("pserver", result.getRootElement());
+ assertEquals("hostname", result.getKeyName());
+ assertEquals("mtznjtax101", result.getKeyValue());
+ }*/
+
+ /**
+ * Test get relative uri.
+ *
+ * @throws Exception the exception
+ */
+ /*
+ @Test
+ public void testGetRelativeUri() throws Exception {
+
+ OxmEntityDescriptor desc = new OxmEntityDescriptor();
+ desc.addPrimaryKeyName("hostname");
+ desc.setEntityName("pserver");
+
+ OxmEntityLookup entityLookup = OxmEntityLookup.getInstance();
+ entityLookup.addEntityDescriptor("pserver", desc);
+
+ AttributeUpdater updater = new AttributeUpdater(new OxmModelLoader(), entityLookup,
+ new ActiveInventoryConfig(ActiveInventoryConfigUtil.getValidTestProperties()));
+ // Test entity uri without "/aai/version/"
+ String result = updater.getRelativeUri("cloud-infrastructure/pservers/pserver/mtznjtax101");
+ assertEquals("/cloud-infrastructure/pservers/pserver/mtznjtax101", result);
+ result = updater.getRelativeUri("/aai/v8/cloud-infrastructure/pservers/pserver/mtznjtax101");
+ assertEquals("/cloud-infrastructure/pservers/pserver/mtznjtax101", result);
+
+ result = updater.getRelativeUri("/v8/cloud-infrastructure/pservers/pserver/mtznjtax101");
+ assertEquals("/cloud-infrastructure/pservers/pserver/mtznjtax101", result);
+
+ result = updater.getRelativeUri("aai/v88/cloud-infrastructure/pservers/pserver/mtznjtax101");
+ assertEquals("/cloud-infrastructure/pservers/pserver/mtznjtax101", result);
+
+ result = updater.getRelativeUri("/cloud-infrastructure/pservers/pserver/mtznjtax101");
+ assertEquals("/cloud-infrastructure/pservers/pserver/mtznjtax101", result);
+ }
+
+}
+*/ \ No newline at end of file
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/editattributes/EditAttributesTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/editattributes/EditAttributesTest.java
new file mode 100644
index 0000000..4e7e80a
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/editattributes/EditAttributesTest.java
@@ -0,0 +1,171 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+
+package org.onap.aai.sparky.editattributes;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import javax.servlet.ReadListener;
+import javax.servlet.ServletInputStream;
+
+import org.apache.commons.io.IOUtils;
+import org.junit.Before;
+import org.junit.BeforeClass;
+
+
+/**
+ * The Class EditAttributesTest.
+ */
+public class EditAttributesTest {
+ String sampleJsonRequest =
+ "{ \"entity-uri\" : \"some/uri/value/here\", \"entity-type\" : \"complex\","
+ + " \"attributes\" : { \"prov-status\" : \"PREPROV\", \"inMaint\" : \"true\","
+ + " \"isClosedLoop\" : \"false\" }}";
+
+ /**
+ * Sets the up before class.
+ *
+ * @throws Exception the exception
+ */
+ @BeforeClass
+ public static void setUpBeforeClass() throws Exception {}
+
+ /**
+ * Sets the up.
+ *
+ * @throws Exception the exception
+ */
+ @Before
+ public void setUp() throws Exception {}
+
+
+ /**
+ * Test analyze edit request body.
+ */
+ /*
+ @Test
+ public void testAnalyzeEditRequestBody() {
+ AttributeEditProcessor aes = new AttributeEditProcessor();
+ EditRequest request = aes.analyzeEditRequestBody(sampleJsonRequest);
+ System.out.println("JSON Body : " + sampleJsonRequest);
+ assertNotNull(request);
+ assertEquals("URI should match", "some/uri/value/here", request.getEntityUri());
+ assertEquals("Entity Type should match", "complex", request.getEntityType());
+ assertEquals("Attribute ProvStatus should match", "PREPROV",
+ request.getAttributes().get("prov-status"));
+ assertEquals("Attribute inMaint should be true", "true",
+ request.getAttributes().get("inMaint"));
+ assertEquals("Attribute isClosedLoop should be false", "false",
+ request.getAttributes().get("isClosedLoop"));
+
+ }
+ */
+
+
+ /**
+ * Test edit request.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ * @throws ServletException the servlet exception
+ * @throws JSONException the JSON exception
+ */
+ /*
+ @Test
+ public void testEditRequest() throws IOException, ServletException, JSONException {
+ HttpServletRequest mockRequest = mock(HttpServletRequest.class);
+ HttpServletResponse mockResponse = mock(HttpServletResponse.class);
+ ServletOutputStream mockOutput = mock(ServletOutputStream.class);
+ ServletInputStream mockInput = new MockServletInputStream(sampleJsonRequest);
+
+ when(mockRequest.getRequestURI()).thenReturn("editAttributes");
+ when(mockResponse.getOutputStream()).thenReturn(mockOutput);
+
+ when(mockRequest.getInputStream()).thenReturn(mockInput);
+
+ Principal princip = new UserPrincipal("ds1150");
+
+ when(mockRequest.getUserPrincipal()).thenReturn(princip);
+
+ PrintWriter writer = new PrintWriter("editServletTest.txt");
+ when(mockResponse.getWriter()).thenReturn(writer);
+ AttributeEditProcessor aes = new AttributeEditProcessor();
+ aes.doPost(mockRequest, mockResponse);
+ JSONObject result = null;
+ try {
+ writer.close();
+ result = new JSONObject(FileUtils.readFileToString(new File("editServletTest.txt"), "UTF-8"));
+ } catch (JSONException ex) {
+ // Nothing to catch
+ }
+ assertNotNull(result);
+ // assertEquals("Attributes updated successfully (just need PATCH !!!)", result.get("result"));
+ }
+ */
+
+
+
+ /**
+ * The Class MockServletInputStream.
+ */
+ class MockServletInputStream extends ServletInputStream {
+ InputStream inputStream;
+
+ /**
+ * Instantiates a new mock servlet input stream.
+ *
+ * @param string the string
+ */
+ MockServletInputStream(String string) {
+ this.inputStream = IOUtils.toInputStream(string);
+ }
+
+ /* (non-Javadoc)
+ * @see java.io.InputStream#read()
+ */
+ @Override
+ public int read() throws IOException {
+ return inputStream.read();
+ }
+
+ @Override
+ public boolean isFinished() {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public boolean isReady() {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public void setReadListener(ReadListener readListener) {
+ // TODO Auto-generated method stub
+
+ }
+ }
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/editattributes/TestUserAuthorizationReader.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/editattributes/TestUserAuthorizationReader.java
new file mode 100644
index 0000000..4f99b6d
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/editattributes/TestUserAuthorizationReader.java
@@ -0,0 +1,113 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+
+package org.onap.aai.sparky.editattributes;
+
+import static org.hamcrest.Matchers.containsInAnyOrder;
+import static org.hamcrest.Matchers.empty;
+import static org.junit.Assert.assertThat;
+
+import java.io.File;
+import java.nio.file.Paths;
+import java.util.List;
+
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.onap.aai.sparky.editattributes.UserAuthorizationReader;
+
+/**
+ * The Class TestUserAuthorizationReader.
+ */
+public class TestUserAuthorizationReader {
+
+ private static File userAuthFile;
+ private static File userAuthFileEmpty;
+
+ /**
+ * Sets the up before class.
+ *
+ * @throws Exception the exception
+ */
+ @BeforeClass
+ public static void setUpBeforeClass() throws Exception {
+ userAuthFile = Paths.get(TestData.USER_AUTH_FILE.getFilename()).toFile();
+ userAuthFileEmpty = Paths.get(TestData.USER_AUTH_FILE_EMPTY.getFilename()).toFile();
+ }
+
+ /**
+ * The Enum TestData.
+ */
+ enum TestData {
+ // @formatter:off
+ USER_AUTH_FILE(
+ "src/test/resources/user-auth-reader/authorized-users.config"), USER_AUTH_FILE_EMPTY(
+ "src/test/resources/user-auth-reader/authorized-users-empty.config");
+
+ private String filename;
+
+ /**
+ * Instantiates a new test data.
+ *
+ * @param filename the filename
+ */
+ TestData(String filename) {
+ this.filename = filename;
+ }
+
+ public String getFilename() {
+ return this.filename;
+ }
+ // @formatter:on
+ }
+
+ /**
+ * Test get users.
+ *
+ * @throws Exception the exception
+ */
+ @Test
+ public void testGetUsers() throws Exception {
+ UserAuthorizationReader userAuthorizationReader = new UserAuthorizationReader(userAuthFile);
+
+ // Method under test
+ List<String> userList = userAuthorizationReader.getUsers();
+
+ assertThat(userList, containsInAnyOrder("user1", "user2 user3", "user4"));
+ }
+
+ /**
+ * Test get users passing empty config.
+ *
+ * @throws Exception the exception
+ */
+ @Test
+ public void testGetUsersPassingEmptyConfig() throws Exception {
+ UserAuthorizationReader userConfigReader = new UserAuthorizationReader(userAuthFileEmpty);
+
+ List<String> userList = userConfigReader.getUsers();
+
+ assertThat(userList, empty());
+ }
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/editattributes/TestUserValidator.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/editattributes/TestUserValidator.java
new file mode 100644
index 0000000..e20defa
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/editattributes/TestUserValidator.java
@@ -0,0 +1,137 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+
+package org.onap.aai.sparky.editattributes;
+
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Mockito.when;
+
+import java.io.File;
+import java.nio.file.Paths;
+
+import org.apache.log4j.BasicConfigurator;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.onap.aai.sparky.editattributes.UserAuthorizationReader;
+import org.onap.aai.sparky.editattributes.UserValidator;
+
+/**
+ * The Class TestUserValidator.
+ */
+@RunWith(MockitoJUnitRunner.class)
+public class TestUserValidator {
+
+ @Mock
+ private UserAuthorizationReader userAuthorizationReader;
+
+ @InjectMocks
+ private UserValidator userValidator;
+
+ private static File userAuthFile;
+ private static File missingUserAuthFile;
+
+ /**
+ * Sets the up before class.
+ *
+ * @throws Exception the exception
+ */
+ @BeforeClass
+ public static void setUpBeforeClass() throws Exception {
+ BasicConfigurator.configure();
+ userAuthFile = Paths.get(TestData.USER_AUTH_FILE.getFilename()).toFile();
+ missingUserAuthFile = Paths.get(TestData.MISSING_USER_AUTH_FILE.getFilename()).toFile();
+ }
+
+ /**
+ * The Enum TestData.
+ */
+ enum TestData {
+ // @formatter:off
+ USER_AUTH_FILE(
+ "src/test/resources/user-validator/authorized-users.config"), MISSING_USER_AUTH_FILE(
+ "src/test/resources/user-validator/missing.config");
+
+ private String filename;
+
+ /**
+ * Instantiates a new test data.
+ *
+ * @param filename the filename
+ */
+ TestData(String filename) {
+ this.filename = filename;
+ }
+
+ public String getFilename() {
+ return this.filename;
+ }
+ // @formatter:on
+ }
+
+ /**
+ * Test is authorized user.
+ *
+ * @throws Exception the exception
+ */
+ @Test
+ public void testIsAuthorizedUser() throws Exception {
+ when(userAuthorizationReader.getUsers()).thenCallRealMethod();
+ when(userAuthorizationReader.getUserAuthorizationFile()).thenReturn(userAuthFile);
+
+ boolean isAuthUser = userValidator.isAuthorizedUser("user1");
+ assertThat(isAuthUser, is(true));
+
+ boolean isAuthUser2 = userValidator.isAuthorizedUser("user2");
+ assertThat(isAuthUser2, is(false));
+
+ boolean isAuthUser3 = userValidator.isAuthorizedUser("user3");
+ assertThat(isAuthUser3, is(false));
+
+ boolean isAuthUser4 = userValidator.isAuthorizedUser("not-in-file");
+ assertThat(isAuthUser4, is(false));
+
+ boolean isAuthUser5 = userValidator.isAuthorizedUser("user4");
+ assertThat(isAuthUser5, is(true));
+ }
+
+ /**
+ * Test not authorized if file not present.
+ *
+ * @throws Exception the exception
+ */
+ @Test
+ public void testNotAuthorizedIfFileNotPresent() throws Exception {
+ when(userAuthorizationReader.getUsers()).thenCallRealMethod();
+ when(userAuthorizationReader.getUserAuthorizationFile()).thenReturn(missingUserAuthFile);
+
+ boolean isAuthUser = userValidator.isAuthorizedUser("user1");
+ assertThat(isAuthUser, is(false));
+ }
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/editattributes/entity/EditRequestTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/editattributes/entity/EditRequestTest.java
new file mode 100644
index 0000000..5f87a27
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/editattributes/entity/EditRequestTest.java
@@ -0,0 +1,43 @@
+package org.onap.aai.sparky.editattributes.entity;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import java.util.HashMap;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.onap.aai.sparky.viewandinspect.EntityTypeAggregation;
+import org.onap.aai.sparky.viewandinspect.entity.GraphMeta;
+
+import com.fasterxml.jackson.databind.node.JsonNodeFactory;
+
+public class EditRequestTest {
+
+ private EditRequest editAttribute;
+ private HashMap<String,Object> attributes;
+
+
+
+ @Before
+ public void init() throws Exception {
+
+ editAttribute = new EditRequest();
+ attributes = new HashMap<String,Object>();
+
+ }
+
+
+ @Test
+ public void updateValues() {
+
+ editAttribute.setEntityUri("");
+ assertNotNull(editAttribute.getEntityUri());
+ editAttribute.setEntityType("");
+ assertNotNull(editAttribute.getEntityType());
+ editAttribute.setAttributes(attributes);
+ assertNotNull(editAttribute.getAttributes());
+ }
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/inventory/EntityHistoryQueryBuilderTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/inventory/EntityHistoryQueryBuilderTest.java
new file mode 100644
index 0000000..9cd7781
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/inventory/EntityHistoryQueryBuilderTest.java
@@ -0,0 +1,34 @@
+package org.onap.aai.sparky.inventory;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+//import java.security.SecureRandom;
+
+import org.junit.Before;
+import org.junit.Test;
+//import org.openecomp.sparky.analytics.HistoricalCounter;
+import org.onap.aai.sparky.inventory.EntityHistoryQueryBuilder;
+
+public class EntityHistoryQueryBuilderTest {
+
+ private EntityHistoryQueryBuilder entityHistoryQueryBuilder;
+
+ @Before
+ public void init() throws Exception {
+ entityHistoryQueryBuilder = new EntityHistoryQueryBuilder();
+ }
+
+ @SuppressWarnings("static-access")
+ @Test
+ public void successfullBuild() {
+ entityHistoryQueryBuilder.getQuery("table");
+ assertNotNull(entityHistoryQueryBuilder.createTableQuery());
+ entityHistoryQueryBuilder.getQuery("graph");
+ assertNotNull(entityHistoryQueryBuilder.createGraphQuery());
+ entityHistoryQueryBuilder.getQuery("tree");
+ assertNull(entityHistoryQueryBuilder.getQuery("tree"));
+
+ }
+
+} \ No newline at end of file
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/inventory/GeoIndexDocumentTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/inventory/GeoIndexDocumentTest.java
new file mode 100644
index 0000000..2e39725
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/inventory/GeoIndexDocumentTest.java
@@ -0,0 +1,121 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+
+package org.onap.aai.sparky.inventory;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.onap.aai.sparky.inventory.entity.GeoIndexDocument;
+
+/**
+ * The Class GeoIndexDocumentTest.
+ */
+@RunWith(MockitoJUnitRunner.class)
+public class GeoIndexDocumentTest {
+
+ /**
+ * Inits the.
+ *
+ * @throws Exception the exception
+ */
+ @Before
+ public void init() throws Exception {}
+
+ /**
+ * Checks if is valid geo index document success path.
+ */
+ @Test
+ public void isValidGeoIndexDocument_successPath() {
+
+ GeoIndexDocument geoDoc = new GeoIndexDocument();
+
+ geoDoc.setEntityPrimaryKeyName("pkeyName");
+ geoDoc.setEntityPrimaryKeyValue("pkeyValue");
+ geoDoc.setEntityType("type");
+ geoDoc.setId("12312");
+ geoDoc.setLatitude("-45.123");
+ geoDoc.setLongitude("181.321");
+ geoDoc.setSelfLink("https://server.somewhere.com:8443/aai/v7/id");
+
+ assertTrue(geoDoc.isValidGeoDocument());
+
+ }
+
+ /**
+ * Checks if is valid geo index document fail no geo coordinates.
+ */
+ @Test
+ public void isValidGeoIndexDocument_fail_no_geoCoordinates() {
+
+ GeoIndexDocument geoIndexDoc = new GeoIndexDocument();
+
+ geoIndexDoc.setEntityPrimaryKeyName("pkeyName");
+ geoIndexDoc.setEntityPrimaryKeyValue("pkeyValue");
+ geoIndexDoc.setEntityType("type");
+ geoIndexDoc.setId("12312");
+ geoIndexDoc.setSelfLink("https://server.somewhere.com:8443/aai/v7/id");
+
+ assertFalse(geoIndexDoc.isValidGeoDocument());
+
+ }
+
+ /**
+ * Checks if is valid geo index document fail invalid geo coordinates.
+ */
+ @Test
+ public void isValidGeoIndexDocument_fail_invalid_geoCoordinates() {
+
+ GeoIndexDocument geoIndexDoc = new GeoIndexDocument();
+
+ geoIndexDoc.setEntityPrimaryKeyName("pkeyName");
+ geoIndexDoc.setEntityPrimaryKeyValue("pkeyValue");
+ geoIndexDoc.setEntityType("type");
+ geoIndexDoc.setId("12312");
+ geoIndexDoc.setLatitude("not_a_valid");
+ geoIndexDoc.setLongitude("geo point");
+
+ geoIndexDoc.setSelfLink("https://server.somewhere.com:8443/aai/v7/id");
+
+ assertFalse(geoIndexDoc.isValidGeoDocument());
+
+ }
+
+ /**
+ * Checks if is valid geo index document fail nothing set.
+ */
+ @Test
+ public void isValidGeoIndexDocument_fail_nothing_set() {
+
+ GeoIndexDocument geoIndexDoc = new GeoIndexDocument();
+
+ assertFalse(geoIndexDoc.isValidGeoDocument());
+
+ }
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/inventory/entity/TopographicalEntityTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/inventory/entity/TopographicalEntityTest.java
new file mode 100644
index 0000000..c878077
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/inventory/entity/TopographicalEntityTest.java
@@ -0,0 +1,50 @@
+package org.onap.aai.sparky.inventory.entity;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.ArrayList;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.onap.aai.sparky.viewandinspect.config.VisualizationConfigs;
+
+public class TopographicalEntityTest {
+
+ private TopographicalEntity topographicalEntity;
+
+
+ @Before
+ public void init() throws Exception {
+ topographicalEntity = new TopographicalEntity();
+ }
+
+
+ @SuppressWarnings("static-access")
+ @Test
+ public void updateValues() {
+
+ topographicalEntity.setEntityType("");
+ assertNotNull(topographicalEntity.getEntityType());
+ topographicalEntity.setEntityPrimaryKeyValue("");
+ assertNotNull(topographicalEntity.getEntityPrimaryKeyValue());
+ topographicalEntity.setEntityPrimaryKeyName("");
+ assertNotNull(topographicalEntity.getEntityPrimaryKeyName());
+ topographicalEntity.setLatitude("");
+ assertNotNull(topographicalEntity.getLatitude());
+ topographicalEntity.setLongitude("");
+ assertNotNull(topographicalEntity.getLongitude());
+ topographicalEntity.setSelfLink("");
+ assertNotNull(topographicalEntity.getSelfLink());
+ topographicalEntity.setId("");
+ assertNotNull(topographicalEntity.getId());
+ assertNotNull(topographicalEntity.getSerialversionuid());
+ assertNotNull(topographicalEntity.toString());
+
+ //assertNotNull(topographicalEntity.getAsJson());
+ //assertNotNull(topographicalEntity.generateUniqueShaDigest("","",""));
+ }
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/logging/util/LoggingUtilsTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/logging/util/LoggingUtilsTest.java
new file mode 100644
index 0000000..4dc30a9
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/logging/util/LoggingUtilsTest.java
@@ -0,0 +1,25 @@
+package org.onap.aai.sparky.logging.util;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.onap.aai.sparky.logging.util.LoggingUtils;
+
+public class LoggingUtilsTest {
+
+ private LoggingUtils durationTester;
+ @Before
+ public void init() throws Exception {
+ durationTester = new LoggingUtils();
+ }
+
+ @Test
+ public void durationTester() {
+
+
+ assertEquals("1425",durationTester.setDuration(3575, 5000));
+
+ }
+
+} \ No newline at end of file
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/EntityCountHistoryProcessorTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/EntityCountHistoryProcessorTest.java
new file mode 100644
index 0000000..9629ae8
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/EntityCountHistoryProcessorTest.java
@@ -0,0 +1,154 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+
+package org.onap.aai.sparky.search;
+/*
+import static org.junit.Assert.assertEquals;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.Message;
+import org.apache.camel.component.restlet.RestletConstants;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mockito;
+import org.onap.aai.restclient.client.OperationResult;
+import org.onap.aai.sparky.search.EntityCountHistoryProcessor;
+import org.onap.aai.sparky.util.RestletUtils;
+import org.restlet.Request;
+import org.restlet.Response;
+import org.restlet.data.ClientInfo;
+import org.restlet.data.Reference;
+import org.restlet.data.Status;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+public class EntityCountHistoryProcessorTest {
+ private EntityCountHistoryProcessor entityCountHistoryProcessor;
+ private Exchange mockExchange;
+ private Message mockRequestMessage;
+ private Message mockResponseMessage;
+ private Request mockRestletRequest;
+ private Response mockRestletResponse;
+ private ClientInfo requestClientInfo;
+ private RestletUtils mockRestletUtils;
+
+ @Before
+ public void init() throws Exception {
+ mockExchange = Mockito.mock(Exchange.class);
+ mockRequestMessage = Mockito.mock(Message.class);
+ mockResponseMessage = Mockito.mock(Message.class);
+ mockRestletRequest = Mockito.mock(Request.class);
+ mockRestletResponse = Mockito.mock(Response.class);
+ mockRestletUtils = Mockito.mock(RestletUtils.class);
+
+ entityCountHistoryProcessor = new EntityCountHistoryProcessor();
+ entityCountHistoryProcessor.setRestletUtils(mockRestletUtils);
+
+ requestClientInfo = new ClientInfo();
+
+ Mockito.when(mockRestletRequest.getClientInfo()).thenReturn(requestClientInfo);
+
+ Mockito.when(mockRequestMessage.getHeader(RestletConstants.RESTLET_REQUEST, Request.class))
+ .thenReturn(mockRestletRequest);
+ Mockito.when(mockRequestMessage.getHeader(RestletConstants.RESTLET_RESPONSE, Response.class))
+ .thenReturn(mockRestletResponse);
+ Mockito.when(mockExchange.getIn()).thenReturn(mockRequestMessage);
+ Mockito.when(mockExchange.getOut()).thenReturn(mockResponseMessage);
+ }
+
+ public String getStubbedData_getEntityCountHistory_success() {
+ ObjectMapper mapper = new ObjectMapper();
+ ObjectNode entityCountEntry = mapper.createObjectNode();
+
+ entityCountEntry.put("doc_count", 2069);
+ entityCountEntry.put("key", "complex");
+
+ ArrayNode arrayNode = mapper.createArrayNode();
+ arrayNode.add(entityCountEntry);
+
+ ObjectNode resultNode = mapper.createObjectNode();
+ resultNode.set("result", arrayNode);
+
+ return resultNode.toString();
+ }
+
+ @Test
+ public void testGetEntityCountHistory_success() {
+ EntityCountHistoryProcessor spyEntityCountHistoryProcessor =
+ Mockito.spy(entityCountHistoryProcessor);
+ OperationResult operationResult = new OperationResult();
+
+ String result = getStubbedData_getEntityCountHistory_success();
+
+ operationResult.setResult(Status.SUCCESS_OK.getCode(), result);
+
+ Mockito.when(mockExchange.getIn().getHeader("CamelHttpQuery", String.class)).thenReturn("");
+
+ Mockito.doReturn("table").when(spyEntityCountHistoryProcessor).getTypeParameter(Mockito.any());
+ Mockito.doReturn(operationResult).when(spyEntityCountHistoryProcessor).getResults(Mockito.any(),
+ Mockito.any());
+
+ spyEntityCountHistoryProcessor.getEntityCountHistory(mockExchange);
+
+ ArgumentCaptor<String> entityCaptor = ArgumentCaptor.forClass(String.class);
+ Mockito.verify(mockRestletResponse, Mockito.atLeast(1)).setEntity(entityCaptor.capture(),
+ Mockito.any());
+ assertEquals(operationResult.getResult(), entityCaptor.getValue());
+ }
+
+ @Test
+ public void testGetEntityCountHistory_failure_noTypeParameter() {
+ Mockito.when(mockRestletRequest.getOriginalRef()).thenReturn(new Reference());
+
+ EntityCountHistoryProcessor spyEntityCountHistoryProcessor =
+ Mockito.spy(entityCountHistoryProcessor);
+ OperationResult operationResult = new OperationResult();
+
+ String result = getStubbedData_getEntityCountHistory_success();
+
+ operationResult.setResult(Status.SUCCESS_OK.getCode(), result);
+
+ Mockito.when(mockExchange.getIn().getHeader("CamelHttpQuery", String.class)).thenReturn("");
+
+ Mockito.doReturn("").when(spyEntityCountHistoryProcessor).getTypeParameter(Mockito.any());
+ Mockito.doReturn(operationResult).when(spyEntityCountHistoryProcessor).getResults(Mockito.any(), Mockito.any());
+
+ spyEntityCountHistoryProcessor.getEntityCountHistory(mockExchange);
+
+ ArgumentCaptor<String> entityCaptor = ArgumentCaptor.forClass(String.class);
+ Mockito.verify(mockRestletResponse, Mockito.atLeast(1)).setEntity(entityCaptor.capture(),
+ Mockito.any());
+ assertEquals("{ \"errorMessage\" : Unsupported request. Resource not found. }",
+ entityCaptor.getValue());
+
+ ArgumentCaptor<Status> responseCodeCaptor = ArgumentCaptor.forClass(Status.class);
+ Mockito.verify(mockRestletResponse, Mockito.atLeast(1)).setStatus(responseCodeCaptor.capture());
+ assertEquals(Status.CLIENT_ERROR_NOT_FOUND, responseCodeCaptor.getValue());
+ }
+}
+*/ \ No newline at end of file
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/EntityTypeSummaryBucketTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/EntityTypeSummaryBucketTest.java
new file mode 100644
index 0000000..31f0c04
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/EntityTypeSummaryBucketTest.java
@@ -0,0 +1,31 @@
+package org.onap.aai.sparky.search;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class EntityTypeSummaryBucketTest {
+
+private EntityTypeSummaryBucket entityTypeSummaryBucket;
+
+ @Before
+ public void init() throws Exception {
+ entityTypeSummaryBucket = new EntityTypeSummaryBucket();
+
+ }
+
+
+ @Test
+ public void updateValues() {
+
+ entityTypeSummaryBucket.setKey("54566");
+ assertNotNull(entityTypeSummaryBucket.getKey());
+ entityTypeSummaryBucket.setCount(3);
+ assertEquals(3,entityTypeSummaryBucket.getCount());
+
+ }
+
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/EntityTypeSummaryTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/EntityTypeSummaryTest.java
new file mode 100644
index 0000000..de8929e
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/EntityTypeSummaryTest.java
@@ -0,0 +1,37 @@
+package org.onap.aai.sparky.search;
+
+import static org.junit.Assert.assertNotNull;
+
+import java.util.ArrayList;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class EntityTypeSummaryTest {
+
+
+ private EntityTypeSummary entityTypeSummaryBucket;
+ private ArrayList<EntityTypeSummaryBucket> bucketList;
+ private EntityTypeSummaryBucket bucket;
+
+ @Before
+ public void init() throws Exception {
+ entityTypeSummaryBucket = new EntityTypeSummary();
+ bucketList = new ArrayList<EntityTypeSummaryBucket>();
+ bucket = new EntityTypeSummaryBucket();
+
+ }
+
+
+ @Test
+ public void updateValues() {
+
+ entityTypeSummaryBucket.setTotalChartHits(8);
+ assertNotNull(entityTypeSummaryBucket.getTotalChartHits());
+ entityTypeSummaryBucket.setBuckets(bucketList);
+ assertNotNull(entityTypeSummaryBucket.getBuckets());
+ entityTypeSummaryBucket.addBucket(bucket);
+
+ }
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/SearchEntityPropertiesTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/SearchEntityPropertiesTest.java
new file mode 100644
index 0000000..2958525
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/SearchEntityPropertiesTest.java
@@ -0,0 +1,34 @@
+package org.onap.aai.sparky.search;
+
+import static org.junit.Assert.assertNotNull;
+
+import java.util.HashMap;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class SearchEntityPropertiesTest {
+
+ private SearchEntityProperties searchEntityProperties;
+ private HashMap<String,String> fields;
+
+ @Before
+ public void init() throws Exception {
+ searchEntityProperties = new SearchEntityProperties();
+ fields = new HashMap<String,String>();
+
+ }
+
+
+ @Test
+ public void updateValues() {
+
+ searchEntityProperties.setFields(fields);
+ assertNotNull(searchEntityProperties.getFields());
+ searchEntityProperties.setType("VNF-Stack");
+ assertNotNull(searchEntityProperties.getType());
+
+ }
+
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/SearchServiceAdapterTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/SearchServiceAdapterTest.java
new file mode 100644
index 0000000..7963528
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/SearchServiceAdapterTest.java
@@ -0,0 +1,47 @@
+package org.onap.aai.sparky.search;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.ArrayList;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.onap.aai.restclient.enums.RestAuthenticationMode;
+import org.onap.aai.sparky.dal.rest.config.RestEndpointConfig;
+
+public class SearchServiceAdapterTest {
+
+ private SearchServiceAdapter searchServiceAdapter;
+ private RestEndpointConfig endpointConfig;
+
+ @Before
+ public void init() throws Exception {
+
+ endpointConfig = new RestEndpointConfig();
+ endpointConfig.setRestAuthenticationMode(RestAuthenticationMode.SSL_BASIC);
+ searchServiceAdapter = new SearchServiceAdapter(endpointConfig,"1.0");
+ }
+
+
+ @Test
+ public void updateValues() {
+
+ searchServiceAdapter.setServiceApiVersion("2.0");
+ assertNotNull(searchServiceAdapter.getServiceApiVersion());
+ searchServiceAdapter.setEndpointConfig(endpointConfig);
+ assertNotNull(searchServiceAdapter.getEndpointConfig());
+ assertNotNull(searchServiceAdapter.doPost("https://10.247.40.25:8000","{maxResults:10, queryStr: f}","application/json"));
+ assertNotNull(searchServiceAdapter.doGet("https://10.247.40.25:8000","application/json"));
+ assertNotNull(searchServiceAdapter.doPut("https://10.247.40.25:8000","{maxResults:10, queryStr: f}","application/json"));
+ assertNotNull(searchServiceAdapter.doDelete("https://10.247.40.25:8000","application/json"));
+ assertNotNull(searchServiceAdapter.getTxnHeader());
+ assertNotNull(searchServiceAdapter.buildSearchServiceQueryUrl("searchentity-localhost"));
+ assertNotNull(searchServiceAdapter.buildSearchServiceUrlForApi("searchentity-localhost","2.0"));
+
+
+ }
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/UnifiedSearchProcessorTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/UnifiedSearchProcessorTest.java
new file mode 100644
index 0000000..b0aa22b
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/UnifiedSearchProcessorTest.java
@@ -0,0 +1,445 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+
+package org.onap.aai.sparky.search;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.Exchange;
+import org.apache.camel.Message;
+import org.apache.camel.impl.DefaultCamelContext;
+import org.apache.camel.impl.DefaultExchange;
+import org.json.JSONObject;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.onap.aai.sparky.common.search.CommonSearchSuggestion;
+import org.onap.aai.sparky.search.api.SearchProvider;
+import org.onap.aai.sparky.search.entity.MockSearchResponse;
+import org.onap.aai.sparky.search.entity.QuerySearchEntity;
+import org.onap.aai.sparky.search.entity.SearchSuggestion;
+import org.onap.aai.sparky.search.registry.SearchProviderRegistry;
+import org.onap.aai.sparky.util.HttpServletHelper;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+
+public class UnifiedSearchProcessorTest {
+
+ public interface Suggester {
+ public void addSuggestion( SearchSuggestion suggestion );
+ }
+
+ private abstract class AbstractDummySearchProvider implements SearchProvider, Suggester {
+
+ protected List<SearchSuggestion> suggestions;
+
+ protected AbstractDummySearchProvider() {
+ suggestions = new ArrayList<SearchSuggestion>();
+ }
+
+ public List<SearchSuggestion> getSuggestions() {
+ return suggestions;
+ }
+
+ @Override
+ public List<SearchSuggestion> search(QuerySearchEntity queryRequest) {
+ return getSuggestions();
+ }
+ }
+
+ private class AlphaSearchProvider extends AbstractDummySearchProvider {
+ public AlphaSearchProvider() {
+ super();
+ }
+
+ @Override
+ public void addSuggestion(SearchSuggestion suggestion) {
+ if (suggestion != null) {
+ suggestions.add(suggestion);
+ }
+ }
+ }
+
+ private class BravoSearchProvider extends AbstractDummySearchProvider {
+ public BravoSearchProvider() {
+ super();
+ }
+
+ @Override
+ public void addSuggestion(SearchSuggestion suggestion) {
+ if (suggestion != null) {
+ suggestions.add(suggestion);
+ }
+ }
+ }
+
+ private class GammaSearchProvider extends AbstractDummySearchProvider {
+ public GammaSearchProvider() {
+ super();
+ }
+
+ @Override
+ public void addSuggestion(SearchSuggestion suggestion) {
+ if (suggestion != null) {
+ suggestions.add(suggestion);
+ }
+ }
+ }
+
+ private SearchServiceAdapter mockSearchAdapter;
+
+ private UnifiedSearchProcessor unifiedSearchProcessor;
+ private Message mockRequestMessage;
+ private ObjectMapper mapper;
+
+ private Exchange exchange;
+ private CamelContext camelContext;
+
+ @Before
+ public void init() {
+
+ camelContext = new DefaultCamelContext();
+ exchange = new DefaultExchange(camelContext);
+
+ mockRequestMessage = Mockito.mock(Message.class);
+ exchange.setIn(mockRequestMessage);
+
+ unifiedSearchProcessor = new UnifiedSearchProcessor();
+ unifiedSearchProcessor.setUseOrderedSearchProviderKeys(true);
+
+ mapper = new ObjectMapper();
+
+ mockSearchAdapter = Mockito.mock(SearchServiceAdapter.class);
+ }
+
+
+ @Test
+ public void validateDefaultConstructor() {
+
+ // initially it should be null until the bean wiring initializes it
+ assertNull(unifiedSearchProcessor.getSearchProviderRegistry());
+
+ }
+
+
+ @Test
+ public void validateAccessors() {
+
+ SearchProviderRegistry searchProviderRegistry = new SearchProviderRegistry();
+ unifiedSearchProcessor.setSearchProviderRegistry(searchProviderRegistry);
+
+ // initially it should be null until the bean wiring initializes it
+ assertNotNull(unifiedSearchProcessor.getSearchProviderRegistry());
+ assertEquals(0, searchProviderRegistry.getSearchProviders().size());
+
+ }
+
+ private void initializeSearchMocks(String requestPayload) {
+
+ HttpServletRequest request = Mockito.mock(HttpServletRequest.class);
+ HttpServletHelper.setRequestPayload(request, "application/json", requestPayload);
+
+ Mockito.when(request.getRequestURI()).thenReturn("fakeUri");
+ Mockito.when(request.getLocalPort()).thenReturn(8001);
+ Mockito.when(mockRequestMessage.getBody(Mockito.eq(HttpServletRequest.class))).thenReturn(request);
+ Mockito.when(mockRequestMessage.getBody(Mockito.eq(String.class))).thenReturn(requestPayload);
+
+ }
+
+ private String getSearchRequestJson(String queryString, int maxResults) {
+
+ JSONObject root = new JSONObject();
+ root.put("queryStr", queryString);
+ root.put("maxResults", maxResults);
+
+ return root.toString();
+
+ }
+
+ private String getExternalSearchRequestJson() {
+ JSONObject root = new JSONObject();
+
+ root.put("view", "testView");
+ root.put("entityId", "thisIsAnId");
+ root.put("entityType", "pserver");
+
+ return root.toString();
+ }
+
+
+ @Test
+ public void testSearch_search_when_noSearchProviders() throws IOException {
+
+ // mock env setup
+
+ initializeSearchMocks(getSearchRequestJson("vnfs",10));
+
+ SearchProviderRegistry searchProviderRegistry = new SearchProviderRegistry();
+ unifiedSearchProcessor.setSearchProviderRegistry(searchProviderRegistry);
+
+ // method under test
+ unifiedSearchProcessor.search(exchange);
+
+ assertEquals(200, exchange.getOut().getHeader(Exchange.HTTP_RESPONSE_CODE));
+
+ String entityPayload = exchange.getOut().getBody(String.class);
+ assertNotNull(entityPayload);
+
+ MockSearchResponse searchResponse = mapper.readValue(entityPayload, MockSearchResponse.class);
+
+ assertEquals(0, searchResponse.getTotalFound());
+ assertEquals(0, searchResponse.getSuggestions().size());
+
+ }
+
+ @Test
+ public void testSearch_search_when_ThreeSearchProviders_no_suggestions() throws IOException {
+
+ // mock env setup
+
+ initializeSearchMocks(getSearchRequestJson("vnfs",10));
+
+ SearchProviderRegistry searchProviderRegistry = new SearchProviderRegistry();
+
+ AlphaSearchProvider alpha = new AlphaSearchProvider();
+ BravoSearchProvider bravo = new BravoSearchProvider();
+ GammaSearchProvider gamma = new GammaSearchProvider();
+
+ searchProviderRegistry.addSearchProvider(alpha);
+ searchProviderRegistry.addSearchProvider(bravo);
+ searchProviderRegistry.addSearchProvider(gamma);
+
+ unifiedSearchProcessor.setSearchProviderRegistry(searchProviderRegistry);
+
+ // method under test
+ unifiedSearchProcessor.search(exchange);
+
+ assertEquals(200, exchange.getOut().getHeader(Exchange.HTTP_RESPONSE_CODE));
+
+ String entityPayload = exchange.getOut().getBody(String.class);
+ assertNotNull(entityPayload);
+
+ /*
+ * With a null view name, an empty filter set should be returned - there should be 0 filters
+ */
+
+ SearchResponse searchResponse = mapper.readValue(entityPayload, SearchResponse.class);
+
+ assertEquals(0, searchResponse.getTotalFound());
+ assertEquals(0, searchResponse.getSuggestions().size());
+
+ }
+
+ private void addSuggestions(int numSuggestions, String suggestionPrefix, Suggester suggester) {
+ for ( int x = 0; x < numSuggestions; x++ ){
+ CommonSearchSuggestion suggestion = new CommonSearchSuggestion();
+ suggestion.setText(suggestionPrefix + "-" + x);
+ suggester.addSuggestion(suggestion);
+ }
+ }
+
+ private int countSuggestions(String suggestionPrefix, SearchResponse response) {
+
+ int totalFound = 0;
+
+ for ( SearchSuggestion suggestion : response.getSuggestions()) {
+
+ if ( suggestion.getText() != null && suggestion.getText().startsWith(suggestionPrefix)) {
+ totalFound++;
+ }
+ }
+
+ return totalFound;
+
+ }
+
+ private int countSuggestions(String suggestionPrefix, MockSearchResponse response) {
+
+ int totalFound = 0;
+
+ for ( SearchSuggestion suggestion : response.getSuggestions()) {
+
+ if ( suggestion.getText() != null && suggestion.getText().startsWith(suggestionPrefix)) {
+ totalFound++;
+ }
+ }
+
+ return totalFound;
+
+ }
+
+
+ @Test
+ public void testSearch_search_when_ThreeSearchProviders_5suggestions_each() throws IOException {
+
+ // mock env setup
+
+ initializeSearchMocks(getSearchRequestJson("vnfs",10));
+
+ SearchProviderRegistry searchProviderRegistry = new SearchProviderRegistry();
+
+ AlphaSearchProvider alpha = new AlphaSearchProvider();
+ BravoSearchProvider bravo = new BravoSearchProvider();
+ GammaSearchProvider gamma = new GammaSearchProvider();
+
+ addSuggestions(5, "alpha", alpha);
+ addSuggestions(5, "bravo", bravo);
+ addSuggestions(5, "gamma", gamma);
+
+ searchProviderRegistry.addSearchProvider(alpha);
+ searchProviderRegistry.addSearchProvider(bravo);
+ searchProviderRegistry.addSearchProvider(gamma);
+
+ unifiedSearchProcessor.setSearchProviderRegistry(searchProviderRegistry);
+
+ // method under test
+ unifiedSearchProcessor.search(exchange);
+
+ assertEquals(200, exchange.getOut().getHeader(Exchange.HTTP_RESPONSE_CODE));
+
+ String entityPayload = exchange.getOut().getBody(String.class);
+ assertNotNull(entityPayload);
+
+ MockSearchResponse searchResponse = mapper.readValue(entityPayload, MockSearchResponse.class);
+
+ assertEquals(10, searchResponse.getTotalFound());
+ assertEquals(10, searchResponse.getSuggestions().size());
+
+ assertEquals( 4, countSuggestions("alpha", searchResponse));
+ assertEquals( 3, countSuggestions("bravo", searchResponse));
+ assertEquals( 3, countSuggestions("gamma", searchResponse));
+
+ }
+
+ @Test
+ public void testSearch_search_when_ThreeSearchProviders_mixedNumSuggestions() throws IOException {
+
+ // mock env setup
+
+ initializeSearchMocks(getSearchRequestJson("vnfs",13));
+
+ SearchProviderRegistry searchProviderRegistry = new SearchProviderRegistry();
+
+ AlphaSearchProvider alpha = new AlphaSearchProvider();
+ BravoSearchProvider bravo = new BravoSearchProvider();
+ GammaSearchProvider gamma = new GammaSearchProvider();
+
+ searchProviderRegistry.addSearchProvider(alpha);
+ searchProviderRegistry.addSearchProvider(bravo);
+ searchProviderRegistry.addSearchProvider(gamma);
+
+ unifiedSearchProcessor.setSearchProviderRegistry(searchProviderRegistry);
+
+ addSuggestions(45,"alpha",alpha);
+ addSuggestions(1,"bravo",bravo);
+ addSuggestions(99,"gamma",gamma);
+
+ // method under test
+ unifiedSearchProcessor.search(exchange);
+
+ assertEquals(200, exchange.getOut().getHeader(Exchange.HTTP_RESPONSE_CODE));
+
+ String entityPayload = exchange.getOut().getBody(String.class);
+ assertNotNull(entityPayload);
+
+ MockSearchResponse searchResponse = mapper.readValue(entityPayload, MockSearchResponse.class);
+
+ assertEquals(13, searchResponse.getTotalFound());
+ assertEquals(13, searchResponse.getSuggestions().size());
+
+ /**
+ * There should be an even divide of suggestions per search provider relative
+ * to the suggestions available per search provider.
+ * Alpha has 45 suggestions
+ * Bravo has 1 suggestion
+ * Gamma has 99 suggestions
+ *
+ * We only asked for 13 suggestions to be returned, so based on the suggestion
+ * distribution algorithm we will get a fair distribution of suggestions per provider
+ * relative to what each provider has available. Resulting in:
+ * 6 from Alpha
+ * 1 from Bravo
+ * 6 from Gamma
+ *
+ */
+
+ assertEquals( 6, countSuggestions("alpha", searchResponse));
+ assertEquals( 1, countSuggestions("bravo", searchResponse));
+ assertEquals( 6, countSuggestions("gamma", searchResponse));
+
+ }
+
+ @Test
+ public void testSearch_search_when_ThreeSearchProviders_wantedMoreSuggestionsThanAvailable() throws IOException {
+
+ // mock env setup
+
+ initializeSearchMocks(getSearchRequestJson("vnfs",13));
+
+ SearchProviderRegistry searchProviderRegistry = new SearchProviderRegistry();
+
+ AlphaSearchProvider alpha = new AlphaSearchProvider();
+ BravoSearchProvider bravo = new BravoSearchProvider();
+ GammaSearchProvider gamma = new GammaSearchProvider();
+
+ searchProviderRegistry.addSearchProvider(alpha);
+ searchProviderRegistry.addSearchProvider(bravo);
+ searchProviderRegistry.addSearchProvider(gamma);
+
+ unifiedSearchProcessor.setSearchProviderRegistry(searchProviderRegistry);
+
+ addSuggestions(1,"alpha",alpha);
+ addSuggestions(4,"bravo",bravo);
+ addSuggestions(0,"gamma",gamma);
+
+ // method under test
+ unifiedSearchProcessor.search(exchange);
+
+ assertEquals(200, exchange.getOut().getHeader(Exchange.HTTP_RESPONSE_CODE));
+
+ String entityPayload = exchange.getOut().getBody(String.class);
+ assertNotNull(entityPayload);
+
+ MockSearchResponse searchResponse = mapper.readValue(entityPayload, MockSearchResponse.class);
+
+ assertEquals(5, searchResponse.getTotalFound());
+ assertEquals(5, searchResponse.getSuggestions().size());
+
+ assertEquals( 1, countSuggestions("alpha", searchResponse));
+ assertEquals( 4, countSuggestions("bravo", searchResponse));
+ assertEquals( 0, countSuggestions("gamma", searchResponse));
+
+ }
+} \ No newline at end of file
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/config/SuggestionConfigTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/config/SuggestionConfigTest.java
new file mode 100644
index 0000000..864b7ff
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/config/SuggestionConfigTest.java
@@ -0,0 +1,42 @@
+package org.onap.aai.sparky.search.config;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+
+import org.junit.Before;
+import org.junit.Test;
+public class SuggestionConfigTest {
+
+
+ private SuggestionConfig suggestionsConfig;
+ private ArrayList<String> stopWords;
+ private HashMap<String,String> pairs;
+ @Before
+ public void init() throws Exception{
+
+ suggestionsConfig = new SuggestionConfig();
+ stopWords = new ArrayList<String>();
+ pairs = new HashMap<String,String>();
+
+
+ }
+
+ @Test
+ public void updateValues(){
+
+ suggestionsConfig.setStopWords(stopWords);
+ assertNotNull(suggestionsConfig.getStopWords());
+ suggestionsConfig.setPairingList(pairs);
+ assertNotNull(suggestionsConfig.getPairingList());
+ suggestionsConfig.setDefaultPairingValue("with");
+ assertNotNull(suggestionsConfig.getDefaultPairingValue());
+ suggestionsConfig.setViSuggestionRoute("schema");
+ assertNotNull(suggestionsConfig.getViSuggestionRoute());
+
+ }
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/entity/MockSearchResponse.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/entity/MockSearchResponse.java
new file mode 100644
index 0000000..02a1aee
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/entity/MockSearchResponse.java
@@ -0,0 +1,71 @@
+package org.onap.aai.sparky.search.entity;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.onap.aai.sparky.common.search.CommonSearchSuggestion;
+
+public class MockSearchResponse {
+ private long processingTimeInMs;
+ private int totalFound;
+
+ private List<CommonSearchSuggestion> suggestions;
+
+ /**
+ * Instantiates a new search response.
+ */
+ public MockSearchResponse() {
+ this.suggestions = new ArrayList<CommonSearchSuggestion>();
+ this.processingTimeInMs = 0;
+ this.totalFound = 0;
+ }
+
+ public long getProcessingTimeInMs() {
+ return processingTimeInMs;
+ }
+
+ public void setProcessingTimeInMs(long processingTimeInMs) {
+ this.processingTimeInMs = processingTimeInMs;
+ }
+
+ public int getTotalFound() {
+ return totalFound;
+ }
+
+ public void setTotalFound(int totalFound) {
+ this.totalFound = totalFound;
+ }
+
+ public List<CommonSearchSuggestion> getSuggestions() {
+ return suggestions;
+ }
+
+ public void setSuggestions(List<CommonSearchSuggestion> suggestions) {
+ this.suggestions = suggestions;
+ }
+
+ /**
+ * Adds the entity entry.
+ *
+ * @param suggestionEntry that will be converted to JSON
+ */
+ public void addSuggestion(CommonSearchSuggestion suggestionEntity){
+ suggestions.add(suggestionEntity);
+ }
+
+ /**
+ * Increments the total number of hits for this SearchResponse by
+ * the value passed in.
+ *
+ * @param additionalCount - Count to increment the total found
+ */
+ public void addToTotalFound(int additionalCount) {
+ totalFound += additionalCount;
+ }
+
+ @Override
+ public String toString() {
+ return "DummySearchResponse [processingTimeInMs=" + processingTimeInMs + ", totalFound="
+ + totalFound + ", suggestions=" + suggestions + "]";
+ }
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/filters/FilterProcessorTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/filters/FilterProcessorTest.java
new file mode 100644
index 0000000..0644a53
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/filters/FilterProcessorTest.java
@@ -0,0 +1,374 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+
+package org.onap.aai.sparky.search.filters;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.json.Json;
+import javax.json.JsonArray;
+import javax.json.JsonObject;
+import javax.json.JsonReader;
+import javax.json.stream.JsonParsingException;
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.Exchange;
+import org.apache.camel.Message;
+import org.apache.camel.component.restlet.RestletConstants;
+import org.apache.camel.impl.DefaultCamelContext;
+import org.apache.camel.impl.DefaultExchange;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mockito;
+import org.onap.aai.restclient.enums.RestAuthenticationMode;
+import org.onap.aai.sparky.config.SparkyResourceLoader;
+import org.onap.aai.sparky.dal.ElasticSearchAdapter;
+import org.onap.aai.sparky.dal.rest.RestClientConstructionException;
+import org.onap.aai.sparky.dal.rest.config.RestEndpointConfig;
+import org.onap.aai.sparky.search.filters.FilterProcessor;
+import org.onap.aai.sparky.search.filters.FilteredSearchHelper;
+import org.onap.aai.sparky.search.filters.config.UiFilterConfig;
+import org.onap.aai.sparky.search.filters.config.UiFilterListItemConfig;
+import org.onap.aai.sparky.search.filters.config.UiFilterOptionsValuesConfig;
+import org.onap.aai.sparky.search.filters.config.FiltersDetailsConfig;
+import org.onap.aai.sparky.search.filters.config.FiltersConfig;
+import org.onap.aai.sparky.search.filters.config.UiViewListItemConfig;
+import org.onap.aai.sparky.search.filters.entity.DiscoverFiltersRequest;
+import org.onap.aai.sparky.search.filters.entity.ViewConfiguration;
+import org.onap.aai.sparky.search.filters.entity.ViewFilter;
+import org.onap.aai.sparky.util.HttpServletHelper;
+import org.onap.aai.sparky.util.NodeUtils;
+import org.onap.aai.sparky.util.SparkyTestConstants;
+import org.onap.aai.sparky.search.filters.config.FiltersForViewsConfig;
+import org.restlet.Request;
+import org.restlet.Response;
+import org.restlet.data.MediaType;
+import org.restlet.data.Status;
+import org.springframework.core.io.DefaultResourceLoader;
+
+import com.fasterxml.jackson.core.JsonParseException;
+import com.fasterxml.jackson.databind.JsonMappingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+public class FilterProcessorTest {
+
+ private FilterProcessor filterProcessor;
+ private FilteredSearchHelper filteredSearchHelper;
+ private ObjectMapper mapper;
+ private RestEndpointConfig restEndpointConfig;
+
+ private Exchange exchange;
+ private CamelContext camelContext;
+ private Message mockRequestMessage;
+
+
+ protected UiViewListItemConfig generateViewConfig(ViewConfiguration viewConfig) {
+
+ UiViewListItemConfig uiViewConfig = new UiViewListItemConfig(viewConfig.getViewName(), null);
+
+ List<UiFilterListItemConfig> filters = new ArrayList<UiFilterListItemConfig>();
+
+ for (ViewFilter viewFilter : viewConfig.getViewFilters()) {
+ filters.add(new UiFilterListItemConfig(viewFilter.getId(), viewFilter.getDefaultValue()));
+ }
+
+ uiViewConfig.setListOfFilters(filters);
+
+ return uiViewConfig;
+ }
+
+ protected FiltersConfig generateDefaultViewsFilterConfig() {
+
+ FiltersForViewsConfig uiViewsConfig = new FiltersForViewsConfig();
+ FiltersConfig viewFilterConfig = new FiltersConfig();
+
+ List<UiViewListItemConfig> views = new ArrayList<UiViewListItemConfig>();
+
+ // Default filter value to use below
+ UiFilterOptionsValuesConfig defaultValue = new UiFilterOptionsValuesConfig("Today", "Last 0 hours");
+
+ // VNF View - 4 Filters
+ ViewConfiguration vnfViewConfig = new ViewConfiguration("vnfSearch");
+ vnfViewConfig.addViewFilter(new ViewFilter("1", null));
+ vnfViewConfig.addViewFilter(new ViewFilter("2", null));
+ vnfViewConfig.addViewFilter(new ViewFilter("7", null));
+ vnfViewConfig.addViewFilter(new ViewFilter("8", null));
+ views.add(generateViewConfig(vnfViewConfig));
+
+ // View and Inspect (Schema) - 0 Filters
+ ViewConfiguration viewInspectConfig = new ViewConfiguration("viewInspect");
+ views.add(generateViewConfig(viewInspectConfig));
+
+ // Data Integrity - 4 Filters
+ ViewConfiguration dataIntegrityConfig = new ViewConfiguration("dataIntegrity");
+ dataIntegrityConfig.addViewFilter(new ViewFilter("3", null));
+ dataIntegrityConfig.addViewFilter(new ViewFilter("4", null));
+ dataIntegrityConfig.addViewFilter(new ViewFilter("5", defaultValue));
+ dataIntegrityConfig.addViewFilter(new ViewFilter("6", null));
+ views.add(generateViewConfig(dataIntegrityConfig));
+
+ uiViewsConfig.setViews(views);
+
+ viewFilterConfig.setViewsConfig(uiViewsConfig);
+
+ List<UiFilterOptionsValuesConfig> optionsValues = new ArrayList<UiFilterOptionsValuesConfig>();
+ optionsValues.add(new UiFilterOptionsValuesConfig("Today", "Last 0 hours"));
+ optionsValues.add(new UiFilterOptionsValuesConfig("Since Yesterday", "Last 24 hours"));
+ optionsValues.add(new UiFilterOptionsValuesConfig("Since Last Week", "Last 7 days"));
+ optionsValues.add(new UiFilterOptionsValuesConfig("Since Last Month", "Last 30 days"));
+ optionsValues.add(new UiFilterOptionsValuesConfig("Custom Range", "Custom Range"));
+
+
+
+ FiltersDetailsConfig uiFiltersConfig = new FiltersDetailsConfig();
+
+ List<UiFilterConfig> uiFilterConfig = new ArrayList<UiFilterConfig>();
+ uiFilterConfig.add(new UiFilterConfig("1", "filterName1", "Display Name 1", "dropDown", "false", "Any 1", null, "options", null, null));
+ uiFilterConfig.add(new UiFilterConfig("2", "filterName2", "Display Name 2", "dropDown", "false", "Any 2", null, "options", null, null));
+ uiFilterConfig.add(new UiFilterConfig("3", "filterName3", "Display Name 3", "dropDown", "false", "Any 3", null, "options", null, null));
+ uiFilterConfig.add(new UiFilterConfig("4", "filterName4", "Display Name 4", "dropDown", "false", "Any 4", null, "options", null, null));
+ uiFilterConfig.add(new UiFilterConfig("5", "filterName5", "Display Name 5", "date", "false", "Any 5", defaultValue, "dynamicOptions", optionsValues, null));
+ uiFilterConfig.add(new UiFilterConfig("6", "filterName6", "Display Name 6", "dropDown", "false", "Any 6", null, "options", null, null));
+ uiFilterConfig.add(new UiFilterConfig("7", "filterName7", "Display Name 7", "dropDown", "false", "Any 7", null, "options", null, null));
+ uiFilterConfig.add(new UiFilterConfig("8", "filterName8", "Display Name 8", "dropDown", "false", "Any 8", null, "options", null, null));
+
+ uiFiltersConfig.setFilters(uiFilterConfig);
+
+ viewFilterConfig.setFiltersConfig(uiFiltersConfig);
+
+ return viewFilterConfig;
+ }
+
+ @Before
+ public void init()throws RestClientConstructionException {
+
+ camelContext = new DefaultCamelContext();
+ exchange = new DefaultExchange(camelContext);
+
+ mockRequestMessage = Mockito.mock(Message.class);
+
+ exchange.setIn(mockRequestMessage);
+
+ //TODO-> edit the following:FilteredSearchHelper & FilterProcessor to pass in the correct parameters
+ restEndpointConfig = new RestEndpointConfig();
+ restEndpointConfig.setRestAuthenticationMode(RestAuthenticationMode.SSL_BASIC);
+ filteredSearchHelper = new FilteredSearchHelper(new FiltersConfig(),
+ new FilterElasticSearchAdapter(new ElasticSearchAdapter(restEndpointConfig)));
+ filterProcessor = new FilterProcessor();
+
+ mapper = new ObjectMapper();
+ }
+
+
+ @Test
+ public void validateDefaultConstructor() {
+ assertNotNull(filterProcessor.getMapper());
+ assertNull(filterProcessor.getFilteredSearchHelper());
+ }
+
+ private void verifyResponseAndNumFiltersForBadRequest(Exchange exchange, Status expectedStatus, int numExpectedFilters)
+ throws JsonParseException, JsonMappingException, IOException {
+
+ assertEquals(expectedStatus.getCode(), exchange.getOut().getHeader(Exchange.HTTP_RESPONSE_CODE));
+
+ String entityPayload = exchange.getOut().getBody(String.class);
+ assertNotNull(entityPayload);
+
+ JsonReader jsonReader = Json.createReader(new StringReader(entityPayload));
+ JsonObject responsePayload = jsonReader.readObject();
+
+ JsonObject filters = responsePayload.getJsonObject("filters");
+ assertEquals(0, filters.size());
+ }
+
+ private void initializeMocks(String requestPayload) throws IOException {
+
+ HttpServletRequest request = Mockito.mock(HttpServletRequest.class);
+ if ( requestPayload != null) {
+ HttpServletHelper.setRequestPayload(request, "application/json", requestPayload);
+ }
+
+ Mockito.when(request.getRequestURI()).thenReturn("fakeUri");
+ Mockito.when(request.getLocalPort()).thenReturn(8001);
+ Mockito.when(mockRequestMessage.getBody(Mockito.eq(HttpServletRequest.class))).thenReturn(request);
+ Mockito.when(mockRequestMessage.getBody(Mockito.eq(String.class))).thenReturn(requestPayload);
+
+ SparkyResourceLoader resourceLoader = new SparkyResourceLoader();
+ resourceLoader.setResourceLoader(new DefaultResourceLoader());
+
+ filterProcessor.setFilteredSearchHelper(filteredSearchHelper);
+
+ FiltersConfig filtersConfig = new FiltersConfig();
+ filtersConfig.initializeFiltersDetailsConfig(resourceLoader.getResourceAsFile(SparkyTestConstants.FILTERS_JSON_FILE, false));
+ filtersConfig.initializeFiltersForViewsConfig(resourceLoader.getResourceAsFile(SparkyTestConstants.VIEWS_JSON_FILE, false));
+
+ filteredSearchHelper.setFiltersConfig(filtersConfig);
+
+ }
+
+
+ @Test
+ public void testGetFiltersWithValues_success_path() throws IOException {
+
+ // Initialize for call against 'vnfSearch'
+ DiscoverFiltersRequest vnfSearchrequest = new DiscoverFiltersRequest();
+ vnfSearchrequest.setViewName("vnfSearch");
+
+ initializeMocks(NodeUtils.convertObjectToJson(vnfSearchrequest, false));
+
+ // Test call against 'vnfSearch'
+ filterProcessor.getFiltersWithValues(exchange);
+
+ assertEquals(200, exchange.getOut().getHeader(Exchange.HTTP_RESPONSE_CODE));
+
+ String entityPayload = exchange.getOut().getBody(String.class);
+ assertNotNull(entityPayload);
+
+ JsonReader vnfJsonReader = Json.createReader(new StringReader(entityPayload));
+ JsonObject vnfResponsePayload = vnfJsonReader.readObject();
+
+ JsonObject vnfFilters = vnfResponsePayload.getJsonObject("filters");
+ assertNotNull(vnfFilters);
+ assertEquals(0, vnfFilters.size());
+
+ //JsonObject filterOne = vnfFilters.getJsonObject("1");
+ //assertNotNull(filterOne);
+ //assertEquals("Display Name 1", filterOne.getString("label"));
+
+ JsonObject filterEight = vnfFilters.getJsonObject("8");
+ //assertNotNull(filterEight);
+ // JsonObject eightInnerControl = filterEight.getJsonObject("controls").getJsonObject("filterName8");
+ // assertEquals(4, eightInnerControl.size());
+ //assertEquals("dropDown", eightInnerControl.getString("type"));
+ //assertEquals("false", eightInnerControl.getString("multiSelect"));
+ //assertEquals("Any 8", eightInnerControl.getString("watermark"));
+ //assertEquals(0, eightInnerControl.getJsonArray("options").size());
+
+ // Initialize for call against 'dataIntegrity'
+ DiscoverFiltersRequest dataIntegrityRequest = new DiscoverFiltersRequest();
+ dataIntegrityRequest.setViewName("dataIntegrity");
+
+ initializeMocks(NodeUtils.convertObjectToJson(dataIntegrityRequest, false));
+
+ // Test call against 'dataIntegrity'
+ filterProcessor.getFiltersWithValues(exchange);
+
+ assertEquals(200, exchange.getOut().getHeader(Exchange.HTTP_RESPONSE_CODE));
+
+ entityPayload = exchange.getOut().getBody(String.class);
+ assertNotNull(entityPayload);
+
+ JsonReader dIJsonReader = Json.createReader(new StringReader(entityPayload));
+ JsonObject dIResponsePayload = dIJsonReader.readObject();
+
+ JsonObject dIFilters = dIResponsePayload.getJsonObject("filters");
+ assertNotNull(dIFilters);
+ // assertEquals(4, dIFilters.size());
+
+ //JsonObject filterFour = dIFilters.getJsonObject("4");
+ //// assertNotNull(filterFour);
+ // assertEquals("Display Name 4", filterFour.getString("label"));
+
+ JsonObject filterFive = dIFilters.getJsonObject("5");
+ //assertNotNull(filterFive);
+ //JsonObject fiveInnerControl = filterFive.getJsonObject("controls").getJsonObject("filterName5");
+ //assertEquals(5, fiveInnerControl.size());
+ //assertEquals("date", fiveInnerControl.getString("type"));
+ // assertEquals("false", fiveInnerControl.getString("multiSelect"));
+ //assertEquals("Any 5", fiveInnerControl.getString("watermark"));
+ // JsonArray dynamicOptions = fiveInnerControl.getJsonArray("dynamicOptions");
+ //assertEquals(5, dynamicOptions.size());
+ //JsonObject today = dynamicOptions.getJsonObject(0);
+ //assertEquals("Today", today.getString("decode"));
+ }
+
+ @Test
+ public void testGetFiltersWithValues_viewNameNull() throws IOException {
+
+ DiscoverFiltersRequest discoverFiltersRequest = new DiscoverFiltersRequest();
+ initializeMocks(NodeUtils.convertObjectToJson(discoverFiltersRequest, false));
+
+ // Method under test
+ filterProcessor.getFiltersWithValues(exchange);
+
+ verifyResponseAndNumFiltersForBadRequest(exchange, Status.CLIENT_ERROR_NOT_FOUND, 0);
+ }
+
+ @Test
+ public void testGetFiltersWithValues_viewNameEmptyString() throws IOException {
+
+ DiscoverFiltersRequest discoverFiltersRequest = new DiscoverFiltersRequest();
+ discoverFiltersRequest.setViewName("");
+
+ initializeMocks(NodeUtils.convertObjectToJson(discoverFiltersRequest, false));
+
+ // Method under test
+ filterProcessor.getFiltersWithValues(exchange);
+
+ verifyResponseAndNumFiltersForBadRequest(exchange, Status.CLIENT_ERROR_NOT_FOUND, 0);
+ }
+
+ @Test
+ public void testGetFiltersWithValues_requestPayloadIsNull() throws IOException {
+
+ initializeMocks(null);
+
+ // Method under test
+ filterProcessor.getFiltersWithValues(exchange);
+
+ verifyResponseAndNumFiltersForBadRequest(exchange, Status.CLIENT_ERROR_NOT_FOUND, 0);
+ }
+
+ @Test
+ public void testGetFiltersWithValues_requestPayloadIsEmptyString() throws IOException {
+
+ initializeMocks("");
+
+ // Method under test
+ filterProcessor.getFiltersWithValues(exchange);
+
+ verifyResponseAndNumFiltersForBadRequest(exchange, Status.CLIENT_ERROR_NOT_FOUND, 0);
+ }
+
+ @Test(expected=JsonParsingException.class)
+ public void testGetFiltersWithValues_requestPayloadCausesException() throws IOException {
+
+ initializeMocks("{");
+
+ // Method under test
+ filterProcessor.getFiltersWithValues(exchange);
+
+ verifyResponseAndNumFiltersForBadRequest(exchange, Status.SERVER_ERROR_INTERNAL, 0);
+ }
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/filters/FilteredSearchHelperTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/filters/FilteredSearchHelperTest.java
new file mode 100644
index 0000000..56afcf9
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/filters/FilteredSearchHelperTest.java
@@ -0,0 +1,69 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+
+package org.onap.aai.sparky.search.filters;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.IOException;
+
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.onap.aai.sparky.search.filters.FilteredSearchHelper;
+import org.onap.aai.sparky.search.filters.config.FiltersConfig;
+/*
+public class FilteredSearchHelperTest {
+
+ private static FilteredSearchHelper filteredSearchHelper;
+
+ @BeforeClass
+ public static void init() throws IOException {
+ FiltersConfig config = FiltersConfig.getInstance();
+ config.setFilterMappingsFileName("src/test/resources/filters/aaiui_views.json");
+ config.setFiltersFileName("src/test/resources/filters/aaiui_filters.json");
+ System.out.println("SETTING UIVIEWSCONFIG");
+ config.setViewsConfig(config.readUiViewsConfig());
+ System.out.println("SETTING UIFILTERSCONFIG");
+ config.setFiltersConfig(config.readUiFiltersConfig());
+
+ filteredSearchHelper = new FilteredSearchHelper(config);
+ }
+
+ @Test
+ public void testDoFilterDiscovery_validViewName() {
+ assertEquals(4, filteredSearchHelper.doFilterDiscovery("vnfSearch").getFilters().size());
+ assertEquals(4, filteredSearchHelper.doFilterDiscovery("dataIntegrity").getFilters().size());
+ }
+
+ @Test
+ public void testDoFilterDiscovery_invalidViewName_nameGiven() {
+ assertEquals(0, filteredSearchHelper.doFilterDiscovery("InvalidViewName").getFilters().size());
+ }
+
+ @Test
+ public void testDoFilterDiscovery_invalidViewName_emptyString() {
+ assertEquals(0, filteredSearchHelper.doFilterDiscovery("").getFilters().size());
+ }
+}*/
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/filters/config/FiltersConfigTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/filters/config/FiltersConfigTest.java
new file mode 100644
index 0000000..54ebe99
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/filters/config/FiltersConfigTest.java
@@ -0,0 +1,47 @@
+package org.onap.aai.sparky.search.filters.config;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.ArrayList;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.onap.aai.sparky.viewandinspect.config.VisualizationConfigs;
+
+public class FiltersConfigTest {
+
+ private FiltersConfig filtersConfig;
+ private FiltersForViewsConfig viewsConfig;
+ private FiltersDetailsConfig filtersDetailsConfig;
+
+ @Before
+ public void init() throws Exception {
+ filtersConfig = new FiltersConfig();
+ viewsConfig = new FiltersForViewsConfig();
+ filtersDetailsConfig = new FiltersDetailsConfig();
+
+
+ }
+
+
+ @Test
+ public void updateValues() {
+
+ filtersConfig.setViewsFileName("");
+ assertNotNull(filtersConfig.getViewsFileName());
+ filtersConfig.setFiltersFileName("");
+ assertNotNull(filtersConfig.getFiltersFileName());
+ filtersConfig.setViewsConfig(viewsConfig);
+ assertNotNull(filtersConfig.getViewsConfig());
+ filtersConfig.setFiltersConfig(filtersDetailsConfig);
+ assertNotNull(filtersConfig.getFiltersConfig());
+ assertNull(filtersConfig.getFilterById(""));
+ assertNull(filtersConfig.readUiViewsConfig());
+
+
+ }
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/filters/config/FiltersDetailsConfigTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/filters/config/FiltersDetailsConfigTest.java
new file mode 100644
index 0000000..3bf4842
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/filters/config/FiltersDetailsConfigTest.java
@@ -0,0 +1,40 @@
+package org.onap.aai.sparky.search.filters.config;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.ArrayList;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.onap.aai.sparky.viewandinspect.config.VisualizationConfigs;
+
+public class FiltersDetailsConfigTest {
+
+ private FiltersDetailsConfig filtersDetailsConfig;
+ private ArrayList<UiFilterConfig> filters;
+ private FiltersDetailsConfig filtersDetailsConfigs;
+
+ @Before
+ public void init() throws Exception {
+ filtersDetailsConfig = new FiltersDetailsConfig();
+ filters = new ArrayList<UiFilterConfig>();
+ filtersDetailsConfigs = new FiltersDetailsConfig(filters);
+
+ }
+
+
+ @Test
+ public void updateValues() {
+
+ filtersDetailsConfig.setFilters(filters);
+ assertNotNull(filtersDetailsConfig.getFilters());
+ assertNotNull(filtersDetailsConfig.toString());
+
+
+
+ }
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/filters/config/FiltersForViewsConfigTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/filters/config/FiltersForViewsConfigTest.java
new file mode 100644
index 0000000..7740610
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/filters/config/FiltersForViewsConfigTest.java
@@ -0,0 +1,40 @@
+package org.onap.aai.sparky.search.filters.config;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.ArrayList;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.onap.aai.sparky.viewandinspect.config.VisualizationConfigs;
+
+public class FiltersForViewsConfigTest {
+
+ private FiltersForViewsConfig filtersForView;
+ private ArrayList<UiViewListItemConfig> views;
+ private FiltersForViewsConfig filtersForViews;
+
+ @Before
+ public void init() throws Exception {
+ filtersForView = new FiltersForViewsConfig();
+ views = new ArrayList<UiViewListItemConfig>();
+ filtersForViews = new FiltersForViewsConfig(views);
+
+ }
+
+
+ @Test
+ public void updateValues() {
+
+ filtersForView.setViews(views);
+ assertNotNull(filtersForView.getViews());
+ assertNotNull(filtersForView.toString());
+
+
+
+ }
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/filters/config/UiFilterConfigTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/filters/config/UiFilterConfigTest.java
new file mode 100644
index 0000000..7cd539d
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/filters/config/UiFilterConfigTest.java
@@ -0,0 +1,57 @@
+package org.onap.aai.sparky.search.filters.config;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+
+import java.util.ArrayList;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class UiFilterConfigTest {
+
+ private UiFilterConfig uiFiltersConfig;
+ private UiFilterOptionsValuesConfig defaultValue;
+ private UiFilterDataSourceConfig dataSource;
+ private ArrayList<UiFilterOptionsValuesConfig> optionValues;
+
+
+ @Before
+ public void init() throws Exception {
+ defaultValue = new UiFilterOptionsValuesConfig("","");
+ dataSource = new UiFilterDataSourceConfig();
+ optionValues = new ArrayList<UiFilterOptionsValuesConfig>();
+ uiFiltersConfig = new UiFilterConfig("","","","","","",defaultValue,"",optionValues,dataSource);
+
+
+
+ }
+
+
+ @Test
+ public void updateValues() {
+
+ uiFiltersConfig.setFilterId("");
+ assertNotNull(uiFiltersConfig.getFilterId());
+ uiFiltersConfig.setFilterName("");
+ assertNotNull(uiFiltersConfig.getFilterName());
+ uiFiltersConfig.setDisplayName("");
+ assertNotNull(uiFiltersConfig.getDisplayName());
+ uiFiltersConfig.setDataType("");
+ assertNotNull(uiFiltersConfig.getDataType());
+ uiFiltersConfig.setMultiSelect("");
+ assertNotNull(uiFiltersConfig.getMultiSelect());
+ uiFiltersConfig.setWatermark("");
+ assertNotNull(uiFiltersConfig.getWatermark());
+ uiFiltersConfig.setOptionsType("");
+ assertNotNull(uiFiltersConfig.getOptionsType());
+ uiFiltersConfig.setDataSource(dataSource);
+ assertNotNull(uiFiltersConfig.getDataSource());
+ uiFiltersConfig.setOptionsValues(optionValues);
+ assertNotNull(uiFiltersConfig.getOptionsValues());
+ uiFiltersConfig.setDefaultValue(defaultValue);
+ assertNotNull(uiFiltersConfig.getDefaultValue());
+ assertNotNull(uiFiltersConfig.toString());
+ }
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/filters/config/UiFilterDataSourceConfigTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/filters/config/UiFilterDataSourceConfigTest.java
new file mode 100644
index 0000000..e4402cf
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/filters/config/UiFilterDataSourceConfigTest.java
@@ -0,0 +1,44 @@
+package org.onap.aai.sparky.search.filters.config;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.ArrayList;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.onap.aai.sparky.viewandinspect.config.VisualizationConfigs;
+
+public class UiFilterDataSourceConfigTest {
+
+ private UiFilterDataSourceConfig uiFiltersDataSourceConfig;
+ private UiFilterDataSourceConfig uiFiltersDataSourceConfigs;
+
+
+ @Before
+ public void init() throws Exception {
+
+ uiFiltersDataSourceConfig = new UiFilterDataSourceConfig();
+ uiFiltersDataSourceConfigs = new UiFilterDataSourceConfig("","","","");
+
+
+
+ }
+
+
+ @Test
+ public void updateValues() {
+
+ uiFiltersDataSourceConfig.setIndexName("");
+ assertNotNull(uiFiltersDataSourceConfig.getIndexName());
+ uiFiltersDataSourceConfig.setDocType("");
+ assertNotNull(uiFiltersDataSourceConfig.getDocType());
+ uiFiltersDataSourceConfig.setFieldName("");
+ assertNotNull(uiFiltersDataSourceConfig.getFieldName());
+ uiFiltersDataSourceConfig.setPathToField("");
+ assertNotNull(uiFiltersDataSourceConfig.getPathToField());
+ assertNotNull(uiFiltersDataSourceConfig.toString());
+ }
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/filters/config/UiFilterListItemConfigTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/filters/config/UiFilterListItemConfigTest.java
new file mode 100644
index 0000000..48e7955
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/filters/config/UiFilterListItemConfigTest.java
@@ -0,0 +1,34 @@
+package org.onap.aai.sparky.search.filters.config;
+
+import static org.junit.Assert.assertNotNull;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class UiFilterListItemConfigTest {
+
+ private UiFilterListItemConfig uiFilterLstItem;
+ private UiFilterOptionsValuesConfig defaultValue;
+
+
+ @Before
+ public void init() throws Exception {
+ defaultValue = new UiFilterOptionsValuesConfig("","");
+ uiFilterLstItem = new UiFilterListItemConfig("",defaultValue);
+
+
+
+ }
+
+
+ @Test
+ public void updateValues() {
+
+ uiFilterLstItem.setFilterId("");
+ assertNotNull(uiFilterLstItem.getFilterId());
+ uiFilterLstItem.setDefaultValue(defaultValue);
+ assertNotNull(uiFilterLstItem.getDefaultValue());
+ assertNotNull(uiFilterLstItem.toString());
+ }
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/filters/config/UiFilterOptionsValuesConfigTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/filters/config/UiFilterOptionsValuesConfigTest.java
new file mode 100644
index 0000000..ca15771
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/filters/config/UiFilterOptionsValuesConfigTest.java
@@ -0,0 +1,31 @@
+package org.onap.aai.sparky.search.filters.config;
+
+import static org.junit.Assert.assertNotNull;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class UiFilterOptionsValuesConfigTest {
+
+ private UiFilterOptionsValuesConfig uiFilterOptionsValues;
+
+
+ @Before
+ public void init() throws Exception {
+
+ uiFilterOptionsValues = new UiFilterOptionsValuesConfig("","");
+
+ }
+
+
+ @Test
+ public void updateValues() {
+
+ uiFilterOptionsValues.setCode("");
+ assertNotNull(uiFilterOptionsValues.getCode());
+ uiFilterOptionsValues.setDecode("");
+ assertNotNull(uiFilterOptionsValues.getDecode());
+ assertNotNull(uiFilterOptionsValues.toString());
+ }
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/filters/config/UiViewListItemConfigTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/filters/config/UiViewListItemConfigTest.java
new file mode 100644
index 0000000..39b919f
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/filters/config/UiViewListItemConfigTest.java
@@ -0,0 +1,38 @@
+package org.onap.aai.sparky.search.filters.config;
+
+import static org.junit.Assert.assertNotNull;
+
+import java.util.ArrayList;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class UiViewListItemConfigTest {
+
+ private ArrayList<UiFilterListItemConfig> uiFilterLstItem;
+ private UiViewListItemConfig uiViewLstItem;
+
+
+ @Before
+ public void init() throws Exception {
+
+ uiFilterLstItem = new ArrayList<UiFilterListItemConfig>();
+ uiViewLstItem = new UiViewListItemConfig("",uiFilterLstItem);
+
+
+
+ }
+
+
+ @Test
+ public void updateValues() {
+
+ uiViewLstItem.setViewName("");
+ assertNotNull(uiViewLstItem.getViewName());
+ uiViewLstItem.setListOfFilters(uiFilterLstItem);
+ assertNotNull(uiViewLstItem.getFilters());
+ assertNotNull(uiViewLstItem.toString());
+ }
+
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/filters/entity/DiscoverFiltersRequest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/filters/entity/DiscoverFiltersRequest.java
new file mode 100644
index 0000000..336e3b1
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/filters/entity/DiscoverFiltersRequest.java
@@ -0,0 +1,40 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+
+package org.onap.aai.sparky.search.filters.entity;
+
+public class DiscoverFiltersRequest {
+
+ private String viewName;
+
+ public String getViewName() {
+ return viewName;
+ }
+
+ public void setViewName(String viewName) {
+ this.viewName = viewName;
+ }
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/filters/entity/ViewConfiguration.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/filters/entity/ViewConfiguration.java
new file mode 100644
index 0000000..f6c352b
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/filters/entity/ViewConfiguration.java
@@ -0,0 +1,68 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+
+package org.onap.aai.sparky.search.filters.entity;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class ViewConfiguration {
+
+ private String viewName;
+ private List<ViewFilter> viewFilters;
+
+ public ViewConfiguration() {
+ viewFilters = new ArrayList<ViewFilter>();
+ }
+
+ public ViewConfiguration(String viewName) {
+ viewFilters = new ArrayList<ViewFilter>();
+ this.setViewName(viewName);
+ }
+
+ public String getViewName() {
+ return viewName;
+ }
+
+ public void setViewName(String viewName) {
+ this.viewName = viewName;
+ }
+
+ public List<ViewFilter> getViewFilters() {
+ return viewFilters;
+ }
+
+ public void setViewFilters(List<ViewFilter> viewFilters) {
+ this.viewFilters = viewFilters;
+ }
+
+ public void addViewFilter(ViewFilter viewFilter) {
+ if (viewFilters != null) {
+ if (!viewFilters.contains(viewFilter)) {
+ viewFilters.add(viewFilter);
+ }
+ }
+ }
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/filters/entity/ViewFilter.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/filters/entity/ViewFilter.java
new file mode 100644
index 0000000..94832d5
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/filters/entity/ViewFilter.java
@@ -0,0 +1,57 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+
+package org.onap.aai.sparky.search.filters.entity;
+
+import org.onap.aai.sparky.search.filters.config.UiFilterOptionsValuesConfig;
+
+public class ViewFilter {
+
+ private String id;
+ private UiFilterOptionsValuesConfig defaultValue;
+
+ public ViewFilter() {}
+
+ public ViewFilter(String id, UiFilterOptionsValuesConfig defaultValue) {
+ this.id = id;
+ this.defaultValue = defaultValue;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public UiFilterOptionsValuesConfig getDefaultValue() {
+ return defaultValue;
+ }
+
+ public void setDefaultValue(UiFilterOptionsValuesConfig defaultValue) {
+ this.defaultValue = defaultValue;
+ }
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/security/SecurityContextFactoryImplTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/security/SecurityContextFactoryImplTest.java
new file mode 100644
index 0000000..0c3a8ce
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/security/SecurityContextFactoryImplTest.java
@@ -0,0 +1,143 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+
+package org.onap.aai.sparky.security;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.io.FileInputStream;
+
+import javax.net.ssl.SSLContext;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.onap.aai.sparky.security.SecurityContextFactory;
+import org.onap.aai.sparky.security.SecurityContextFactoryImpl;
+import org.onap.aai.sparky.util.LogValidator;
+
+import ch.qos.logback.classic.Level;
+
+/**
+ * The Class SecurityContextFactoryImplTest.
+ */
+public class SecurityContextFactoryImplTest {
+
+ private LogValidator logValidator;
+
+ /**
+ * Inits the.
+ *
+ * @throws Exception the exception
+ */
+ @Before
+ public void init() throws Exception {
+ logValidator = new LogValidator();
+ logValidator.initializeLogger(Level.WARN);
+ }
+
+ /**
+ * Basic construction test.
+ *
+ * @throws Exception the exception
+ */
+ @Test
+ public void basicConstructionTest() throws Exception {
+
+ SecurityContextFactory sslContextFactory = new SecurityContextFactoryImpl();
+
+ assertEquals("TLS", sslContextFactory.getSslAlgorithm());
+ assertEquals("SunX509", sslContextFactory.getKeyManagerAlgortihm());
+ assertEquals("PKCS12", sslContextFactory.getKeyStoreType());
+ assertEquals(false, sslContextFactory.isServerCertificationChainValidationEnabled());
+ assertEquals(null, sslContextFactory.getClientCertFileInputStream());
+ }
+
+ /**
+ * Validate secure context.
+ *
+ * @throws Exception the exception
+ */
+ @Test
+ public void validateSecureContext() throws Exception {
+
+ SecurityContextFactory sslContextFactory = new SecurityContextFactoryImpl();
+
+ SSLContext sslContext = sslContextFactory.getSecureContext();
+
+ assertNotNull(sslContext);
+ }
+
+ /**
+ * Validate secure context with server cert chain validation.
+ *
+ * @throws Exception the exception
+ */
+ @Test
+ public void validateSecureContext_withServerCertChainValidation() throws Exception {
+
+ SecurityContextFactory sslContextFactory = new SecurityContextFactoryImpl();
+ sslContextFactory.setServerCertificationChainValidationEnabled(true);
+ sslContextFactory.setTrustStoreFileName("filename");
+
+ sslContextFactory.setClientCertFileName(null);
+
+ SSLContext sslContext = sslContextFactory.getSecureContext();
+
+ assertNotNull(sslContext);
+ }
+
+ /**
+ * Validate accessors.
+ *
+ * @throws Exception the exception
+ */
+ @Test
+ public void validateAccessors() throws Exception {
+
+ SecurityContextFactory sslContextFactory = new SecurityContextFactoryImpl();
+
+ FileInputStream mockInputStream = Mockito.mock(FileInputStream.class);
+
+ sslContextFactory.setSslAlgorithm("sslAlgorithm");
+ sslContextFactory.setKeyManagerAlgortihm("keyManagerAlgorithm");
+ sslContextFactory.setKeyStoreType("keyStoreType");
+ sslContextFactory.setClientCertFileInputStream(mockInputStream);
+ sslContextFactory.setServerCertificationChainValidationEnabled(true);
+ sslContextFactory.setTrustStoreFileName("truststoreFileName");
+ sslContextFactory.setClientCertPassword("password");
+
+ assertEquals("sslAlgorithm", sslContextFactory.getSslAlgorithm());
+ assertEquals("keyManagerAlgorithm", sslContextFactory.getKeyManagerAlgortihm());
+ assertEquals("keyStoreType", sslContextFactory.getKeyStoreType());
+ assertEquals(mockInputStream, sslContextFactory.getClientCertFileInputStream());
+ assertEquals(true, sslContextFactory.isServerCertificationChainValidationEnabled());
+ assertEquals("truststoreFileName", sslContextFactory.getTrustStoreFileName());
+ assertEquals("password", sslContextFactory.getClientCertPassword());
+
+ }
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/security/portal/TestPortalRestAPIServiceImpl.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/security/portal/TestPortalRestAPIServiceImpl.java
new file mode 100644
index 0000000..bdd9093
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/security/portal/TestPortalRestAPIServiceImpl.java
@@ -0,0 +1,283 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ *
+
+package org.onap.aai.sparky.security.portal;
+
+import static org.hamcrest.Matchers.empty;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.nullValue;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Mockito.when;
+
+import java.io.File;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.onap.aai.sparky.security.portal.PortalRestAPIServiceImpl;
+import org.onap.aai.sparky.security.portal.UserManager;
+import org.onap.aai.sparky.security.portal.config.PortalAuthenticationConfig;
+import org.onap.aai.sparky.security.portal.config.RolesConfig;
+import org.openecomp.portalsdk.core.onboarding.exception.PortalAPIException;
+import org.openecomp.portalsdk.core.restful.domain.EcompRole;
+import org.openecomp.portalsdk.core.restful.domain.EcompUser;
+import org.powermock.core.classloader.annotations.PowerMockIgnore;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+import org.powermock.reflect.Whitebox;
+
+@PowerMockIgnore({ "javax.crypto.*" })
+@RunWith(PowerMockRunner.class)
+@PrepareForTest({ PortalAuthenticationConfig.class, RolesConfig.class })
+public class TestPortalRestAPIServiceImpl {
+
+ private static File testUsersFile;
+ private static final String LOGINID_1 = "200";
+ private static final String LOGINID_2 = "201";
+ private static final String VIEW_ROLE = "View";
+
+ enum TestData {
+ // @formatter:off
+ TEST_USERS ("src/test/resources/portal/test-users.config"),
+ PORTAL_AUTHENTICATION_PROPERTIES ("src/test/resources/portal/portal-authentication.properties"),
+ ROLES_CONFIG_FILE ("src/test/resources/portal/roles.config");
+
+ private String filename;
+ TestData(String filename) {this.filename = filename;}
+ public String getFilename() {return this.filename;}
+ // @formatter:on
+ }
+
+ @Mock
+ private UserManager userManager = new UserManager(testUsersFile);
+
+ @InjectMocks
+ private PortalRestAPIServiceImpl portalApi = new PortalRestAPIServiceImpl();
+
+ @BeforeClass
+ public static void setUpBeforeClass() throws Exception {
+ testUsersFile = Paths.get(TestData.TEST_USERS.getFilename()).toFile();
+ }
+
+ @AfterClass
+ public static void tearDownAfterClass() throws Exception {
+ Files.deleteIfExists(testUsersFile.toPath());
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ Whitebox.setInternalState(RolesConfig.class, "ROLES_CONFIG_FILE",
+ TestData.ROLES_CONFIG_FILE.getFilename());
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ Files.deleteIfExists(testUsersFile.toPath());
+ }
+
+ @Test
+ public void testPushAndGetUser() throws Exception {
+ EcompUser user = new EcompUser();
+ user.setLoginId(LOGINID_1);
+
+ portalApi.pushUser(user);
+ EcompUser storedUser = portalApi.getUser(user.getLoginId());
+
+ assertThat(storedUser.getLoginId(), is(user.getLoginId()));
+ }
+
+ @Test(expected = PortalAPIException.class)
+ public void testCannotPushUserTwice() throws Exception {
+ EcompUser user = new EcompUser();
+ user.setLoginId(LOGINID_1);
+
+ portalApi.pushUser(user);
+ portalApi.pushUser(user);
+ }
+
+ @Test(expected = PortalAPIException.class)
+ public void testGetUnknownUser() throws Exception {
+ EcompUser user = new EcompUser();
+ user.setLoginId(LOGINID_1);
+ portalApi.pushUser(user);
+
+ portalApi.getUser("does-not-exist");
+ }
+
+ @Test
+ public void testGetUsers() throws Exception {
+ EcompUser user = new EcompUser();
+ user.setLoginId(LOGINID_1);
+
+ EcompUser user2 = new EcompUser();
+ user2.setLoginId(LOGINID_2);
+
+ portalApi.pushUser(user);
+ portalApi.pushUser(user2);
+
+ List<EcompUser> users = portalApi.getUsers();
+
+ assertThat(users.size(), is(2));
+ assertThat(users.get(0).getLoginId(), is(LOGINID_1));
+ assertThat(users.get(1).getLoginId(), is(LOGINID_2));
+ }
+
+ @Test
+ public void testEditUser() throws Exception {
+ EcompUser user = new EcompUser();
+ user.setLoginId(LOGINID_1);
+ user.setFirstName("Bob");
+
+ portalApi.pushUser(user);
+
+ user.setFirstName("Jen");
+ portalApi.editUser(LOGINID_1, user);
+
+ assertThat(portalApi.getUser(LOGINID_1).getFirstName(), is("Jen"));
+ }
+
+ @Test(expected = PortalAPIException.class)
+ public void testEditUnknowUser() throws Exception {
+ EcompUser user = new EcompUser();
+ user.setLoginId(LOGINID_1);
+ portalApi.pushUser(user);
+
+ portalApi.editUser("does-no-exist", new EcompUser());
+ }
+
+ @Test
+ public void testGetRoles() throws Exception {
+ EcompUser user = new EcompUser();
+ user.setLoginId(LOGINID_1);
+ user.setRoles(new HashSet<>(portalApi.getAvailableRoles()));
+
+ portalApi.pushUser(user);
+
+ List<EcompRole> userRoles = portalApi.getUserRoles(LOGINID_1);
+
+ assertThat(userRoles.size(), is(1));
+ assertThat(userRoles.get(0).getId(), is(1L));
+ assertThat(userRoles.get(0).getName(), is(VIEW_ROLE));
+ }
+
+ @Test
+ public void testPushUserRoles() throws Exception {
+ EcompUser user = new EcompUser();
+ user.setLoginId(LOGINID_1);
+ portalApi.pushUser(user);
+
+ EcompUser storedUser = portalApi.getUser(LOGINID_1);
+ assertThat(storedUser.getRoles(), nullValue());
+
+ portalApi.pushUserRole(LOGINID_1, UserManager.getRoles());
+
+ Set<EcompRole> storedUserRoles = portalApi.getUser(LOGINID_1).getRoles();
+ ArrayList<EcompRole> rolesList = new ArrayList<>(storedUserRoles);
+
+ assertThat(rolesList.size(), is(1));
+ assertThat(rolesList.get(0).getId(), is(1L));
+ assertThat(rolesList.get(0).getName(), is(VIEW_ROLE));
+ }
+
+ @Test
+ public void testCannotPushRoleTwice() throws Exception {
+ EcompUser user = new EcompUser();
+ user.setLoginId(LOGINID_1);
+ portalApi.pushUser(user);
+
+ EcompUser storedUser = portalApi.getUser(LOGINID_1);
+ assertThat(storedUser.getRoles(), nullValue());
+
+ portalApi.pushUserRole(LOGINID_1, UserManager.getRoles());
+ portalApi.pushUserRole(LOGINID_1, UserManager.getRoles());
+
+ Set<EcompRole> storedUserRoles = portalApi.getUser(LOGINID_1).getRoles();
+ ArrayList<EcompRole> rolesList = new ArrayList<>(storedUserRoles);
+
+ assertThat(rolesList.size(), is(1));
+ assertThat(rolesList.get(0).getId(), is(1L));
+ assertThat(rolesList.get(0).getName(), is(VIEW_ROLE));
+ }
+
+ @Test
+ public void testDeleteUserRoles() throws Exception {
+ EcompUser user = new EcompUser();
+ user.setLoginId(LOGINID_1);
+ user.setFirstName("Bob");
+ List<EcompRole> availableRoles = portalApi.getAvailableRoles();
+ user.setRoles(new LinkedHashSet<EcompRole>(availableRoles));
+
+ portalApi.pushUser(user);
+
+ portalApi.pushUserRole(LOGINID_1, new ArrayList<EcompRole>());
+
+ EcompUser userWithNoRoles = portalApi.getUser(LOGINID_1);
+
+ assertThat(userWithNoRoles.getRoles(), empty());
+ }
+
+ @Test
+ public void testPushNullRoles() throws Exception {
+ EcompUser user = new EcompUser();
+ user.setLoginId(LOGINID_1);
+ user.setFirstName("Bob");
+ List<EcompRole> availableRoles = portalApi.getAvailableRoles();
+ user.setRoles(new LinkedHashSet<EcompRole>(availableRoles));
+
+ portalApi.pushUser(user);
+ portalApi.pushUserRole(LOGINID_1, null);
+
+ EcompUser userWithNoRoles = portalApi.getUser(LOGINID_1);
+
+ assertThat(userWithNoRoles.getRoles(), empty());
+ }
+
+ @Test
+ public void testIsAppAuthenticated() throws Exception {
+ Whitebox.setInternalState(PortalAuthenticationConfig.class, "AUTHENTICATION_CONFIG_FILE",
+ TestData.PORTAL_AUTHENTICATION_PROPERTIES.getFilename());
+
+ HttpServletRequest request = Mockito.mock(HttpServletRequest.class);
+ when(request.getHeader("username")).thenReturn("testuser");
+ when(request.getHeader("password")).thenReturn("testpassword");
+
+ assertThat(portalApi.isAppAuthenticated(request), is(true));
+ }
+}*/ \ No newline at end of file
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/security/portal/TestUserManager.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/security/portal/TestUserManager.java
new file mode 100644
index 0000000..c34854a
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/security/portal/TestUserManager.java
@@ -0,0 +1,265 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+
+package org.onap.aai.sparky.security.portal;
+
+import static org.hamcrest.Matchers.empty;
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertThat;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.stream.Collectors;
+
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.onap.aai.sparky.security.portal.UserManager;
+import org.onap.aai.sparky.util.NodeUtils;
+import org.openecomp.portalsdk.core.restful.domain.EcompUser;
+import org.powermock.modules.junit4.PowerMockRunner;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.gson.Gson;
+
+@RunWith(PowerMockRunner.class)
+// @PrepareForTest(RolesConfig.class)
+public class TestUserManager {
+
+ private static final String LOGINID_3 = "3";
+ private static File noFile;
+ private static File concurrentUsers;
+ private static File concurrentEditUsers;
+
+ private static final Gson GSON = new Gson();
+ private static final String LOGINID_1 = "1";
+ private static final String LOGINID_2 = "2";
+
+ private static Logger logger = LoggerFactory.getLogger(TestUserManager.class);
+
+ enum TestData {
+ // @formatter:off
+ NO_FILE ("src/test/resources/portal/no-users.config"),
+ CONCURRENT_USERS ("src/test/resources/portal/concurrent-users.config"),
+ CONCURRENT_EDIT_USERS ("src/test/resources/portal/concurrent-edit-users.config");
+// ROLES_CONFIG_FILE ("src/test/resources/portal/roles.config");
+
+ private String filename;
+ TestData(String filename) {this.filename = filename;}
+ public String getFilename() {return this.filename;}
+ // @formatter:on
+ }
+
+ @BeforeClass
+ public static void setUpBeforeClass() throws Exception {
+ noFile = Paths.get(TestData.NO_FILE.getFilename()).toFile();
+ concurrentUsers = Paths.get(TestData.CONCURRENT_USERS.getFilename()).toFile();
+ concurrentEditUsers = Paths.get(TestData.CONCURRENT_EDIT_USERS.getFilename()).toFile();
+ }
+
+ @AfterClass
+ public static void tearDownAfterClass() throws Exception {
+ Files.deleteIfExists(concurrentUsers.toPath());
+ Files.deleteIfExists(concurrentEditUsers.toPath());
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ EcompUser user1 = new EcompUser();
+ user1.setLoginId(LOGINID_1);
+
+ EcompUser user2 = new EcompUser();
+ user2.setLoginId(LOGINID_2);
+
+ List<EcompUser> users = Arrays.asList(user1, user2);
+ Files.write(concurrentEditUsers.toPath(), GSON.toJson(users).getBytes());
+
+ // Whitebox.setInternalState(RolesConfig.class, "ROLES_CONFIG_FILE",
+ // TestData.ROLES_CONFIG_FILE.getFilename());
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ Files.deleteIfExists(concurrentUsers.toPath());
+ Files.deleteIfExists(concurrentEditUsers.toPath());
+ }
+
+ @Test
+ public void testGetUsersNoFile() throws Exception {
+ UserManager userManager = new UserManager(noFile);
+ List<EcompUser> users = userManager.getUsers();
+
+ assertThat(users, empty());
+ }
+
+ @Test
+ public void testConcurrentPush() throws Exception {
+ Callable<EcompUser> pushTask = () -> {
+ return pushTask(concurrentUsers, String.valueOf(NodeUtils.getRandomTxnId()));
+ };
+
+ List<Callable<EcompUser>> callables = Arrays.asList(pushTask, pushTask, pushTask, pushTask,
+ pushTask);
+
+ ExecutorService executor = Executors.newWorkStealingPool();
+ executor.invokeAll(callables).stream().map(future -> {
+ try {
+ return future.get();
+ } catch (Exception e) {
+ throw new IllegalStateException(e);
+ }
+ });
+
+ UserManager userManager = new UserManager(concurrentUsers);
+ assertThat(userManager.getUsers().size(), is(5));
+ }
+
+ /**
+ * Concurrent push/edit with sequential retry on failure.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testConcurrentPushAndEdit() throws Exception {
+ Callable<EcompUser> pushTaskRandomId = () -> {
+ return pushTask(concurrentEditUsers, String.valueOf(NodeUtils.getRandomTxnId()));
+ };
+
+ Callable<EcompUser> pushTaskId3 = () -> {
+ return pushTask(concurrentEditUsers, LOGINID_3);
+ };
+
+ Callable<EcompUser> editTaskId1 = () -> {
+ return editTask(LOGINID_1, "Bob");
+ };
+
+ Callable<EcompUser> editTaskId2 = () -> {
+ return editTask(LOGINID_2, "Jen");
+ };
+
+ Callable<EcompUser> editTaskId3 = () -> {
+ return editTask(LOGINID_3, "Amy");
+ };
+
+ List<Callable<EcompUser>> callables = Arrays.asList(pushTaskRandomId, pushTaskRandomId,
+ pushTaskId3, editTaskId1, pushTaskRandomId, pushTaskRandomId, editTaskId3, editTaskId2,
+ pushTaskRandomId);
+
+ ExecutorService executor = Executors.newWorkStealingPool();
+ List<EcompUser> userTasks = executor.invokeAll(callables).stream().map(future -> {
+ try {
+ return future.get();
+ } catch (Exception e) {
+ throw new IllegalStateException(e);
+ }
+ }).collect(Collectors.toList());
+
+ assertThat(userTasks.size(), is(9));
+
+ assertUserPushEdit(concurrentEditUsers);
+ }
+
+ /**
+ * Retry push/edit if assert fails following concurrent attempt.
+ *
+ * @param userFile
+ * @throws Exception
+ */
+ private void assertUserPushEdit(File userFile) throws Exception {
+ UserManager userManager = new UserManager(userFile);
+ try {
+ assertThat(userManager.getUsers().size(), is(8));
+ } catch (Throwable t) {
+ int size = userManager.getUsers().size();
+ logger.error("Failed to push all users. Only created: " + size + " users. " + t.getMessage());
+ pushTask(concurrentEditUsers, String.valueOf(NodeUtils.getRandomTxnId()));
+ assertThat(userManager.getUsers().size(), is(size + 1));
+ }
+
+ try {
+ assertThat(userManager.getUser(LOGINID_1).get().getFirstName(), is("Bob"));
+ } catch (Throwable t) {
+ logger.error("Failed to edit user. " + t.getMessage());
+ retryEdit(userManager, LOGINID_1, "Bob");
+ }
+
+ try {
+ assertThat(userManager.getUser(LOGINID_2).get().getFirstName(), is("Jen"));
+ } catch (Throwable t) {
+ logger.error("Failed to edit user. " + t.getMessage());
+ retryEdit(userManager, LOGINID_2, "Jen");
+ }
+
+ try {
+ assertThat(userManager.getUser(LOGINID_3).isPresent(), is(true));
+ } catch (Throwable t) {
+ logger.error("Failed to push user. " + t.getMessage());
+ pushTask(concurrentEditUsers, LOGINID_3);
+ assertThat(userManager.getUser(LOGINID_3).isPresent(), is(true));
+ }
+
+ try {
+ assertThat(userManager.getUser(LOGINID_3).get().getFirstName(), is("Amy"));
+ } catch (Throwable t) {
+ logger.error("Failed to edit user. " + t.getMessage());
+ retryEdit(userManager, LOGINID_3, "Amy");
+ }
+ }
+
+ private void retryEdit(UserManager userManager, String loginId, String firstName)
+ throws IOException {
+ editTask(loginId, firstName);
+ assertThat(userManager.getUser(loginId).get().getFirstName(), is(firstName));
+ }
+
+ private EcompUser pushTask(File fileStore, String loginId) throws IOException {
+ UserManager userManager = new UserManager(fileStore);
+ EcompUser user = new EcompUser();
+ user.setLoginId(loginId);
+ userManager.pushUser(user);
+ return user;
+ }
+
+ private EcompUser editTask(String loginId, String firstName) throws IOException {
+ UserManager userManager = new UserManager(concurrentEditUsers);
+ EcompUser user = new EcompUser();
+ user.setLoginId(loginId);
+ user.setFirstName(firstName);
+ userManager.editUser(loginId, user);
+ return user;
+ }
+
+} \ No newline at end of file
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/subscription/config/SubscriptionConfigTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/subscription/config/SubscriptionConfigTest.java
new file mode 100644
index 0000000..6aaca1a
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/subscription/config/SubscriptionConfigTest.java
@@ -0,0 +1,54 @@
+package org.onap.aai.sparky.subscription.config;
+
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.ArrayList;
+
+import org.junit.Before;
+import org.junit.Test;
+
+
+public class SubscriptionConfigTest {
+
+
+
+ private SubscriptionConfig subscriptionConfig;
+ private ArrayList<String> annEntities;
+
+ @Before
+ public void init() throws Exception {
+ subscriptionConfig = new SubscriptionConfig();
+ annEntities = new ArrayList<String>();
+
+ }
+
+
+ @Test
+ public void updateValues() {
+
+ subscriptionConfig.setSubscriptionTarget("portal");
+ assertNotNull(subscriptionConfig.getSubscriptionTarget());
+ subscriptionConfig.setSubscriptionOrigin("sparky");
+ assertNotNull(subscriptionConfig.getSubscriptionOrigin());
+ subscriptionConfig.setSubscriptionMessageType("subscribe");
+ assertNotNull(subscriptionConfig.getSubscriptionMessageType());
+ subscriptionConfig.setSubscriptionTopic("portal-dispalyNotification");
+ assertNotNull(subscriptionConfig.getSubscriptionTopic());
+ subscriptionConfig.setAnnEntitiyTypes(annEntities);
+ assertNotNull(subscriptionConfig.getAnnEntitiyTypes());
+ subscriptionConfig.setLaunchOITarget("portal");
+ assertNotNull(subscriptionConfig.getLaunchOITarget());
+ subscriptionConfig.setLaunchOIOrigin("sparky");
+ assertNotNull(subscriptionConfig.getLaunchOIOrigin());
+ subscriptionConfig.setLaunchOIMessageType("publish");
+ assertNotNull(subscriptionConfig.getLaunchOIMessageType());
+ subscriptionConfig.setLaunchOITopic("portal-displayNotification");
+ assertNotNull(subscriptionConfig.getLaunchOITopic());
+ subscriptionConfig.setIsLaunchOIEnabled(true);
+ assertTrue(subscriptionConfig.getIsLaunchOIEnabled());
+ }
+
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/subscription/payload/entity/MessageTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/subscription/payload/entity/MessageTest.java
new file mode 100644
index 0000000..bd3297e
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/subscription/payload/entity/MessageTest.java
@@ -0,0 +1,32 @@
+package org.onap.aai.sparky.subscription.payload.entity;
+
+import static org.junit.Assert.assertNotNull;
+
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class MessageTest {
+
+ private Message message;
+ private Payload payLoad;
+
+ @Before
+ public void init() throws Exception {
+ message = new Message();
+ payLoad = new Payload();
+
+ }
+
+
+ @Test
+ public void updateValues() {
+
+ message.setApplicationName("Network Navigator");
+ assertNotNull(message.getApplicationName());
+ message.setPayload(payLoad);
+ assertNotNull(message.getPayload());
+ }
+
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/subscription/payload/entity/ObjectInspectorPayloadTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/subscription/payload/entity/ObjectInspectorPayloadTest.java
new file mode 100644
index 0000000..1bbddcb
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/subscription/payload/entity/ObjectInspectorPayloadTest.java
@@ -0,0 +1,43 @@
+package org.onap.aai.sparky.subscription.payload.entity;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import java.io.IOException;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.onap.aai.sparky.subscription.config.SubscriptionConfig;
+
+import com.fasterxml.jackson.core.JsonParseException;
+import com.fasterxml.jackson.databind.JsonMappingException;
+
+public class ObjectInspectorPayloadTest {
+
+ private ObjectInspectorPayload objectInspectorPayload;
+ private Message message;
+
+ @Before
+ public void init() throws Exception {
+ objectInspectorPayload = new ObjectInspectorPayload();
+ message = new Message();
+
+ }
+
+
+ @Test
+ public void updateValues() throws JsonParseException, JsonMappingException, IOException {
+
+ objectInspectorPayload.setMessage(message);
+ assertNotNull(objectInspectorPayload.getMessage());
+ objectInspectorPayload.setTopic("sparky");
+ assertNotNull(objectInspectorPayload.getTopic());
+ objectInspectorPayload.setMessageType("subscribe");
+ assertNotNull(objectInspectorPayload.getMessageType());
+ objectInspectorPayload.setOrigin("portal-dispalyNotification");
+ assertNotNull(objectInspectorPayload.getOrigin());
+ objectInspectorPayload.setTarget("");
+ assertNotNull(objectInspectorPayload.getTarget());
+ }
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/subscription/payload/entity/ParamsTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/subscription/payload/entity/ParamsTest.java
new file mode 100644
index 0000000..eac6f74
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/subscription/payload/entity/ParamsTest.java
@@ -0,0 +1,30 @@
+package org.onap.aai.sparky.subscription.payload.entity;
+
+import static org.junit.Assert.assertNotNull;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class ParamsTest {
+
+
+
+ private Params params;
+
+
+ @Before
+ public void init() throws Exception {
+ params = new Params();
+ }
+
+
+ @Test
+ public void updateValues() {
+
+ params.setObjectName("");
+ assertNotNull(params.getObjectName());
+ params.setExternalClassId("222");
+ assertNotNull(params.getExternalClassId());
+ }
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/subscription/payload/entity/PayloadTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/subscription/payload/entity/PayloadTest.java
new file mode 100644
index 0000000..95d43e9
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/subscription/payload/entity/PayloadTest.java
@@ -0,0 +1,32 @@
+package org.onap.aai.sparky.subscription.payload.entity;
+
+import static org.junit.Assert.assertNotNull;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class PayloadTest {
+
+
+ private Payload payload;
+ private Params params;
+
+ @Before
+ public void init() throws Exception {
+ payload = new Payload();
+ params = new Params();
+
+ }
+
+
+ @Test
+ public void updateValues() {
+
+ payload.setAction("Launch-tab");
+ assertNotNull(payload.getAction());
+ payload.setParams(params);
+ assertNotNull(payload.getParams());
+ }
+
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/sync/AbstractEntitySynchronizerTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/sync/AbstractEntitySynchronizerTest.java
new file mode 100644
index 0000000..3bd4928
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/sync/AbstractEntitySynchronizerTest.java
@@ -0,0 +1,463 @@
+package org.onap.aai.sparky.sync;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.security.SecureRandom;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Pattern;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.onap.aai.cl.api.Logger;
+import org.onap.aai.cl.eelf.LoggerFactory;
+import org.onap.aai.restclient.client.OperationResult;
+import org.onap.aai.sparky.config.oxm.SearchableEntityLookup;
+import org.onap.aai.sparky.config.oxm.SearchableOxmEntityDescriptor;
+import org.onap.aai.sparky.dal.ActiveInventoryAdapter;
+import org.onap.aai.sparky.dal.ElasticSearchAdapter;
+import org.onap.aai.sparky.dal.NetworkTransaction;
+import org.onap.aai.sparky.dal.rest.HttpMethod;
+import org.onap.aai.sparky.sync.config.NetworkStatisticsConfig;
+
+
+
+public class AbstractEntitySynchronizerTest {
+
+ public class QuantumSynchronizer extends AbstractEntitySynchronizer {
+
+ private boolean amIDone;
+ private SearchableEntityLookup searchableEntityLookup;
+
+ protected QuantumSynchronizer(Logger logger, String syncName, int numSyncWorkers, int numActiveInventoryWorkers,
+ int numElasticsearchWorkers, String indexName, NetworkStatisticsConfig aaiStatConfig,
+ NetworkStatisticsConfig esStatConfig) throws Exception {
+ super(logger, syncName, numSyncWorkers, numActiveInventoryWorkers, numElasticsearchWorkers, indexName,
+ aaiStatConfig, esStatConfig);
+
+ amIDone = false;
+
+ }
+
+ public void setSearchableEntityLookup(SearchableEntityLookup searchableEntityLookup) {
+ this.searchableEntityLookup = searchableEntityLookup;
+ }
+
+ public void initCounters() {
+ if (this.searchableEntityLookup != null) {
+ this.aaiEntityStats
+ .intializeEntityCounters(searchableEntityLookup.getSearchableEntityDescriptors().keySet());
+ this.esEntityStats
+ .intializeEntityCounters(searchableEntityLookup.getSearchableEntityDescriptors().keySet());
+
+ }
+ }
+
+ public void setSyncDone(boolean done) {
+ this.amIDone = done;
+ }
+
+ @Override
+ protected boolean isSyncDone() {
+ return amIDone;
+ }
+
+ }
+
+ private static Logger LOG = LoggerFactory.getInstance().getLogger(AbstractEntitySynchronizerTest.class);
+ private static SecureRandom secureRandom = new SecureRandom();
+
+ private QuantumSynchronizer quantumSync;
+ private NetworkStatisticsConfig aaiStatConfig;
+ private NetworkStatisticsConfig esStatConfig;
+ private ElasticSearchAdapter esAdapter;
+ private ActiveInventoryAdapter aaiAdapter;
+ private SearchableEntityLookup searchableEntityLookup;
+
+
+ @Before
+ public void init() throws Exception {
+
+ aaiStatConfig = new NetworkStatisticsConfig();
+
+ aaiStatConfig.setNumSamplesPerThreadForRunningAverage(100);
+
+ aaiStatConfig.setBytesHistogramLabel("[Response Size In Bytes]");
+ aaiStatConfig.setBytesHistogramMaxYAxis(1000000L);
+ aaiStatConfig.setBytesHistogramNumBins(20);
+ aaiStatConfig.setBytesHistogramNumDecimalPoints(2);
+
+ aaiStatConfig.setQueueLengthHistogramLabel("[Queue Item Length]");
+ aaiStatConfig.setQueueLengthHistogramMaxYAxis(20000);
+ aaiStatConfig.setQueueLengthHistogramNumBins(20);
+ aaiStatConfig.setQueueLengthHistogramNumDecimalPoints(2);
+
+ aaiStatConfig.setTaskAgeHistogramLabel("[Task Age In Ms]");
+ aaiStatConfig.setTaskAgeHistogramMaxYAxis(600000L);
+ aaiStatConfig.setTaskAgeHistogramNumBins(20);
+ aaiStatConfig.setTaskAgeHistogramNumDecimalPoints(2);
+
+ aaiStatConfig.setResponseTimeHistogramLabel("[Response Time In Ms]");
+ aaiStatConfig.setResponseTimeHistogramMaxYAxis(1000L);
+ aaiStatConfig.setResponseTimeHistogramNumBins(20);
+ aaiStatConfig.setResponseTimeHistogramNumDecimalPoints(2);
+
+ aaiStatConfig.setTpsHistogramLabel("[Transactions Per Second]");
+ aaiStatConfig.setTpsHistogramMaxYAxis(100);
+ aaiStatConfig.setTpsHistogramNumBins(20);
+ aaiStatConfig.setTpsHistogramNumDecimalPoints(2);
+
+ esStatConfig = new NetworkStatisticsConfig();
+
+ esStatConfig.setNumSamplesPerThreadForRunningAverage(100);
+
+ esStatConfig.setBytesHistogramLabel("[Response Size In Bytes]");
+ esStatConfig.setBytesHistogramMaxYAxis(1000000L);
+ esStatConfig.setBytesHistogramNumBins(20);
+ esStatConfig.setBytesHistogramNumDecimalPoints(2);
+
+ esStatConfig.setQueueLengthHistogramLabel("[Queue Item Length]");
+ esStatConfig.setQueueLengthHistogramMaxYAxis(20000);
+ esStatConfig.setQueueLengthHistogramNumBins(20);
+ esStatConfig.setQueueLengthHistogramNumDecimalPoints(2);
+
+ esStatConfig.setTaskAgeHistogramLabel("[Task Age In Ms]");
+ esStatConfig.setTaskAgeHistogramMaxYAxis(600000L);
+ esStatConfig.setTaskAgeHistogramNumBins(20);
+ esStatConfig.setTaskAgeHistogramNumDecimalPoints(2);
+
+ esStatConfig.setResponseTimeHistogramLabel("[Response Time In Ms]");
+ esStatConfig.setResponseTimeHistogramMaxYAxis(10000L);
+ esStatConfig.setResponseTimeHistogramNumBins(20);
+ esStatConfig.setResponseTimeHistogramNumDecimalPoints(2);
+
+ esStatConfig.setTpsHistogramLabel("[Transactions Per Second]");
+ esStatConfig.setTpsHistogramMaxYAxis(100);
+ esStatConfig.setTpsHistogramNumBins(20);
+ esStatConfig.setTpsHistogramNumDecimalPoints(2);
+
+ esAdapter = Mockito.mock(ElasticSearchAdapter.class);
+ aaiAdapter = Mockito.mock(ActiveInventoryAdapter.class);
+
+ }
+
+ @Test
+ public void validateNetworkStatConfig() {
+
+ // validate aaiStatConfig
+
+ assertEquals(100, aaiStatConfig.getNumSamplesPerThreadForRunningAverage());
+
+ assertEquals("[Response Size In Bytes]",aaiStatConfig.getBytesHistogramLabel());
+ assertEquals(1000000L,aaiStatConfig.getBytesHistogramMaxYAxis());
+ assertEquals(20,aaiStatConfig.getBytesHistogramNumBins());
+ assertEquals(2,aaiStatConfig.getBytesHistogramNumDecimalPoints());
+
+ assertEquals("[Queue Item Length]",aaiStatConfig.getQueueLengthHistogramLabel());
+ assertEquals(20000,aaiStatConfig.getQueueLengthHistogramMaxYAxis());
+ assertEquals(20,aaiStatConfig.getQueueLengthHistogramNumBins());
+ assertEquals(2,aaiStatConfig.getQueueLengthHistogramNumDecimalPoints());
+
+ assertEquals("[Task Age In Ms]",aaiStatConfig.getTaskAgeHistogramLabel());
+ assertEquals(600000L,aaiStatConfig.getTaskAgeHistogramMaxYAxis());
+ assertEquals(20,aaiStatConfig.getTaskAgeHistogramNumBins());
+ assertEquals(2,aaiStatConfig.getTaskAgeHistogramNumDecimalPoints());
+
+ assertEquals("[Response Time In Ms]",aaiStatConfig.getResponseTimeHistogramLabel());
+ assertEquals(1000L,aaiStatConfig.getResponseTimeHistogramMaxYAxis());
+ assertEquals(20,aaiStatConfig.getResponseTimeHistogramNumBins());
+ assertEquals(2, aaiStatConfig.getResponseTimeHistogramNumDecimalPoints());
+
+ assertEquals("[Transactions Per Second]",aaiStatConfig.getTpsHistogramLabel());
+ assertEquals(100,aaiStatConfig.getTpsHistogramMaxYAxis());
+ assertEquals(20,aaiStatConfig.getTpsHistogramNumBins());
+ assertEquals(2,aaiStatConfig.getTpsHistogramNumDecimalPoints());
+
+ // validate esStatConfig
+
+ assertEquals(100, esStatConfig.getNumSamplesPerThreadForRunningAverage());
+
+ assertEquals("[Response Size In Bytes]",esStatConfig.getBytesHistogramLabel());
+ assertEquals(1000000L,esStatConfig.getBytesHistogramMaxYAxis());
+ assertEquals(20,esStatConfig.getBytesHistogramNumBins());
+ assertEquals(2,esStatConfig.getBytesHistogramNumDecimalPoints());
+
+ assertEquals("[Queue Item Length]",esStatConfig.getQueueLengthHistogramLabel());
+ assertEquals(20000,esStatConfig.getQueueLengthHistogramMaxYAxis());
+ assertEquals(20,esStatConfig.getQueueLengthHistogramNumBins());
+ assertEquals(2,esStatConfig.getQueueLengthHistogramNumDecimalPoints());
+
+ assertEquals("[Task Age In Ms]",esStatConfig.getTaskAgeHistogramLabel());
+ assertEquals(600000L,esStatConfig.getTaskAgeHistogramMaxYAxis());
+ assertEquals(20,esStatConfig.getTaskAgeHistogramNumBins());
+ assertEquals(2,esStatConfig.getTaskAgeHistogramNumDecimalPoints());
+
+ assertEquals("[Response Time In Ms]",esStatConfig.getResponseTimeHistogramLabel());
+ assertEquals(10000L,esStatConfig.getResponseTimeHistogramMaxYAxis());
+ assertEquals(20,esStatConfig.getResponseTimeHistogramNumBins());
+ assertEquals(2, esStatConfig.getResponseTimeHistogramNumDecimalPoints());
+
+ assertEquals("[Transactions Per Second]",esStatConfig.getTpsHistogramLabel());
+ assertEquals(100,esStatConfig.getTpsHistogramMaxYAxis());
+ assertEquals(20,esStatConfig.getTpsHistogramNumBins());
+ assertEquals(2,esStatConfig.getTpsHistogramNumDecimalPoints());
+
+ }
+
+ @Test
+ public void validateBasicConstruction() throws Exception {
+
+ quantumSync = new QuantumSynchronizer(LOG, "quanumSynchronizer", 5, 5, 5, "quantum-search-index", aaiStatConfig,
+ esStatConfig);
+
+ quantumSync.setAaiAdapter(aaiAdapter);
+ quantumSync.setElasticSearchAdapter(esAdapter);
+
+ quantumSync.clearCache();
+
+ assertNotNull(quantumSync.getAaiAdapter());
+ assertNotNull(quantumSync.getElasticSearchAdapter());
+ assertEquals("quantum-search-index", quantumSync.getIndexName());
+
+ quantumSync.setIndexName("new-search-index-name");
+ assertEquals("new-search-index-name", quantumSync.getIndexName());
+
+ quantumSync.shutdownExecutors();
+ }
+
+ private static String REST_STAT_LINE_FORMAT = ".*%s.*1XX:.*%d.*2XX:.*%d.*3XX:.*%d.*4XX:.*%d.*5XX:.*%d.*6XX:.*%d.*";
+ private static String ENTITY_STATS_LINE_FORMAT = ".*%s.*TOTAL:.*%d.*FOUND:.*%d.*NO_PAYLOAD:.*%d.*NOT_FOUND:.*%d.*NUM_RETRIES:.*%d.*ERROR:.*%d.*";
+
+ private boolean reportContainsRestStatistics(String testString, HttpMethod httpMethod, long oneXX, long twoXX,
+ long threeXX, long fourXX, long fiveXX, long sixXX) {
+
+ Pattern pattern = Pattern.compile(String.format(REST_STAT_LINE_FORMAT, httpMethod.toString(), oneXX, twoXX,
+ threeXX, fourXX, fiveXX, sixXX));
+
+ String lines[] = testString.split("\\r?\\n");
+
+ /*
+ * if we get a match on any of the lines in the report, then we
+ * succeeded
+ */
+
+ for (String line : lines) {
+ if (pattern.matcher(line).matches()) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ private boolean reportContainsEntityStatistics(String testString, String entityType, long total, long found,
+ long noPayload, long notFound, long numRetries, long numErrors) {
+
+ Pattern pattern = Pattern.compile(String.format(ENTITY_STATS_LINE_FORMAT, entityType, total, found,
+ noPayload, notFound, numRetries, numErrors));
+
+ String lines[] = testString.split("\\r?\\n");
+
+ /*
+ * if we get a match on any of the lines in the report, then we
+ * succeeded
+ */
+
+ for (String line : lines) {
+ if (pattern.matcher(line).matches()) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+
+ @Test
+ public void validateStatisticTrackingAndReporting() throws Exception {
+
+ quantumSync = new QuantumSynchronizer(LOG, "quanumSynchronizer", 5, 5, 5, "quantum-search-index", aaiStatConfig,
+ esStatConfig);
+
+ quantumSync.setAaiAdapter(aaiAdapter);
+ quantumSync.setElasticSearchAdapter(esAdapter);
+
+ searchableEntityLookup = new SearchableEntityLookup();
+
+ Map<String,SearchableOxmEntityDescriptor> searchableDescriptors = new HashMap<String,SearchableOxmEntityDescriptor>();
+
+ SearchableOxmEntityDescriptor complexDescriptor = new SearchableOxmEntityDescriptor();
+ complexDescriptor.setEntityName("complex");
+ List<String> pkeyNames = new ArrayList<String>();
+ pkeyNames.add("physical-location-id");
+
+ complexDescriptor.setPrimaryKeyAttributeNames(pkeyNames);
+ complexDescriptor.setSearchableAttributes(pkeyNames);
+
+ searchableDescriptors.put("complex", complexDescriptor);
+
+ searchableEntityLookup.setSearchableEntityDescriptors(searchableDescriptors);
+
+ quantumSync.setSearchableEntityLookup(searchableEntityLookup);
+ quantumSync.initCounters();
+
+ int randomMaxTimesToPegCounters = secureRandom.nextInt(1000);
+
+ NetworkTransaction txn = null;
+ OperationResult opResult = null;
+
+
+ /*
+ * The result of this block is that for all HttpMethod types [ PUT, POST, GET, etc ] we'll peg a complex entity
+ * type counter a random number of times (set before the for loop, and for each status code category 1XX -> 6XX.
+ */
+
+ // GET, PUT, POST, DELETE, PATCH, HEAD
+ for (HttpMethod httpMethod : HttpMethod.values()) {
+
+ // for randomMaxTimesToPegCounters
+ for (int numTimesToPegCounter = 0; numTimesToPegCounter < randomMaxTimesToPegCounters; numTimesToPegCounter++) {
+ txn = new NetworkTransaction();
+ txn.setOperationType(httpMethod);
+ txn.setEntityType("complex");
+
+ /*
+ * set the txn optime to a random value between 0 and 10000 ms.
+ * Over thousands of counter statistics the random sample
+ * averages should be approximately uniform, but is highly
+ * dependent on the pseudo-RNG.
+ */
+ txn.setOpTimeInMs(secureRandom.nextInt(10000));
+
+ // 1XX, 2XX, 3XX, 4XX, 5XX, 6XX
+ for ( int resultCode = 100; resultCode < 700; resultCode += 100) {
+ opResult = new OperationResult();
+ opResult.setResultCode(resultCode);
+
+ txn.setOperationResult(opResult);
+
+ // peg both AAI and ES statistics
+
+ quantumSync.updateActiveInventoryCounters(txn);
+ quantumSync.updateActiveInventoryCounters(httpMethod, "complex", opResult);
+
+ quantumSync.updateElasticSearchCounters(txn);
+ quantumSync.updateElasticSearchCounters(httpMethod, "complex", opResult);
+
+ }
+ }
+ }
+
+ for (int numTimesToPegCounter = 0; numTimesToPegCounter < randomMaxTimesToPegCounters; numTimesToPegCounter++) {
+ quantumSync.incActiveInventoryWorkOnHandCounter();
+ quantumSync.incElasticSearchWorkOnHandCounter();
+ }
+
+ assertEquals( randomMaxTimesToPegCounters, quantumSync.aaiWorkOnHand.get());
+ assertEquals( randomMaxTimesToPegCounters, quantumSync.esWorkOnHand.get());
+
+ /*
+ * now we'll generate various reports and try to validate the output
+ */
+
+ String aaiStatsReport = quantumSync.getActiveInventoryStatisticsReport();
+
+ /*
+ * We double the expected validation check number because we peg each
+ * counter in each category twice (with different APIs for the same
+ * entity.
+ */
+
+ assertTrue(reportContainsRestStatistics(aaiStatsReport, HttpMethod.DELETE, randomMaxTimesToPegCounters * 2,
+ randomMaxTimesToPegCounters * 2, randomMaxTimesToPegCounters * 2, randomMaxTimesToPegCounters * 2,
+ randomMaxTimesToPegCounters * 2, randomMaxTimesToPegCounters * 2));
+
+ assertTrue(reportContainsRestStatistics(aaiStatsReport, HttpMethod.PUT, randomMaxTimesToPegCounters * 2,
+ randomMaxTimesToPegCounters * 2, randomMaxTimesToPegCounters * 2, randomMaxTimesToPegCounters * 2,
+ randomMaxTimesToPegCounters * 2, randomMaxTimesToPegCounters * 2));
+
+ assertTrue(reportContainsRestStatistics(aaiStatsReport, HttpMethod.POST, randomMaxTimesToPegCounters * 2,
+ randomMaxTimesToPegCounters * 2, randomMaxTimesToPegCounters * 2, randomMaxTimesToPegCounters * 2,
+ randomMaxTimesToPegCounters * 2, randomMaxTimesToPegCounters * 2));
+
+ assertTrue(reportContainsRestStatistics(aaiStatsReport, HttpMethod.GET, randomMaxTimesToPegCounters * 2,
+ randomMaxTimesToPegCounters * 2, randomMaxTimesToPegCounters * 2, randomMaxTimesToPegCounters * 2,
+ randomMaxTimesToPegCounters * 2, randomMaxTimesToPegCounters * 2));
+
+ long total = (randomMaxTimesToPegCounters*2)*6;
+ long found = randomMaxTimesToPegCounters*2;
+ long noPayload = (randomMaxTimesToPegCounters*2)*6;
+ long notFound = 0;
+ long numRetries = 0;
+ long numErrors = (randomMaxTimesToPegCounters*2)*5;
+
+ assertTrue(reportContainsEntityStatistics(aaiStatsReport, "complex", total, found,
+ noPayload, notFound, numRetries, numErrors));
+
+ String esStatsReport = quantumSync.getElasticSearchStatisticsReport();
+
+ assertTrue(reportContainsRestStatistics(esStatsReport, HttpMethod.DELETE, randomMaxTimesToPegCounters * 2,
+ randomMaxTimesToPegCounters * 2, randomMaxTimesToPegCounters * 2, randomMaxTimesToPegCounters * 2,
+ randomMaxTimesToPegCounters * 2, randomMaxTimesToPegCounters * 2));
+
+ assertTrue(reportContainsRestStatistics(esStatsReport, HttpMethod.PUT, randomMaxTimesToPegCounters * 2,
+ randomMaxTimesToPegCounters * 2, randomMaxTimesToPegCounters * 2, randomMaxTimesToPegCounters * 2,
+ randomMaxTimesToPegCounters * 2, randomMaxTimesToPegCounters * 2));
+
+ assertTrue(reportContainsRestStatistics(esStatsReport, HttpMethod.POST, randomMaxTimesToPegCounters * 2,
+ randomMaxTimesToPegCounters * 2, randomMaxTimesToPegCounters * 2, randomMaxTimesToPegCounters * 2,
+ randomMaxTimesToPegCounters * 2, randomMaxTimesToPegCounters * 2));
+
+ assertTrue(reportContainsRestStatistics(esStatsReport, HttpMethod.GET, randomMaxTimesToPegCounters * 2,
+ randomMaxTimesToPegCounters * 2, randomMaxTimesToPegCounters * 2, randomMaxTimesToPegCounters * 2,
+ randomMaxTimesToPegCounters * 2, randomMaxTimesToPegCounters * 2));
+
+
+ assertNotNull(quantumSync.getStatReport(10000L, false));
+ assertNotNull(quantumSync.getStatReport(20000L, true));
+
+ for (int numTimesToPegCounter = 0; numTimesToPegCounter < randomMaxTimesToPegCounters; numTimesToPegCounter++) {
+ quantumSync.decActiveInventoryWorkOnHandCounter();
+ quantumSync.decElasticSearchWorkOnHandCounter();
+ }
+
+ assertEquals( 0, quantumSync.aaiWorkOnHand.get());
+ assertEquals( 0, quantumSync.esWorkOnHand.get());
+
+ /*
+ * Validate stat reports display zero stats for complex
+ */
+
+ quantumSync.resetCounters();
+
+ aaiStatsReport = quantumSync.getActiveInventoryStatisticsReport();
+
+ /*
+ * We double the expected validation check number because we peg each
+ * counter in each category twice (with different APIs for the same
+ * entity.
+ */
+
+ assertTrue(reportContainsRestStatistics(aaiStatsReport, HttpMethod.DELETE, 0, 0, 0, 0, 0, 0));
+ assertTrue(reportContainsRestStatistics(aaiStatsReport, HttpMethod.PUT, 0, 0, 0, 0, 0, 0));
+ assertTrue(reportContainsRestStatistics(aaiStatsReport, HttpMethod.POST, 0, 0, 0, 0, 0, 0));
+ assertTrue(reportContainsRestStatistics(aaiStatsReport, HttpMethod.GET, 0, 0, 0, 0, 0, 0));
+
+ assertTrue(reportContainsEntityStatistics(aaiStatsReport, "complex", 0, 0, 0, 0, 0, 0));
+
+ esStatsReport = quantumSync.getElasticSearchStatisticsReport();
+
+ assertTrue(reportContainsRestStatistics(esStatsReport, HttpMethod.DELETE, 0, 0, 0, 0, 0, 0));
+ assertTrue(reportContainsRestStatistics(esStatsReport, HttpMethod.PUT, 0, 0, 0, 0, 0, 0));
+ assertTrue(reportContainsRestStatistics(esStatsReport, HttpMethod.POST, 0, 0, 0, 0, 0, 0));
+ assertTrue(reportContainsRestStatistics(esStatsReport, HttpMethod.GET, 0, 0, 0, 0, 0, 0));
+
+ quantumSync.shutdownExecutors();
+ }
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/sync/AggregationSynchronizerTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/sync/AggregationSynchronizerTest.java
new file mode 100644
index 0000000..65e6e70
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/sync/AggregationSynchronizerTest.java
@@ -0,0 +1,345 @@
+package org.onap.aai.sparky.sync;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.security.SecureRandom;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.ws.rs.core.MediaType;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Matchers;
+import org.mockito.Mockito;
+import org.onap.aai.restclient.client.OperationResult;
+import org.onap.aai.sparky.aggregation.sync.AggregationSynchronizer;
+import org.onap.aai.sparky.config.oxm.OxmEntityDescriptor;
+import org.onap.aai.sparky.config.oxm.OxmEntityLookup;
+import org.onap.aai.sparky.dal.ActiveInventoryAdapter;
+import org.onap.aai.sparky.dal.ElasticSearchAdapter;
+import org.onap.aai.sparky.sync.config.ElasticSearchSchemaConfig;
+import org.onap.aai.sparky.sync.config.NetworkStatisticsConfig;
+import org.onap.aai.sparky.sync.enumeration.OperationState;
+import org.onap.aai.sparky.sync.enumeration.SynchronizerState;
+import org.onap.aai.sparky.util.TestResourceLoader;
+
+public class AggregationSynchronizerTest {
+
+ //private static Logger LOG = LoggerFactory.getInstance().getLogger(AggregationSynchronizerTest.class);
+ private static SecureRandom secureRandom = new SecureRandom();
+ private AggregationSynchronizer aggregationSynchronizer;
+
+ private ElasticSearchSchemaConfig esSchemaConfig;
+ private NetworkStatisticsConfig aaiStatConfig;
+ private NetworkStatisticsConfig esStatConfig;
+ private OxmEntityLookup oxmEntityLookup;
+ private ElasticSearchAdapter esAdapter;
+ private ActiveInventoryAdapter aaiAdapter;
+
+
+
+ @Before
+ public void init() throws Exception {
+
+ esSchemaConfig = new ElasticSearchSchemaConfig();
+ esSchemaConfig.setIndexDocType("default");
+ esSchemaConfig.setIndexMappingsFileName(null);
+ esSchemaConfig.setIndexName("aggregation-index-name");
+ esSchemaConfig.setIndexSettingsFileName(null);
+
+
+ aaiStatConfig = new NetworkStatisticsConfig();
+
+ aaiStatConfig.setNumSamplesPerThreadForRunningAverage(100);
+
+ aaiStatConfig.setBytesHistogramLabel("[Response Size In Bytes]");
+ aaiStatConfig.setBytesHistogramMaxYAxis(1000000L);
+ aaiStatConfig.setBytesHistogramNumBins(20);
+ aaiStatConfig.setBytesHistogramNumDecimalPoints(2);
+
+ aaiStatConfig.setQueueLengthHistogramLabel("[Queue Item Length]");
+ aaiStatConfig.setQueueLengthHistogramMaxYAxis(20000);
+ aaiStatConfig.setQueueLengthHistogramNumBins(20);
+ aaiStatConfig.setQueueLengthHistogramNumDecimalPoints(2);
+
+ aaiStatConfig.setTaskAgeHistogramLabel("[Task Age In Ms]");
+ aaiStatConfig.setTaskAgeHistogramMaxYAxis(600000L);
+ aaiStatConfig.setTaskAgeHistogramNumBins(20);
+ aaiStatConfig.setTaskAgeHistogramNumDecimalPoints(2);
+
+ aaiStatConfig.setResponseTimeHistogramLabel("[Response Time In Ms]");
+ aaiStatConfig.setResponseTimeHistogramMaxYAxis(1000L);
+ aaiStatConfig.setResponseTimeHistogramNumBins(20);
+ aaiStatConfig.setResponseTimeHistogramNumDecimalPoints(2);
+
+ aaiStatConfig.setTpsHistogramLabel("[Transactions Per Second]");
+ aaiStatConfig.setTpsHistogramMaxYAxis(100);
+ aaiStatConfig.setTpsHistogramNumBins(20);
+ aaiStatConfig.setTpsHistogramNumDecimalPoints(2);
+
+ esStatConfig = new NetworkStatisticsConfig();
+
+ esStatConfig.setNumSamplesPerThreadForRunningAverage(100);
+
+ esStatConfig.setBytesHistogramLabel("[Response Size In Bytes]");
+ esStatConfig.setBytesHistogramMaxYAxis(1000000L);
+ esStatConfig.setBytesHistogramNumBins(20);
+ esStatConfig.setBytesHistogramNumDecimalPoints(2);
+
+ esStatConfig.setQueueLengthHistogramLabel("[Queue Item Length]");
+ esStatConfig.setQueueLengthHistogramMaxYAxis(20000);
+ esStatConfig.setQueueLengthHistogramNumBins(20);
+ esStatConfig.setQueueLengthHistogramNumDecimalPoints(2);
+
+ esStatConfig.setTaskAgeHistogramLabel("[Task Age In Ms]");
+ esStatConfig.setTaskAgeHistogramMaxYAxis(600000L);
+ esStatConfig.setTaskAgeHistogramNumBins(20);
+ esStatConfig.setTaskAgeHistogramNumDecimalPoints(2);
+
+ esStatConfig.setResponseTimeHistogramLabel("[Response Time In Ms]");
+ esStatConfig.setResponseTimeHistogramMaxYAxis(10000L);
+ esStatConfig.setResponseTimeHistogramNumBins(20);
+ esStatConfig.setResponseTimeHistogramNumDecimalPoints(2);
+
+ esStatConfig.setTpsHistogramLabel("[Transactions Per Second]");
+ esStatConfig.setTpsHistogramMaxYAxis(100);
+ esStatConfig.setTpsHistogramNumBins(20);
+ esStatConfig.setTpsHistogramNumDecimalPoints(2);
+
+ oxmEntityLookup = new OxmEntityLookup();
+
+ esAdapter = Mockito.mock(ElasticSearchAdapter.class);
+ aaiAdapter = Mockito.mock(ActiveInventoryAdapter.class);
+
+ Map<String,OxmEntityDescriptor> oxmEntityDescriptors = new HashMap<String,OxmEntityDescriptor>();
+
+ OxmEntityDescriptor complexDescriptor = new OxmEntityDescriptor();
+ complexDescriptor.setEntityName("complex");
+ List<String> pkeyNames = new ArrayList<String>();
+ pkeyNames.add("physical-location-id");
+
+ complexDescriptor.setPrimaryKeyAttributeNames(pkeyNames);
+
+ oxmEntityDescriptors.put("complex", complexDescriptor);
+
+ oxmEntityLookup.setEntityDescriptors(oxmEntityDescriptors);
+
+
+
+ }
+
+ @Test
+ public void validateBasicConstruction() throws Exception {
+
+ aggregationSynchronizer = new AggregationSynchronizer("complex", esSchemaConfig, 5, 5, 5, aaiStatConfig,
+ esStatConfig, oxmEntityLookup);
+
+ aggregationSynchronizer.setAaiAdapter(aaiAdapter);
+ aggregationSynchronizer.setElasticSearchAdapter(esAdapter);
+
+ assertNotNull(aggregationSynchronizer.getAaiAdapter());
+ assertNotNull(aggregationSynchronizer.getElasticSearchAdapter());
+
+ }
+
+ @Test
+ public void validateSmallSync() throws Exception {
+
+ aggregationSynchronizer = new AggregationSynchronizer("complex", esSchemaConfig, 5, 5, 5, aaiStatConfig,
+ esStatConfig, oxmEntityLookup);
+
+ aggregationSynchronizer.setAaiAdapter(aaiAdapter);
+ aggregationSynchronizer.setElasticSearchAdapter(esAdapter);
+
+ String nodesQueryResponse = TestResourceLoader
+ .getTestResourceDataJson("/sync/aai/activeInventory_complex_nodesQuery_response.json");
+
+ OperationResult complexSelfLinks = new OperationResult();
+
+ complexSelfLinks.setResultCode(200);
+ complexSelfLinks.setResult(nodesQueryResponse);
+
+ Mockito.when( aaiAdapter.getSelfLinksByEntityType("complex")).thenReturn(complexSelfLinks);
+
+ for (int x = 1; x <= 5; x++) {
+
+ Mockito.when(aaiAdapter.repairSelfLink(Matchers.contains("complex" + x), Mockito.anyString()))
+ .thenReturn("https://server.proxy:8443/aai/v11/cloud-infrastructure/complexes/complex" + x);
+
+ Mockito.when(aaiAdapter.queryActiveInventoryWithRetries(Matchers.contains("complex" + x),
+ Mockito.anyString(), Mockito.anyInt()))
+ .thenReturn(new OperationResult(200, TestResourceLoader
+ .getTestResourceDataJson("/sync/aai/complex" + x + "_fullDepth_aaiEntityRetrieval.json")));
+
+ }
+
+ Mockito.when(esAdapter.buildElasticSearchGetDocUrl(Mockito.anyString(), Mockito.anyString())).thenReturn(
+ "http://localhost:9200/myindex/mytype/doc1", "http://localhost:9200/myindex/mytype/doc2",
+ "http://localhost:9200/myindex/mytype/doc3", "http://localhost:9200/myindex/mytype/doc4",
+ "http://localhost:9200/myindex/mytype/doc5");
+
+ /*
+ * Our initial gets from elastic search should be record-not-found
+ */
+ Mockito.when( esAdapter.doGet(Matchers.contains("doc1"), Mockito.any())).thenReturn(new OperationResult(404,null));
+ Mockito.when( esAdapter.doGet(Matchers.contains("doc2"), Mockito.any())).thenReturn(new OperationResult(404,null));
+ Mockito.when( esAdapter.doGet(Matchers.contains("doc3"), Mockito.any())).thenReturn(new OperationResult(404,null));
+ Mockito.when( esAdapter.doGet(Matchers.contains("doc4"), Mockito.any())).thenReturn(new OperationResult(404,null));
+ Mockito.when( esAdapter.doGet(Matchers.contains("doc5"), Mockito.any())).thenReturn(new OperationResult(404,null));
+
+
+ Mockito.when(esAdapter.doPut(Matchers.contains("doc"), Mockito.any(), Mockito.any()))
+ .thenReturn(new OperationResult(200, null));
+
+ OperationState syncState = aggregationSynchronizer.doSync();
+ assertEquals(OperationState.OK, syncState);
+
+ assertEquals(SynchronizerState.IDLE, aggregationSynchronizer.getState());
+ assertNotNull(aggregationSynchronizer.getStatReport(false));
+ assertNotNull(aggregationSynchronizer.getStatReport(true));
+
+ aggregationSynchronizer.clearCache();
+ aggregationSynchronizer.shutdown();
+
+
+ }
+
+ @Test
+ public void validateSmallSyncWithRetries() throws Exception {
+
+ aggregationSynchronizer = new AggregationSynchronizer("complex", esSchemaConfig, 5, 5, 5, aaiStatConfig,
+ esStatConfig, oxmEntityLookup);
+
+ aggregationSynchronizer.setAaiAdapter(aaiAdapter);
+ aggregationSynchronizer.setElasticSearchAdapter(esAdapter);
+
+ String nodesQueryResponse = TestResourceLoader
+ .getTestResourceDataJson("/sync/aai/activeInventory_complex_nodesQuery_response.json");
+
+ OperationResult complexSelfLinks = new OperationResult();
+
+ complexSelfLinks.setResultCode(200);
+ complexSelfLinks.setResult(nodesQueryResponse);
+
+ Mockito.when( aaiAdapter.getSelfLinksByEntityType("complex")).thenReturn(complexSelfLinks);
+
+ for (int x = 1; x <= 5; x++) {
+
+ Mockito.when(aaiAdapter.repairSelfLink(Matchers.contains("complex" + x), Mockito.anyString()))
+ .thenReturn("https://server.proxy:8443/aai/v11/cloud-infrastructure/complexes/complex" + x);
+
+ Mockito.when(aaiAdapter.queryActiveInventoryWithRetries(Matchers.contains("complex" + x),
+ Mockito.anyString(), Mockito.anyInt()))
+ .thenReturn(new OperationResult(200, TestResourceLoader
+ .getTestResourceDataJson("/sync/aai/complex" + x + "_fullDepth_aaiEntityRetrieval.json")));
+
+ }
+
+ Mockito.when(esAdapter.buildElasticSearchGetDocUrl(Mockito.anyString(), Mockito.anyString())).thenReturn(
+ "http://localhost:9200/myindex/mytype/doc1", "http://localhost:9200/myindex/mytype/doc2",
+ "http://localhost:9200/myindex/mytype/doc3", "http://localhost:9200/myindex/mytype/doc4",
+ "http://localhost:9200/myindex/mytype/doc5");
+
+ /*
+ * Our initial gets from elastic search should be record-not-found
+ */
+ Mockito.when( esAdapter.doGet(Matchers.contains("doc1"), Mockito.any())).thenReturn(new OperationResult(404,null));
+ Mockito.when( esAdapter.doGet(Matchers.contains("doc2"), Mockito.any())).thenReturn(new OperationResult(404,null));
+ Mockito.when( esAdapter.doGet(Matchers.contains("doc3"), Mockito.any())).thenReturn(new OperationResult(404,null));
+ Mockito.when( esAdapter.doGet(Matchers.contains("doc4"), Mockito.any())).thenReturn(new OperationResult(404,null));
+ Mockito.when( esAdapter.doGet(Matchers.contains("doc5"), Mockito.any())).thenReturn(new OperationResult(404,null));
+
+
+ // 409 is the elastic search version conflict code, which will result in the entries being added
+ // to our retry queue and re-attempted a couple times.
+
+ Mockito.when(esAdapter.doPut(Matchers.contains("doc"), Mockito.any(), Mockito.any()))
+ .thenReturn(new OperationResult(409, null));
+
+ OperationState syncState = aggregationSynchronizer.doSync();
+ assertEquals(OperationState.OK, syncState);
+
+ assertEquals(SynchronizerState.IDLE, aggregationSynchronizer.getState());
+ assertNotNull(aggregationSynchronizer.getStatReport(false));
+ assertNotNull(aggregationSynchronizer.getStatReport(true));
+
+ aggregationSynchronizer.clearCache();
+ aggregationSynchronizer.shutdown();
+
+ }
+
+ @Test
+ public void validateSmallSyncWithDocumentElementMerges() throws Exception {
+
+ aggregationSynchronizer = new AggregationSynchronizer("complex", esSchemaConfig, 5, 5, 5, aaiStatConfig,
+ esStatConfig, oxmEntityLookup);
+
+ aggregationSynchronizer.setAaiAdapter(aaiAdapter);
+ aggregationSynchronizer.setElasticSearchAdapter(esAdapter);
+
+ String nodesQueryResponse = TestResourceLoader
+ .getTestResourceDataJson("/sync/aai/activeInventory_complex_nodesQuery_response.json");
+
+ OperationResult complexSelfLinks = new OperationResult();
+
+ complexSelfLinks.setResultCode(200);
+ complexSelfLinks.setResult(nodesQueryResponse);
+
+ Mockito.when( aaiAdapter.getSelfLinksByEntityType("complex")).thenReturn(complexSelfLinks);
+
+ for (int x = 1; x <= 5; x++) {
+
+ Mockito.when(aaiAdapter.repairSelfLink(Matchers.contains("complex" + x), Mockito.anyString()))
+ .thenReturn("https://server.proxy:8443/aai/v11/cloud-infrastructure/complexes/complex" + x);
+
+ Mockito.when(aaiAdapter.queryActiveInventoryWithRetries(Matchers.contains("complex" + x),
+ Mockito.anyString(), Mockito.anyInt()))
+ .thenReturn(new OperationResult(200, TestResourceLoader
+ .getTestResourceDataJson("/sync/aai/complex" + x + "_fullDepth_aaiEntityRetrieval.json")));
+
+ }
+
+ Mockito.when(esAdapter.buildElasticSearchGetDocUrl(Mockito.anyString(), Mockito.anyString())).thenReturn(
+ "http://localhost:9200/myindex/mytype/doc1", "http://localhost:9200/myindex/mytype/doc2",
+ "http://localhost:9200/myindex/mytype/doc3", "http://localhost:9200/myindex/mytype/doc4",
+ "http://localhost:9200/myindex/mytype/doc5");
+
+ /*
+ * Our initial gets from elastic search return 200 ok with a found entity document requiring a doc update
+ */
+ Mockito.when(esAdapter.doGet(Matchers.contains("doc1"), Mockito.any())).thenReturn(new OperationResult(200,
+ TestResourceLoader.getTestResourceDataJson("/sync/ElasticSearch/docEntityFromElasticSearch1.json")));
+
+ Mockito.when(esAdapter.doGet(Matchers.contains("doc2"), Mockito.any())).thenReturn(new OperationResult(200,
+ TestResourceLoader.getTestResourceDataJson("/sync/ElasticSearch/docEntityFromElasticSearch2.json")));
+
+ Mockito.when(esAdapter.doGet(Matchers.contains("doc3"), Mockito.any())).thenReturn(new OperationResult(200,
+ TestResourceLoader.getTestResourceDataJson("/sync/ElasticSearch/docEntityFromElasticSearch3.json")));
+
+ Mockito.when(esAdapter.doGet(Matchers.contains("doc4"), Mockito.any())).thenReturn(new OperationResult(200,
+ TestResourceLoader.getTestResourceDataJson("/sync/ElasticSearch/docEntityFromElasticSearch4.json")));
+
+ Mockito.when(esAdapter.doGet(Matchers.contains("doc5"), Mockito.any())).thenReturn(new OperationResult(200,
+ TestResourceLoader.getTestResourceDataJson("/sync/ElasticSearch/docEntityFromElasticSearch5.json")));
+
+ Mockito.when(esAdapter.doPut(Matchers.contains("doc"), Mockito.any(), Mockito.any()))
+ .thenReturn(new OperationResult(200, null));
+
+ OperationState syncState = aggregationSynchronizer.doSync();
+ assertEquals(OperationState.OK, syncState);
+
+ assertEquals(SynchronizerState.IDLE, aggregationSynchronizer.getState());
+ assertNotNull(aggregationSynchronizer.getStatReport(false));
+ assertNotNull(aggregationSynchronizer.getStatReport(true));
+
+ aggregationSynchronizer.clearCache();
+ aggregationSynchronizer.shutdown();
+
+
+ }
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/sync/ElasticSearchIndexCleanerTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/sync/ElasticSearchIndexCleanerTest.java
new file mode 100644
index 0000000..30394de
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/sync/ElasticSearchIndexCleanerTest.java
@@ -0,0 +1,122 @@
+package org.onap.aai.sparky.sync;
+
+import static org.junit.Assert.*;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.onap.aai.restclient.client.OperationResult;
+import org.onap.aai.sparky.dal.ElasticSearchAdapter;
+import org.onap.aai.sparky.sync.config.ElasticSearchEndpointConfig;
+import org.onap.aai.sparky.sync.config.ElasticSearchSchemaConfig;
+import org.onap.aai.sparky.sync.enumeration.OperationState;
+import org.onap.aai.sparky.util.TestResourceLoader;
+
+public class ElasticSearchIndexCleanerTest {
+
+ private ElasticSearchIndexCleaner esIndexCleaner;
+
+ private ElasticSearchAdapter esAdapter;
+ private ElasticSearchEndpointConfig esRestEndpointConfig;
+ private ElasticSearchSchemaConfig esSchemaConfig;
+
+ @Before
+ public void init() throws Exception {
+
+ esAdapter = Mockito.mock( ElasticSearchAdapter.class);
+ esRestEndpointConfig = new ElasticSearchEndpointConfig();
+ esSchemaConfig = new ElasticSearchSchemaConfig();
+
+ esRestEndpointConfig.setScrollContextBatchRequestSize(5000);
+ esRestEndpointConfig.setEsIpAddress("127.0.0.1");
+ esRestEndpointConfig.setEsServerPort("9200");
+ esRestEndpointConfig.setScrollContextTimeToLiveInMinutes(5);
+
+ }
+
+ @Test
+ public void validateBasicConstruction() throws Exception {
+ esIndexCleaner = new ElasticSearchIndexCleaner(esAdapter, esRestEndpointConfig, esSchemaConfig);
+ }
+
+ @Test
+ public void validatePreOperationCollection() throws Exception {
+
+ String beforeSyncScrollApiResponse = TestResourceLoader.getTestResourceDataJson(
+ "/sync/ElasticSearch/BeforeSync_ElasticSearch_ScrollApi_Successful.json");
+
+ OperationResult scrollApiOpResult = new OperationResult();
+ scrollApiOpResult.setResultCode(200);
+ scrollApiOpResult.setResult(beforeSyncScrollApiResponse);
+
+ Mockito.when(esAdapter.doPost(Mockito.anyString(), Mockito.anyString(), Mockito.anyObject()))
+ .thenReturn(scrollApiOpResult);
+
+ esIndexCleaner = new ElasticSearchIndexCleaner(esAdapter, esRestEndpointConfig, esSchemaConfig);
+ OperationState opState = esIndexCleaner.populatePreOperationCollection();
+
+ assertEquals(OperationState.OK, opState);
+
+ }
+
+ @Test
+ public void validatePostOperationCollection() throws Exception {
+
+ String afterSyncScrollApiResponse = TestResourceLoader.getTestResourceDataJson(
+ "/sync/ElasticSearch/AfterSync_ElasticSearch_ScrollApi_Successful.json");
+
+ OperationResult scrollApiOpResult = new OperationResult();
+ scrollApiOpResult.setResultCode(200);
+ scrollApiOpResult.setResult(afterSyncScrollApiResponse);
+
+ Mockito.when(esAdapter.doPost(Mockito.anyString(), Mockito.anyString(), Mockito.anyObject()))
+ .thenReturn(scrollApiOpResult);
+
+ esIndexCleaner = new ElasticSearchIndexCleaner(esAdapter, esRestEndpointConfig, esSchemaConfig);
+ OperationState opState = esIndexCleaner.populatePostOperationCollection();
+
+ assertEquals(OperationState.OK, opState);
+
+ }
+
+
+ @Test
+ public void validatePerformCleanup() throws Exception {
+
+ String beforeSyncScrollApiResponse = TestResourceLoader.getTestResourceDataJson(
+ "/sync/ElasticSearch/BeforeSync_ElasticSearch_ScrollApi_Successful.json");
+
+ OperationResult beforeScrollApiOpResult = new OperationResult();
+ beforeScrollApiOpResult.setResultCode(200);
+ beforeScrollApiOpResult.setResult(beforeSyncScrollApiResponse);
+
+ String afterSyncScrollApiResponse = TestResourceLoader.getTestResourceDataJson(
+ "/sync/ElasticSearch/AfterSync_ElasticSearch_ScrollApi_Successful.json");
+
+ OperationResult afterScrollApiOpResult = new OperationResult();
+ afterScrollApiOpResult.setResultCode(200);
+ afterScrollApiOpResult.setResult(afterSyncScrollApiResponse);
+
+ Mockito.when(esAdapter.doPost(Mockito.anyString(), Mockito.anyString(), Mockito.anyObject()))
+ .thenReturn(beforeScrollApiOpResult,afterScrollApiOpResult);
+
+ esIndexCleaner = new ElasticSearchIndexCleaner(esAdapter, esRestEndpointConfig, esSchemaConfig);
+
+ OperationState beforeOpState = esIndexCleaner.populatePreOperationCollection();
+ OperationState afterOpState = esIndexCleaner.populatePostOperationCollection();
+
+ assertEquals(OperationState.OK, beforeOpState);
+ assertEquals(OperationState.OK, afterOpState);
+
+ /*
+ * Now we can start the test work
+ */
+
+ OperationState cleanupState = esIndexCleaner.performCleanup();
+ assertEquals(OperationState.OK, cleanupState);
+
+
+ }
+
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/sync/SyncControllerImplTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/sync/SyncControllerImplTest.java
new file mode 100644
index 0000000..a02d5e4
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/sync/SyncControllerImplTest.java
@@ -0,0 +1,81 @@
+package org.onap.aai.sparky.sync;
+
+import static org.junit.Assert.*;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.onap.aai.sparky.sync.IndexCleaner;
+import org.onap.aai.sparky.sync.IndexSynchronizer;
+import org.onap.aai.sparky.sync.IndexValidator;
+import org.onap.aai.sparky.sync.SyncControllerImpl;
+import org.onap.aai.sparky.sync.SyncControllerImpl.SyncActions;
+import org.onap.aai.sparky.sync.config.SyncControllerConfig;
+import org.onap.aai.sparky.sync.enumeration.SynchronizerState;
+
+public class SyncControllerImplTest {
+
+ private SyncControllerConfig syncControllerConfig;
+
+ private IndexSynchronizer mockSynchronizer = Mockito.mock(IndexSynchronizer.class);
+ private IndexValidator mockValidator = Mockito.mock(IndexValidator.class);
+ private IndexCleaner mockCleaner = Mockito.mock(IndexCleaner.class);
+
+ @Before
+ public void init() throws Exception {
+
+ syncControllerConfig = new SyncControllerConfig();
+
+ syncControllerConfig.setSyncTaskDelayInMs(0);
+ syncControllerConfig.setSyncTaskFrequencyInDays(2);
+ syncControllerConfig.setTargetSyncStartTimeStamp("05:00:00 UTC+00:00");
+ syncControllerConfig.setControllerName("Base-Sync-Controller-Impl");
+
+ syncControllerConfig.setPeriodicSyncEnabled(true);
+ syncControllerConfig.setRunOnceSyncEnabled(true);
+
+ }
+
+
+ @Test
+ public void validateBasicConstruction() throws Exception {
+
+ SyncControllerImpl syncController = new SyncControllerImpl(syncControllerConfig);
+
+ assertTrue(syncController.isPeriodicSyncEnabled());
+ assertTrue(syncController.isRunOnceSyncEnabled());
+ assertEquals(0, syncController.getDelayInMs());
+
+ }
+
+ @Test
+ public void validateSmallSync() throws Exception {
+
+ SyncControllerImpl syncController = new SyncControllerImpl(syncControllerConfig);
+
+ Mockito.when( mockSynchronizer.getIndexName() ).thenReturn("mock-sync-index");
+ Mockito.when( mockCleaner.getIndexName()).thenReturn("mock-sync-index");
+ Mockito.when( mockValidator.getIndexName()).thenReturn("mock-sync-index");
+
+ Mockito.when(mockSynchronizer.getStatReport(Boolean.TRUE)).thenReturn("mock-sync-index stat report");
+ Mockito.when(mockValidator.exists()).thenReturn(false);
+ Mockito.when(mockSynchronizer.getState()).thenReturn(SynchronizerState.PERFORMING_SYNCHRONIZATION,
+ SynchronizerState.PERFORMING_SYNCHRONIZATION, SynchronizerState.PERFORMING_SYNCHRONIZATION,
+ SynchronizerState.PERFORMING_SYNCHRONIZATION, SynchronizerState.PERFORMING_SYNCHRONIZATION,
+ SynchronizerState.IDLE);
+
+ syncController.registerEntitySynchronizer(mockSynchronizer);
+ syncController.registerIndexValidator(mockValidator);
+ syncController.registerIndexCleaner(mockCleaner);
+
+
+
+
+ syncController.performAction(SyncActions.SYNCHRONIZE);
+
+
+ }
+
+
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/sync/config/ElasticSearchEndpointConfigTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/sync/config/ElasticSearchEndpointConfigTest.java
new file mode 100644
index 0000000..35dd0bd
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/sync/config/ElasticSearchEndpointConfigTest.java
@@ -0,0 +1,39 @@
+package org.onap.aai.sparky.sync.config;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+
+
+
+import org.junit.Before;
+import org.junit.Test;
+
+
+public class ElasticSearchEndpointConfigTest {
+
+ private ElasticSearchEndpointConfig elasticSearchEndpointConfig;
+
+ @Before
+ public void init() throws Exception {
+ elasticSearchEndpointConfig = new ElasticSearchEndpointConfig();
+
+ }
+
+
+ @Test
+ public void updateValues() {
+
+ elasticSearchEndpointConfig.setEsIpAddress("10.247.25.26");
+ assertNotNull(elasticSearchEndpointConfig.getEsIpAddress());
+ elasticSearchEndpointConfig.setEsServerPort("6585");
+ assertNotNull(elasticSearchEndpointConfig.getEsServerPort());
+ elasticSearchEndpointConfig.setScrollContextTimeToLiveInMinutes(3);
+ assertEquals(3,elasticSearchEndpointConfig.getScrollContextTimeToLiveInMinutes());
+ elasticSearchEndpointConfig.setScrollContextBatchRequestSize(3);
+ assertEquals(3,elasticSearchEndpointConfig.getScrollContextBatchRequestSize());
+
+ }
+
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/sync/config/ElasticSearchSchemaConfigTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/sync/config/ElasticSearchSchemaConfigTest.java
new file mode 100644
index 0000000..88e96b0
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/sync/config/ElasticSearchSchemaConfigTest.java
@@ -0,0 +1,47 @@
+package org.onap.aai.sparky.sync.config;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class ElasticSearchSchemaConfigTest {
+
+private ElasticSearchSchemaConfig elasticSchemaConfig;
+
+ @Before
+ public void init() throws Exception {
+ elasticSchemaConfig = new ElasticSearchSchemaConfig();
+
+ }
+
+
+ @Test
+ public void updateValues() {
+
+ elasticSchemaConfig.setIndexName("entitysearchindex-localhost");
+ assertNotNull(elasticSchemaConfig.getIndexName());
+ elasticSchemaConfig.setIndexDocType("default");
+ assertNotNull(elasticSchemaConfig.getIndexDocType());
+ elasticSchemaConfig.setIndexSettingsFileName("/etc/es_settings.json");
+ assertNotNull(elasticSchemaConfig.getIndexSettingsFileName());
+ elasticSchemaConfig.setIndexMappingsFileName("/etc/es_mappings.json");
+ assertNotNull(elasticSchemaConfig.getIndexMappingsFileName());
+ assertNotNull(elasticSchemaConfig.toString());
+ elasticSchemaConfig.setIndexName(null);
+ assertNull(elasticSchemaConfig.getIndexName());
+ elasticSchemaConfig.setIndexDocType(null);
+ assertNull(elasticSchemaConfig.getIndexDocType());
+ elasticSchemaConfig.setIndexSettingsFileName(null);
+ assertNull(elasticSchemaConfig.getIndexSettingsFileName());
+ elasticSchemaConfig.setIndexMappingsFileName(null);
+ assertNull(elasticSchemaConfig.getIndexMappingsFileName());
+ assertNotNull(elasticSchemaConfig.toString());
+
+
+ }
+
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/sync/config/NetworkStatisticsConfigTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/sync/config/NetworkStatisticsConfigTest.java
new file mode 100644
index 0000000..4e97c6d
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/sync/config/NetworkStatisticsConfigTest.java
@@ -0,0 +1,74 @@
+package org.onap.aai.sparky.sync.config;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class NetworkStatisticsConfigTest {
+
+ private NetworkStatisticsConfig networkStatsConfig;
+
+ @Before
+ public void init() throws Exception {
+ networkStatsConfig = new NetworkStatisticsConfig();
+
+ }
+
+
+ @Test
+ public void updateValues() {
+
+
+
+ networkStatsConfig.setNumSamplesPerThreadForRunningAverage(300);
+ assertEquals(300,networkStatsConfig.getNumSamplesPerThreadForRunningAverage());
+ networkStatsConfig.setBytesHistogramMaxYAxis(25000);
+ assertEquals(25000,networkStatsConfig.getBytesHistogramMaxYAxis());
+ networkStatsConfig.setBytesHistogramLabel("[Response Size In Bytes]");
+ assertNotNull(networkStatsConfig.getBytesHistogramLabel());
+ networkStatsConfig.setQueueLengthHistogramLabel("[Queue Item Length]");
+ assertNotNull(networkStatsConfig.getQueueLengthHistogramLabel());
+ networkStatsConfig.setTaskAgeHistogramLabel("[Task Age In Ms]");
+ assertNotNull(networkStatsConfig.getTaskAgeHistogramLabel());
+ networkStatsConfig.setResponseTimeHistogramLabel("[Response Time In Ms]");
+ assertNotNull(networkStatsConfig.getResponseTimeHistogramLabel());
+ networkStatsConfig.setBytesHistogramNumBins(30);
+ assertEquals(30,networkStatsConfig.getBytesHistogramNumBins());
+ networkStatsConfig.setBytesHistogramNumDecimalPoints(5);
+ assertEquals(5,networkStatsConfig.getBytesHistogramNumDecimalPoints());
+ networkStatsConfig.setQueueLengthHistogramMaxYAxis(30000);
+ assertEquals(30000,networkStatsConfig.getQueueLengthHistogramMaxYAxis());
+ networkStatsConfig.setQueueLengthHistogramNumBins(25);
+ assertEquals(25,networkStatsConfig.getQueueLengthHistogramNumBins());
+ networkStatsConfig.setQueueLengthHistogramNumDecimalPoints(3);
+ assertEquals(3,networkStatsConfig.getQueueLengthHistogramNumDecimalPoints());
+ networkStatsConfig.setTaskAgeHistogramMaxYAxis(2500000);
+ assertEquals(2500000,networkStatsConfig.getTaskAgeHistogramMaxYAxis());
+ networkStatsConfig.setTaskAgeHistogramNumBins(3);
+ assertEquals(3,networkStatsConfig.getTaskAgeHistogramNumBins());
+ networkStatsConfig.setTaskAgeHistogramNumDecimalPoints(25);
+ assertEquals(25,networkStatsConfig.getTaskAgeHistogramNumDecimalPoints());
+ networkStatsConfig.setTpsHistogramLabel("[Transactions Per Second]");
+ assertNotNull(networkStatsConfig.getTpsHistogramLabel());
+ networkStatsConfig.setResponseTimeHistogramMaxYAxis(3);
+ assertEquals(3,networkStatsConfig.getResponseTimeHistogramMaxYAxis());
+ networkStatsConfig.setResponseTimeHistogramNumBins(25);
+ assertEquals(25,networkStatsConfig.getResponseTimeHistogramNumBins());
+ networkStatsConfig.setResponseTimeHistogramNumDecimalPoints(3);
+ assertEquals(3,networkStatsConfig.getResponseTimeHistogramNumDecimalPoints());
+ networkStatsConfig.setTpsHistogramMaxYAxis(25);
+ assertEquals(25,networkStatsConfig.getTpsHistogramMaxYAxis());
+ networkStatsConfig.setTpsHistogramNumBins(3);
+ assertEquals(3,networkStatsConfig.getTpsHistogramNumBins());
+ networkStatsConfig.setTpsHistogramNumDecimalPoints(25);
+ assertEquals(25,networkStatsConfig.getTpsHistogramNumDecimalPoints());
+
+
+
+ }
+
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/sync/config/SyncControllerConfigTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/sync/config/SyncControllerConfigTest.java
new file mode 100644
index 0000000..5aa4650
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/sync/config/SyncControllerConfigTest.java
@@ -0,0 +1,64 @@
+package org.onap.aai.sparky.sync.config;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+
+import org.junit.Before;
+import org.junit.Test;
+
+
+public class SyncControllerConfigTest {
+
+ private SyncControllerConfig syncControllerConfig;
+
+ @Before
+ public void init() throws Exception {
+ syncControllerConfig = new SyncControllerConfig();
+
+
+ }
+
+
+ @Test
+ public void updateValues() {
+
+
+
+
+
+ syncControllerConfig.setNumInternalSyncWorkers(3);
+ assertEquals(3,syncControllerConfig.getNumInternalSyncWorkers());
+ syncControllerConfig.setNumSyncElasticWorkers(5);
+ assertEquals(5,syncControllerConfig.getNumSyncElasticWorkers());
+ syncControllerConfig.setNumSyncActiveInventoryWorkers(6);
+ assertEquals(6,syncControllerConfig.getNumSyncActiveInventoryWorkers());
+ syncControllerConfig.setTargetSyncStartTimeStamp("05:00:00 UTC+00:00");
+ assertNotNull(syncControllerConfig.getTargetSyncStartTimeStamp());
+ syncControllerConfig.setControllerName("Historical-Entity-Sync-Controller");
+ assertNotNull(syncControllerConfig.getControllerName());
+ syncControllerConfig.setEnabled(true);
+ assertTrue(syncControllerConfig.isEnabled());
+ syncControllerConfig.setSyncTaskDelayInMs(8);
+ assertEquals(8,syncControllerConfig.getSyncTaskDelayInMs());
+ syncControllerConfig.setSyncTaskFrequencyInDays(3);
+ assertEquals(3,syncControllerConfig.getSyncTaskFrequencyInDays());
+ syncControllerConfig.setNumSyncControllerWorkers(25);
+ assertEquals(25,syncControllerConfig.getNumSyncControllerWorkers());
+ syncControllerConfig.setRunOnceSyncEnabled(true);
+ assertTrue(syncControllerConfig.isRunOnceSyncEnabled());
+ syncControllerConfig.setPeriodicSyncEnabled(true);
+ assertTrue(syncControllerConfig.isPeriodicSyncEnabled());
+ assertNotNull(syncControllerConfig.getSyncFrequencyInMs());
+ assertNotNull(syncControllerConfig.getTargetSyncTime());
+ assertNotNull(syncControllerConfig.getNextSyncTime());
+ syncControllerConfig.setTimeZoneOfSyncStartTimeStamp("UTC+00:00");
+ assertNotNull(syncControllerConfig.getTimeZoneOfSyncStartTimeStamp());
+
+ }
+
+
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/synchronizer/AsyncRateControlTester.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/synchronizer/AsyncRateControlTester.java
new file mode 100644
index 0000000..00bec1e
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/synchronizer/AsyncRateControlTester.java
@@ -0,0 +1,242 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+
+package org.onap.aai.sparky.synchronizer;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.onap.aai.sparky.sync.config.NetworkStatisticsConfig;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The Class AsyncRateControlTester.
+ */
+public class AsyncRateControlTester {
+
+ private static Logger logger = LoggerFactory.getLogger(AsyncRateControlTester.class);
+
+ private long startTimeInMs;
+
+ private AtomicInteger counter;
+
+ protected boolean syncInProgress;
+
+ /**
+ * Instantiates a new async rate control tester.
+ *
+ * @throws Exception the exception
+ */
+ public AsyncRateControlTester() throws Exception {
+
+ NetworkStatisticsConfig tpc = new NetworkStatisticsConfig();
+
+ tpc.setNumSamplesPerThreadForRunningAverage(100);
+
+ tpc.setBytesHistogramLabel("bytesHistoLabel");
+ tpc.setBytesHistogramMaxYAxis(1000000);
+ tpc.setBytesHistogramNumBins(20);
+ tpc.setBytesHistogramNumDecimalPoints(2);
+
+ tpc.setQueueLengthHistogramLabel("queueHistoLabel");
+ tpc.setQueueLengthHistogramMaxYAxis(1000000);
+ tpc.setQueueLengthHistogramNumBins(20);
+ tpc.setQueueLengthHistogramNumDecimalPoints(2);
+
+ // ZeroDelayProcessor zdp = new ZeroDelayProcessor(LinkProcessorType.AAI, tpc);
+ // zdp.setStatCollector(this.aaiStatCollector);
+ /*
+ * zdp.setTaskProcessorConfig(tpc);
+ *
+ * this.resolver.registerProcessor(zdp); this.resolver.registerEventListener(this); this.counter
+ * = new AtomicInteger(0); this.syncInProgress = false; }
+ *
+ * @Override public void handleEvent(AsyncEvent event) {
+ *
+ * if(event.getEventType() == AsyncEventType.RESOLVER_IDLE) {
+ *
+ * if(syncInProgress) { long duration = System.currentTimeMillis() - startTimeInMs;
+ * System.out.println(getStatReport(duration)); syncInProgress = false; }
+ *
+ * // shutdown(); } else if(event.getEventType() == AsyncEventType.TRANSACTION_PROCESSED) {
+ *
+ * this.syncInProgress = true;
+ *
+ * ExternalResource resource = (ExternalResource)event.getPayload();
+ *
+ * //aaiStatCollector.updateCounters(resource);
+ *
+ * counter.incrementAndGet();
+ *
+ * }
+ *
+ * };
+ *
+ * public void shutdown() { resolver.shutdown(); }
+ *
+ * private int getCounterValue(AtomicInteger counter) {
+ *
+ * if(counter == null) { return 0; }
+ *
+ * return counter.get(); }
+ *
+ * private void addActiveInventoryStatReport(StringBuilder sb) {
+ *
+ * if(sb == null) { return; }
+ *
+ * sb.append("\n\n ").append(LinkProcessorType.AAI.name());
+ *
+ * sb.append("\n\n ").append("REST Operational Stats:");
+ *
+ * /* Map<String, AtomicInteger> procOperationalCounters =
+ * aaiStatCollector.getActiveInventoryOperationalCounters();
+ *
+ * if(procOperationalCounters != null) {
+ *
+ * int _1XX =
+ * getCounterValue(procOperationalCounters.get(ActiveInventoryStatCollector.GET_1XX)); int _2XX
+ * = getCounterValue(procOperationalCounters.get(ActiveInventoryStatCollector.GET_2XX)); int
+ * _3XX = getCounterValue(procOperationalCounters.get(ActiveInventoryStatCollector.GET_3XX));
+ * int _4XX =
+ * getCounterValue(procOperationalCounters.get(ActiveInventoryStatCollector.GET_4XX)); int _5XX
+ * = getCounterValue(procOperationalCounters.get(ActiveInventoryStatCollector.GET_5XX)); int
+ * _6XX = getCounterValue(procOperationalCounters.get(ActiveInventoryStatCollector.GET_6XX));
+ *
+ * sb.append("\n ").append(String.format(
+ * "%-12s 1XX: %-12d 2XX: %-12d 3XX: %-12d 4XX: %-12d 5XX: %-12d 6XX: %-12d ", HttpMethod.GET,
+ * _1XX, _2XX, _3XX, _4XX, _5XX, _6XX)); }
+ */
+
+ // sb.append("\n\n ").append("Entity Stats:");
+
+ /*
+ * sort entities, then sort nested op codes
+ */
+
+ /*
+ * TreeMap<String, HashMap<String, AtomicInteger>> activeInventoryEntitySortedTreeMap = new
+ * TreeMap<String, HashMap<String, AtomicInteger>>( new Comparator<String>() {
+ *
+ * public int compare(String o1, String o2) { return
+ * o1.toLowerCase().compareTo(o2.toLowerCase()); } });
+ */
+
+ /*
+ * activeInventoryEntitySortedTreeMap.putAll(aaiStatCollector.getActiveInventoryEntityCounters()
+ * );
+ *
+ * for(String counterEntityKey : activeInventoryEntitySortedTreeMap.keySet()) {
+ *
+ * HashMap<String, AtomicInteger> entityCounters =
+ * activeInventoryEntitySortedTreeMap.get(counterEntityKey);
+ *
+ * AtomicInteger total = entityCounters.get(ActiveInventoryStatCollector.TOTAL); AtomicInteger
+ * found = entityCounters.get(ActiveInventoryStatCollector.FOUND); AtomicInteger notFound =
+ * entityCounters.get(ActiveInventoryStatCollector.NOT_FOUND); AtomicInteger error =
+ * entityCounters.get(ActiveInventoryStatCollector.ERROR);
+ *
+ * int totalValue = (total == null) ? 0 : total.get(); int foundValue = (found == null) ? 0 :
+ * found.get(); int notFoundValue = (found == null) ? 0 : notFound.get(); int errorValue =
+ * (error == null) ? 0 : error.get();
+ *
+ * sb.append("\n ").append(String.format(
+ * "%-30s TOTAL: %-12d FOUND: %-12d NOT_FOUND: %-12d ERROR: %-12d", counterEntityKey,
+ * totalValue, foundValue, notFoundValue, errorValue));
+ *
+ * }
+ */
+
+ // sb.append("\n\n ").append("Task Processor Stats:");
+
+ // int totalRetries =
+ // getCounterValue(procOperationalCounters.get(ActiveInventoryStatCollector.NUM_RETRIES));
+ // int currentQueueLength = resolver.getCurrentQueueLength(LinkProcessorType.AAI.name());
+
+ /*
+ * sb.append("\n "
+ * ).append(resolver.getProcessorTaskAgeStats(LinkProcessorType.AAI.name(), false, " "
+ * )); sb.append("\n "
+ * ).append(resolver.getProcessorResponseStats(LinkProcessorType.AAI.name(), false, " "
+ * )); sb.append("\n")
+ * .append(resolver.getQueueItemLengthHistogram(LinkProcessorType.AAI.name(), false,
+ * " ")); sb.append("\n")
+ * .append(resolver.getResponseByteSizeHistogram(LinkProcessorType.AAI.name(), false,
+ * " ")); sb.append("\n "
+ * ).append("TPS=").append(resolver.getTPS(LinkProcessorType.AAI.name())).append(", NumRetries="
+ * ).append(totalRetries) .append(", CurrentQueueLength=").append(currentQueueLength);
+ */
+ /*
+ * }
+ *
+ * private String getStatReport(long syncOpTimeInMs) {
+ *
+ * StringBuilder sb = new StringBuilder(128);
+ *
+ * sb.append("\n").append("Async Resolver Statistics: ( Sync Operation Duration = " +
+ * NodeUtils.getDurationBreakdown(syncOpTimeInMs) + " )");
+ *
+ * addActiveInventoryStatReport(sb);
+ *
+ * return sb.toString();
+ *
+ * }
+ *
+ * public void loadResolver(int numItems) {
+ *
+ * if(numItems <= 0) { return; }
+ *
+ * startTimeInMs = System.currentTimeMillis();
+ *
+ * DummyPerformanceTask dpt = null;
+ *
+ * for(int i = 0; i < numItems; i++) {
+ *
+ * dpt = new DummyPerformanceTask(); dpt.setLinkProcessorType(LinkProcessorType.AAI);
+ * dpt.setResourceEntityType("DummyPerformanceEntity"); dpt.setOperationType(HttpMethod.GET);
+ *
+ * resolver.resolve(dpt);
+ *
+ * }
+ *
+ * }
+ *
+ * public static void main(String[] args) throws Exception {
+ *
+ * System.getProperties().setProperty("AJSC_HOME", "x:\\aaiui\\");
+ *
+ * System.out.println("Available processors = " + Runtime.getRuntime().availableProcessors());
+ *
+ * AsyncRateControlTester arcTester = new AsyncRateControlTester();
+ *
+ * // give us time to instrument the jvm with jvisualvm // Thread.sleep(30000);
+ * Thread.sleep(5000);
+ *
+ * arcTester.loadResolver(1000);
+ *
+ *
+ * }
+ */
+ }
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/synchronizer/GizmoEntitySummarizer.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/synchronizer/GizmoEntitySummarizer.java
new file mode 100644
index 0000000..5ea5280
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/synchronizer/GizmoEntitySummarizer.java
@@ -0,0 +1,251 @@
+package org.onap.aai.sparky.synchronizer;
+
+import static java.util.concurrent.CompletableFuture.supplyAsync;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.TreeMap;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
+import java.util.function.Supplier;
+
+import org.onap.aai.cl.api.Logger;
+import org.onap.aai.cl.eelf.LoggerFactory;
+import org.onap.aai.restclient.client.OperationResult;
+import org.onap.aai.restclient.enums.RestAuthenticationMode;
+import org.onap.aai.sparky.config.oxm.OxmModelLoader;
+import org.onap.aai.sparky.dal.GizmoAdapter;
+import org.onap.aai.sparky.dal.exception.ElasticSearchOperationException;
+import org.onap.aai.sparky.dal.rest.RestClientConstructionException;
+import org.onap.aai.sparky.dal.rest.config.RestEndpointConfig;
+import org.onap.aai.sparky.logging.AaiUiMsgs;
+import org.onap.aai.sparky.util.NodeUtils;
+import org.onap.aai.sparky.util.OxmModelAndProcessorHelper;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+
+public class GizmoEntitySummarizer {
+
+ protected ObjectMapper mapper;
+ protected OxmModelLoader oxmModelLoader;
+ private static final Logger logger = LoggerFactory.getInstance().getLogger(GizmoEntitySummarizer.class);
+ protected ExecutorService gizmoExecutor;
+ protected GizmoAdapter gizmoAdapter;
+ protected OxmModelAndProcessorHelper oxmHelper;
+
+ /*
+ * We need to add another concept to the OxmModelLoader which is to generate
+ * a list of entity containers from the OXM JaxbContext
+ */
+
+ public GizmoEntitySummarizer()
+ throws ElasticSearchOperationException, IOException, RestClientConstructionException {
+
+ OxmModelAndProcessorHelper.API_VERSION_OVERRIDE = 11;
+
+ this.gizmoExecutor = NodeUtils.createNamedExecutor("GIZMO-WORKER", 5, logger);
+
+ oxmHelper = OxmModelAndProcessorHelper.getInstance();
+ this.oxmModelLoader = oxmHelper.getModelLoader();
+
+ this.mapper = new ObjectMapper();
+
+ RestEndpointConfig gizmoConfig = new RestEndpointConfig();
+
+ gizmoConfig.setEndpointIpAddress("10.147.138.153");
+ gizmoConfig.setEndpointServerPort("9520");
+ gizmoConfig.setNumRequestRetries(5);
+ gizmoConfig.setRestAuthenticationMode(RestAuthenticationMode.SSL_CERT);
+ gizmoConfig.setConnectTimeoutInMs(60000);
+ gizmoConfig.setReadTimeoutInMs(30000);
+ gizmoConfig.setCertFileName("client-cert-onap.p12");
+ gizmoConfig.setCertPassword("OBF:1y0q1uvc1uum1uvg1pil1pjl1uuq1uvk1uuu1y10");
+ gizmoConfig.setTruststoreFileName("synchronizer.jks");
+ gizmoConfig.setValidateServerCertChain(false);
+ gizmoConfig.setValidateServerHostname(false);
+
+ gizmoAdapter = new GizmoAdapter(oxmModelLoader, gizmoConfig);
+
+ gizmoAdapter.setInventoryBasePath("/services/inventory/v12/");
+ gizmoAdapter.setRelationshipsBasePath("/services/inventory/relationships/v12/");
+
+ }
+
+ private Map<String, Integer> getNumEntitiesPerType() {
+
+ Collection<String> containerTypes = oxmHelper.getOxmEntityContainerLookup().getEntityContainers();
+ Collection<String> links = new ArrayList<String>();
+ Map<String, Integer> entityTypeCounts = new TreeMap<String, Integer>();
+
+ final CountDownLatch latch = new CountDownLatch(containerTypes.size());
+
+ for (String entityType : containerTypes) {
+
+ supplyAsync(new Supplier<Void>() {
+
+ @Override
+ public Void get() {
+
+ OperationResult typeLinksResult = null;
+ try {
+ typeLinksResult = gizmoAdapter.queryGizmoWithRetries(
+ gizmoAdapter.getFullInventoryUrl(entityType), "application/json", 1);
+
+ if (typeLinksResult != null) {
+
+ if (typeLinksResult.wasSuccessful() && typeLinksResult.getResult() != null) {
+
+ JsonNode rootNode = mapper.readValue(typeLinksResult.getResult(), JsonNode.class);
+
+ if (rootNode.isArray()) {
+ ArrayNode arrayNode = (ArrayNode) rootNode;
+ entityTypeCounts.put(entityType, new Integer(arrayNode.size()));
+ } else {
+ entityTypeCounts.put(entityType, new Integer(-1));
+ }
+
+ } else {
+ // -1
+ entityTypeCounts.put(entityType, new Integer(-1));
+ }
+
+ }
+
+ } catch (Exception exc) {
+ entityTypeCounts.put(entityType, new Integer(-1));
+ }
+
+ return null;
+ }
+
+ }, gizmoExecutor).whenComplete((result, error) -> {
+
+ latch.countDown();
+
+ if (error != null) {
+ logger.error(AaiUiMsgs.ERROR_GENERIC,
+ "An error occurred getting data from AAI. Error = " + error.getMessage());
+ }
+
+ });
+
+ }
+
+ // System.out.println("self links size = " + selflinks.size());
+
+ try {
+ latch.await();
+ } catch (InterruptedException e) {
+
+ }
+
+ return entityTypeCounts;
+ }
+
+ private Map<String, Integer> getNumRelationshipsPerType() {
+
+ Map<String, Integer> entityTypeCounts = new TreeMap<String, Integer>();
+
+ final CountDownLatch latch = new CountDownLatch(1);
+
+ supplyAsync(new Supplier<Void>() {
+
+ @Override
+ public Void get() {
+
+ OperationResult typeLinksResult = null;
+ try {
+ typeLinksResult = gizmoAdapter.queryGizmoWithRetries(gizmoAdapter.getFullRelationshipUrl("has"),
+ "application/json", 1);
+
+ if (typeLinksResult != null) {
+
+ if (typeLinksResult.wasSuccessful() && typeLinksResult.getResult() != null) {
+
+ JsonNode rootNode = mapper.readValue(typeLinksResult.getResult(), JsonNode.class);
+
+ if (rootNode.isArray()) {
+ ArrayNode arrayNode = (ArrayNode) rootNode;
+ entityTypeCounts.put("has", new Integer(arrayNode.size()));
+ } else {
+ entityTypeCounts.put("has", new Integer(-1));
+ }
+
+ } else {
+ // -1
+ entityTypeCounts.put("has", new Integer(-1));
+ }
+
+ } else {
+ entityTypeCounts.put("has", new Integer(-1));
+ }
+
+ } catch (Exception exc) {
+ entityTypeCounts.put("has", new Integer(-1));
+ }
+
+ return null;
+ }
+
+ }, gizmoExecutor).whenComplete((result, error) -> {
+
+ latch.countDown();
+
+ if (error != null) {
+ logger.error(AaiUiMsgs.ERROR_GENERIC,
+ "An error occurred getting data from AAI. Error = " + error.getMessage());
+ }
+
+ });
+
+ // System.out.println("self links size = " + selflinks.size());
+
+ try {
+ latch.await();
+ } catch (InterruptedException e) {
+
+ }
+
+ return entityTypeCounts;
+ }
+
+ public void shutdown() {
+ this.gizmoExecutor.shutdown();
+ }
+
+ public static void main(String[] args)
+ throws ElasticSearchOperationException, IOException, RestClientConstructionException {
+
+ System.setProperty("CONFIG_HOME", "X:\\2018_dev\\OSEAAI\\gizmo_integration\\onap_sparky-be\\appconfig-local\\");
+ GizmoEntitySummarizer gizmoSummarizer = new GizmoEntitySummarizer();
+
+ Map<String, Integer> entityCounts = gizmoSummarizer.getNumEntitiesPerType();
+ Map<String, Integer> relationshipCounts = gizmoSummarizer.getNumRelationshipsPerType();
+ gizmoSummarizer.shutdown();
+
+ System.out.println("Gizmo Entities:");
+
+ for (Entry<String, Integer> entry : entityCounts.entrySet()) {
+ String key = entry.getKey();
+ Integer value = entry.getValue();
+
+ System.out.printf("\t%s : %d\n", key, value);
+ }
+
+ System.out.println("\nGizmo Relationships:");
+
+ for (Entry<String, Integer> entry : relationshipCounts.entrySet()) {
+ String key = entry.getKey();
+ Integer value = entry.getValue();
+
+ System.out.printf("\t%s : %d\n", key, value);
+ }
+
+ }
+
+} \ No newline at end of file
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/synchronizer/IndexDocumentTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/synchronizer/IndexDocumentTest.java
new file mode 100644
index 0000000..0451ec5
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/synchronizer/IndexDocumentTest.java
@@ -0,0 +1,104 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+
+package org.onap.aai.sparky.synchronizer;
+
+import java.io.IOException;
+import java.security.NoSuchAlgorithmException;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.onap.aai.sparky.util.LogValidator;
+
+import ch.qos.logback.classic.Level;
+
+
+/**
+ * The Class IndexDocumentTest.
+ */
+@RunWith(MockitoJUnitRunner.class)
+public class IndexDocumentTest {
+
+ private LogValidator logValidator;
+
+
+ /**
+ * Inits the.
+ *
+ * @throws Exception the exception
+ */
+ @Before
+ public void init() throws Exception {
+ logValidator = new LogValidator();
+ logValidator.initializeLogger(Level.WARN);
+ }
+
+ /**
+ * Validate basic construction.
+ *
+ * @throws NoSuchAlgorithmException the no such algorithm exception
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ @Test
+ public void validateBasicConstruction() throws NoSuchAlgorithmException, IOException {
+
+ /*
+ * String testDate = "2016-12-21 00:00:00.00"; OxmEntityDescriptor d = new
+ * OxmEntityDescriptor(); d.setEntityName("service-instance");
+ * d.setPrimaryKeyAttributeName(Arrays.asList("service-instance-id"));
+ * d.setSearchableAttributes(Arrays.asList("service-instance-id"));
+ *
+ * Mockito.when(oxmModelLoader.getEntityDescriptor(anyString())).thenReturn(d);
+ *
+ * SearchableEntity id1 = new SearchableEntity(oxmModelLoader);
+ *
+ * id1.setEntityType("service-instance"); id1.setEntityPrimaryKeyValue("DUP2");
+ * id1.addSearchTagWithIdx("DUP2", String.valueOf(1));
+ *
+ * id1.deriveFields(); id1.setEntityTimeStamp(testDate); ObjectMapper mapper = new
+ * ObjectMapper();
+ *
+ * String objStr = id1.getIndexDocumentJson();
+ *
+ * JsonNode indexDocNode = mapper.readTree(objStr);
+ *
+ * ///
+ *
+ * ObjectNode expectedNode = mapper.createObjectNode(); expectedNode.put("entityType",
+ * "service-instance"); expectedNode.put("entityPrimaryKeyValue", "DUP2");
+ * expectedNode.put("searchTagIDs", "1"); expectedNode.put("searchTags", "DUP2");
+ * expectedNode.put("crossEntityReferenceValues", ""); expectedNode.put("lastmodTimestamp",
+ * testDate);
+ *
+ * assertTrue(NodeUtils.isEqual(expectedNode, indexDocNode)); // Test if the timestamp is
+ * calculated when the node is being created
+ * assertTrue(NodeUtils.getNodeFieldAsText(indexDocNode, "lastmodTimestamp") != null);
+ */
+
+ }
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/synchronizer/IndexableCrossEntityReferenceTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/synchronizer/IndexableCrossEntityReferenceTest.java
new file mode 100644
index 0000000..a7c34d0
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/synchronizer/IndexableCrossEntityReferenceTest.java
@@ -0,0 +1,72 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+
+package org.onap.aai.sparky.synchronizer;
+
+import java.io.IOException;
+import java.security.NoSuchAlgorithmException;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.onap.aai.sparky.sync.entity.IndexableCrossEntityReference;
+
+public class IndexableCrossEntityReferenceTest {
+
+ /**
+ * Inits the.
+ *
+ * @throws Exception the exception
+ */
+ @Before
+ public void init() throws Exception {
+
+ }
+
+ /**
+ * Validate basic construction.
+ *
+ * @throws NoSuchAlgorithmException the no such algorithm exception
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ @Test
+ public void validateBasicConstruction() throws NoSuchAlgorithmException, IOException {
+
+ IndexableCrossEntityReference icer = new IndexableCrossEntityReference();
+
+ icer.setId("MyId");
+ icer.setEntityType("Scott");
+ icer.setEntityPrimaryKeyValue("woot");
+ icer.setLink("me.link.yeeeeeaahhhh");
+
+ icer.addCrossEntityReferenceValue("meow");
+ icer.addCrossEntityReferenceValue("kitty-goes");
+ icer.addCrossEntityReferenceValue("kitty-goes-meow");
+
+ icer.deriveFields();
+
+ System.out.println(icer.getAsJson());
+
+ }
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/synchronizer/SyncControllerBuilder.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/synchronizer/SyncControllerBuilder.java
new file mode 100644
index 0000000..84d7fd2
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/synchronizer/SyncControllerBuilder.java
@@ -0,0 +1,512 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+
+package org.onap.aai.sparky.synchronizer;
+
+/**
+ * The Class SyncControllerBuilder.
+ */
+public class SyncControllerBuilder {
+
+
+ /*
+ * We'll have to revisit this class, as the sync controllers are wired up pretty differently now
+ */
+
+ /**
+ * Test elastic search update api.
+ */
+/* public void testElasticSearchUpdateApi() {
+ try {
+
+ RestClientBuilder clientBuilder = new RestClientBuilder();
+ clientBuilder.setUseHttps(false);
+
+ RestfulDataAccessor nonCachingRestProvider = new RestfulDataAccessor(clientBuilder);
+
+ ElasticSearchConfig esConfig = ElasticSearchConfig.getConfig();
+ ElasticSearchDataProvider elasticSearchDataProvider =
+ new ElasticSearchAdapter(nonCachingRestProvider, esConfig);
+
+ String payload =
+ "{ \"entityType\": \"complex\", \"pkey\": \"MORRISTOWN0075\", \"location\": { \"lat\": \"40.793414\", \"lon\": \"-74.480432\" }, \"selfLink\": \"https://aai-int1.test.att.com:8443/aai/v8/cloud-infrastructure/complexes/complex/MORRISTOWN0075?nodes-only\" }\n";
+
+ String updateRequest = elasticSearchDataProvider.buildBulkImportOperationRequest(
+ "topographysearchindex-localhost", "default",
+ "1e2a6ba9e09d5e1bcb016b3a0b8d50273b42828e47957bd2a2f3ce1854744f5f", "6", payload);
+
+ OperationResult or =
+ elasticSearchDataProvider.doBulkOperation("http://localhost:9200/_bulk", updateRequest);
+
+ System.out.println(or.toString());
+
+ /*
+ * String BULK_IMPORT_INDEX_TEMPLATE =
+ * "{\"index\":{\"_index\":\"%s\",\"_type\":\"%s\",\"_id\":\"%s\", \"_version\":\"%s\"}}\n";
+ *
+ * StringBuilder updateRequestPayload = new StringBuilder(128);
+ * updateRequestPayload.append(String.format(BULK_IMPORT_INDEX_TEMPLATE,
+ * "topographysearchindex-localhost", "default",
+ * "1e2a6ba9e09d5e1bcb016b3a0b8d50273b42828e47957bd2a2f3ce1854744f5f", "5"));
+ *
+ *
+ * updateRequestPayload.append(payload);
+ *
+ * OperationResult or = nonCachingRestProvider.doRestfulOperation(HttpMethod.PUT,
+ * "http://localhost:9200/_bulk", updateRequestPayload.toString(),
+ * RestfulDataAccessor.APPLICATION_X_WWW_FORM_URL_ENCODED,
+ * RestfulDataAccessor.APPLICATION_JSON);
+ */
+
+
+/*
+ } catch (Exception exc) {
+ exc.printStackTrace();
+ System.out.println("Error: failed to sync with message = " + exc.getMessage());
+ }
+ }
+
+ /**
+ * Do historical entity sync.
+ *//*
+ public void doHistoricalEntitySync() {
+ try {
+ SyncController syncController = new SyncControllerImpl("historicalEntityTestController");
+
+ ActiveInventoryAdapter aaiAdapter = new ActiveInventoryAdapter(new OxmModelLoader(), new RestClientBuilder());
+
+ RestClientBuilder clientBuilder = new RestClientBuilder();
+ clientBuilder.setUseHttps(false);
+
+ RestfulDataAccessor nonCachingRestProvider = new RestfulDataAccessor(clientBuilder);
+
+ ElasticSearchConfig esConfig = ElasticSearchConfig.getConfig();
+
+ ElasticSearchAdapter esAdapter = new ElasticSearchAdapter(nonCachingRestProvider,esConfig);
+
+
+ IndexIntegrityValidator entityCounterHistoryValidator =
+ new IndexIntegrityValidator(nonCachingRestProvider, esConfig.getEntityCountHistoryIndex(),
+ esConfig.getType(), esConfig.getIpAddress(), esConfig.getHttpPort(),
+ esConfig.buildElasticSearchEntityCountHistoryTableConfig());
+
+ syncController.registerIndexValidator(entityCounterHistoryValidator);
+
+
+ //////
+
+
+
+ HistoricalEntitySummarizer historicalSummarizer =
+ new HistoricalEntitySummarizer(esConfig.getEntityCountHistoryIndex());
+ historicalSummarizer.setAaiDataProvider(aaiAdapter);
+ historicalSummarizer.setEsDataProvider(esAdapter);
+ syncController.registerEntitySynchronizer(historicalSummarizer);
+
+ ////
+
+ /*
+ * IndexIntegrityValidator entitySearchIndexValidator = new IndexIntegrityValidator(new
+ * RestClientBuilder());
+ *
+ * entitySearchIndexValidator.setIndexName("topographysearchindex-localhost");
+ * entitySearchIndexValidator.setIndexType("default");
+ * entitySearchIndexValidator.setIndexSettings("");
+ * entitySearchIndexValidator.setIndexSettings("");
+ *
+ * syncController.registerIndexValidator(entitySearchIndexValidator);
+ */
+
+ ////
+
+ /*
+ * IndexCleaner index1Cleaner = new ElasticSearchIndexCleaner(nonCachingRestProvider,
+ * "topographysearchindex-localhost", "default", "127.0.0.1", "9200", 5, 5000);
+ */
+
+ // syncController.registerIndexCleaner(index1Cleaner);
+
+ ///
+/*
+ for (int x = 0; x < 10; x++) {
+
+ syncController.performAction(SyncActions.SYNCHRONIZE);
+
+ while (syncController.getState() == SynchronizerState.PERFORMING_SYNCHRONIZATION) {
+
+ System.out.println("sync controller state = " + syncController.getState());
+
+ Thread.sleep(1000);
+ }
+ }
+
+ syncController.shutdown();
+
+ } catch (Exception exc) {
+ exc.printStackTrace();
+ System.out.println("Error: failed to sync with message = " + exc.getMessage());
+ }
+ }
+
+ /**
+ * Do geo entity sync.
+ *//*
+ public void doGeoEntitySync() {
+ try {
+
+ ActiveInventoryAdapter aaiAdapter = new ActiveInventoryAdapter(new OxmModelLoader(), new RestClientBuilder());
+
+ RestClientBuilder clientBuilder = new RestClientBuilder();
+ clientBuilder.setUseHttps(false);
+
+ RestfulDataAccessor nonCachingRestProvider = new RestfulDataAccessor(clientBuilder);
+ ElasticSearchConfig esConfig = ElasticSearchConfig.getConfig();
+
+ ElasticSearchAdapter esAdapter = new ElasticSearchAdapter(nonCachingRestProvider,esConfig);
+
+ IndexIntegrityValidator entitySearchIndexValidator =
+ new IndexIntegrityValidator(nonCachingRestProvider, esConfig.getIndexName(),
+ esConfig.getType(), esConfig.getIpAddress(), esConfig.getHttpPort(),
+ esConfig.buildElasticSearchTableConfig());
+
+ SyncController syncController = new SyncControllerImpl("geoEntitySyncTestController");
+ syncController.registerIndexValidator(entitySearchIndexValidator);
+
+
+ //////
+
+ GeoSynchronizer geoSync = new GeoSynchronizer("topographysearchindex-localhost");
+ geoSync.setAaiDataProvider(aaiAdapter);
+ geoSync.setEsDataProvider(esAdapter);
+ syncController.registerEntitySynchronizer(geoSync);
+
+ ////
+
+ /*
+ * IndexIntegrityValidator entitySearchIndexValidator = new IndexIntegrityValidator(new
+ * RestClientBuilder());
+ *
+ * entitySearchIndexValidator.setIndexName("topographysearchindex-localhost");
+ * entitySearchIndexValidator.setIndexType("default");
+ * entitySearchIndexValidator.setIndexSettings("");
+ * entitySearchIndexValidator.setIndexSettings("");
+ *
+ * syncController.registerIndexValidator(entitySearchIndexValidator);
+ */
+
+ ////
+
+ /*
+ * IndexCleaner index1Cleaner = new ElasticSearchIndexCleaner(nonCachingRestProvider,
+ * "topographysearchindex-localhost", "default", "127.0.0.1", "9200", 5, 5000);
+ */
+
+ // syncController.registerIndexCleaner(index1Cleaner);
+
+ ///
+/*
+ syncController.performAction(SyncActions.SYNCHRONIZE);
+
+ while (syncController.getState() == SynchronizerState.PERFORMING_SYNCHRONIZATION) {
+ Thread.sleep(1000);
+ }
+
+ syncController.shutdown();
+
+ } catch (Exception exc) {
+ exc.printStackTrace();
+ System.out.println("Error: failed to sync with message = " + exc.getMessage());
+ }
+ }
+
+ /**
+ * Do searchable entitysync.
+ *//*
+ public void doSearchableEntitysync() {
+ try {
+
+
+ ActiveInventoryAdapter aaiAdapter = new ActiveInventoryAdapter(new OxmModelLoader(), new RestClientBuilder());
+
+ RestClientBuilder clientBuilder = new RestClientBuilder();
+ clientBuilder.setUseHttps(false);
+
+ RestfulDataAccessor nonCachingRestProvider = new RestfulDataAccessor(clientBuilder);
+ ElasticSearchConfig esConfig = ElasticSearchConfig.getConfig();
+
+ ElasticSearchAdapter esAdapter = new ElasticSearchAdapter(nonCachingRestProvider,esConfig);
+
+ //////
+
+ SyncController syncController = new SyncControllerImpl("searchtableEntityTestController");
+
+ ViewInspectEntitySynchronizer ses =
+ new ViewInspectEntitySynchronizer("entitysearchindex-localhost");
+ ses.setAaiDataProvider(aaiAdapter);
+ ses.setEsDataProvider(esAdapter);
+ syncController.registerEntitySynchronizer(ses);
+
+ ////
+
+ /*
+ * IndexIntegrityValidator entitySearchIndexValidator = new IndexIntegrityValidator(new
+ * RestClientBuilder());
+ *
+ * entitySearchIndexValidator.setIndexName("esi-sync2-localhost");
+ * entitySearchIndexValidator.setIndexType("default");
+ *
+ * syncController.registerIndexValidator(entitySearchIndexValidator);
+ */
+
+ ////
+
+ /*
+ * IndexCleaner index1Cleaner = new ElasticSearchIndexCleaner(nonCachingRestProvider,
+ * "entitysearchindex-localhost", "default", "127.0.0.1", "9200", 5, 5000);
+ *
+ * syncController.registerIndexCleaner(index1Cleaner);
+ */
+
+ ///
+/*
+ syncController.performAction(SyncActions.SYNCHRONIZE);
+
+ while (syncController.getState() == SynchronizerState.PERFORMING_SYNCHRONIZATION) {
+ Thread.sleep(1000);
+ }
+
+ syncController.shutdown();
+
+ } catch (Exception exc) {
+ exc.printStackTrace();
+ System.out.println("Error: failed to sync with message = " + exc.getMessage());
+ }
+ }
+
+ /**
+ * Do cross entity reference sync.
+ *//*
+ public void doCrossEntityReferenceSync() {
+ try {
+
+ ActiveInventoryAdapter aaiAdapter = new ActiveInventoryAdapter(new OxmModelLoader(), new RestClientBuilder());
+
+ RestClientBuilder clientBuilder = new RestClientBuilder();
+ clientBuilder.setUseHttps(false);
+
+ RestfulDataAccessor nonCachingRestProvider = new RestfulDataAccessor(clientBuilder);
+ ElasticSearchConfig esConfig = ElasticSearchConfig.getConfig();
+
+ ElasticSearchAdapter esAdapter = new ElasticSearchAdapter(nonCachingRestProvider,esConfig);
+
+ SyncController syncController = new SyncControllerImpl("crossEntityRefSyncController");
+
+ CrossEntityReferenceSynchronizer cers =
+ new CrossEntityReferenceSynchronizer("entitysearchindex-localhost", ActiveInventoryConfig.getConfig());
+ cers.setAaiDataProvider(aaiAdapter);
+ cers.setEsDataProvider(esAdapter);
+ syncController.registerEntitySynchronizer(cers);
+
+ ViewInspectEntitySynchronizer ses =
+ new ViewInspectEntitySynchronizer("entitysearchindex-localhost");
+ ses.setAaiDataProvider(aaiAdapter);
+ ses.setEsDataProvider(esAdapter);
+ syncController.registerEntitySynchronizer(ses);
+
+ ElasticSearchConfig config = ElasticSearchConfig.getConfig();
+
+ IndexIntegrityValidator entitySearchIndexValidator = new IndexIntegrityValidator(
+ nonCachingRestProvider, config.getIndexName(), config.getType(), config.getIpAddress(),
+ config.getHttpPort(), config.buildElasticSearchTableConfig());
+
+ syncController.registerIndexValidator(entitySearchIndexValidator);
+
+ ////
+
+ IndexCleaner index1Cleaner =
+ new ElasticSearchIndexCleaner(nonCachingRestProvider, config.getIndexName(),
+ config.getType(), config.getIpAddress(), config.getHttpPort(), 5, 5000);
+
+ syncController.registerIndexCleaner(index1Cleaner);
+
+ ///
+
+ syncController.performAction(SyncActions.SYNCHRONIZE);
+
+ while (syncController.getState() == SynchronizerState.PERFORMING_SYNCHRONIZATION) {
+ Thread.sleep(1000);
+ }
+
+ syncController.shutdown();
+
+ } catch (Exception exc) {
+ exc.printStackTrace();
+ System.out.println("Error: Failed to sync with message = " + exc.getMessage());
+ }
+ }
+
+ /**
+ * Do suggestion entitysync.
+ *//*
+ public void doSuggestionEntitySync() {
+ try {
+ ActiveInventoryAdapter aaiAdapter = new ActiveInventoryAdapter(new OxmModelLoader(), new RestClientBuilder());
+
+ RestClientBuilder clientBuilder = new RestClientBuilder();
+ clientBuilder.setUseHttps(false);
+
+ RestfulDataAccessor nonCachingRestProvider = new RestfulDataAccessor(clientBuilder);
+ ElasticSearchConfig esConfig = ElasticSearchConfig.getConfig();
+
+ ElasticSearchAdapter esAdapter = new ElasticSearchAdapter(nonCachingRestProvider, esConfig);
+
+ SyncController syncController = new SyncControllerImpl("suggestionEntityTestController");
+
+ AutosuggestionSynchronizer ses =
+ new AutosuggestionSynchronizer("entityautosuggestindex-localhost");
+ ses.setAaiDataProvider(aaiAdapter);
+ ses.setEsDataProvider(esAdapter);
+ syncController.registerEntitySynchronizer(ses);
+
+ syncController.performAction(SyncActions.SYNCHRONIZE);
+
+ while (syncController.getState() == SynchronizerState.PERFORMING_SYNCHRONIZATION) {
+ Thread.sleep(1000);
+ }
+
+ syncController.shutdown();
+
+ } catch (Exception exc) {
+ exc.printStackTrace();
+ System.out.println("Error: failed to sync with message = " + exc.getMessage());
+ }
+ }
+
+ /*
+ * Do no op sync.
+ *//*
+ public void doNoOpSync() {
+ try {
+ SyncController syncController = new SyncControllerImpl("noopSyncTestController");
+
+ /*
+ * ActiveInventoryAdapter aaiAdapter = new ActiveInventoryAdapter(new RestClientBuilder());
+ *
+ * aaiAdapter.setCacheEnabled(true);
+ *
+ * /*InMemoryEntityCache aaiInMemoryCache = new InMemoryEntityCache();
+ * aaiAdapter.setEntityCache(aaiInMemoryCache);
+ */
+
+ /*
+ * PersistentEntityCache aaiDiskCache = new PersistentEntityCache();
+ * aaiAdapter.setEntityCache(aaiDiskCache);
+ *
+ * ElasticSearchConfig config = ElasticSearchConfig.getConfig(); OXMModelLoader loader =
+ * OXMModelLoader.getInstance(); SyncAdapter syncAdapter = new SyncAdapter(new
+ * RestClientBuilder(), config, loader);
+ *
+ * //////
+ *
+ * SearchableEntitySynchronizer ses = new SearchableEntitySynchronizer();
+ * ses.setAaiDataProvider(aaiAdapter); ses.setEsDataProvider(syncAdapter);
+ * syncController.registerEntitySynchronizer(ses);
+ *
+ * ////
+ *
+ * IndexIntegrityValidator entitySearchIndexValidator = new IndexIntegrityValidator(new
+ * RestClientBuilder());
+ *
+ * entitySearchIndexValidator.setIndexName("esi-sync2-localhost");
+ * entitySearchIndexValidator.setIndexType("default");
+ * entitySearchIndexValidator.setIndexSettings("");
+ * entitySearchIndexValidator.setIndexSettings("");
+ *
+ * syncController.registerIndexValidator(entitySearchIndexValidator);
+ *
+ * ////
+ *
+ * ElasticSearchEntityPurger p1 = new ElasticSearchEntityPurger(new RestClientBuilder());
+ * p1.setIndexName("esi-blal-blah");
+ *
+ * ElasticSearchEntityPurger p2 = new ElasticSearchEntityPurger(new RestClientBuilder());
+ * p2.setIndexName("esi-topo-blah");
+ */
+ ///
+/*
+ syncController.performAction(SyncActions.SYNCHRONIZE);
+
+ while (syncController.getState() == SynchronizerState.PERFORMING_SYNCHRONIZATION) {
+ Thread.sleep(1000);
+ }
+
+ syncController.shutdown();
+
+ } catch (Exception exc) {
+ System.out.println("Error: failed to sync with message = " + exc.getMessage());
+ }
+ }
+
+
+ /**
+ * The main method.
+ *
+ * @param args the arguments
+ *//*
+ public static void main(String[] args) {
+ //boolean runSearchableEntitySync = false;
+ //boolean runGeoEntitySync = true;
+
+ //System.setProperty("AJSC_HOME", "e:\\dev");
+ // System.getProperties().setProperty("AJSC_HOME",
+ // "c:\\rpo\\tier-support-ui\\target\\swm\\package\\nix\\"
+ // + "dist_files\\opt\\app\\ajsc-tier-support-ui");
+
+ System.setProperty("CONFIG_HOME", "appconfig-local");
+ System.setProperty("AJSC_HOME", "x:\\1710_extensibility\\");
+
+ SyncControllerBuilder syncBuilder = new SyncControllerBuilder();
+
+ /*
+ * if (runSearchableEntitySync) syncBuilder.doSearchableEntitysync();
+ */
+/*
+ syncBuilder.doSearchableEntitysync();
+ // syncBuilder.doCrossEntityReferenceSync();
+ // syncBuilder.doHistoricalEntitySync();
+ // syncBuilder.doGeoEntitySync();
+ //syncBuilder.doSuggestionEntitySync();
+ //syncBuilder.doMasterEntitySync();
+
+ // syncBuilder.testElasticSearchUpdateAPI();
+
+ /*
+ * if (runGeoEntitySync) { syncBuilder.doGeoEntitySync(); }
+ */
+
+
+
+ //}
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/synchronizer/SyncControllerServiceTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/synchronizer/SyncControllerServiceTest.java
new file mode 100644
index 0000000..d4d62ba
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/synchronizer/SyncControllerServiceTest.java
@@ -0,0 +1,34 @@
+package org.onap.aai.sparky.synchronizer;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.onap.aai.sparky.sync.SyncControllerRegistry;
+import org.onap.aai.sparky.sync.SyncControllerService;
+
+public class SyncControllerServiceTest {
+
+ private TestSyncController alpha;
+ private SyncControllerService syncService;
+ private SyncControllerRegistry syncControllerRegistry;
+
+ @Before
+ public void init() {
+ alpha = new TestSyncController("alpha");
+ syncControllerRegistry = new SyncControllerRegistry();
+ syncService = new SyncControllerService(syncControllerRegistry, 5,5);
+
+ }
+
+ @Test
+ public void validateControllerRegistration() {
+
+ syncControllerRegistry.registerSyncController( alpha );
+
+ syncService.startSync();
+
+ syncService.shutdown();
+
+ }
+
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/synchronizer/TestSyncController.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/synchronizer/TestSyncController.java
new file mode 100644
index 0000000..c61f78b
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/synchronizer/TestSyncController.java
@@ -0,0 +1,177 @@
+package org.onap.aai.sparky.synchronizer;
+
+import java.util.Calendar;
+import java.util.Date;
+import java.util.concurrent.Semaphore;
+
+import org.onap.aai.sparky.sync.IndexCleaner;
+import org.onap.aai.sparky.sync.IndexSynchronizer;
+import org.onap.aai.sparky.sync.IndexValidator;
+import org.onap.aai.sparky.sync.SyncController;
+import org.onap.aai.sparky.sync.SyncControllerImpl.SyncActions;
+import org.onap.aai.sparky.sync.enumeration.OperationState;
+import org.onap.aai.sparky.sync.enumeration.SynchronizerState;
+
+public class TestSyncController implements SyncController {
+
+ private String controllerName;
+ private boolean periodic;
+ private SynchronizerState internalState;
+ private Semaphore gate;
+
+ public TestSyncController(String name) {
+ this.controllerName = name;
+ this.internalState = SynchronizerState.IDLE;
+ this.gate = new Semaphore(1);
+ }
+
+
+ @Override
+ public String getControllerName() {
+ return this.controllerName;
+ }
+
+ @Override
+ public OperationState performAction(SyncActions requestedAction) {
+
+ if (gate.tryAcquire()) {
+
+ internalState = SynchronizerState.PERFORMING_SYNCHRONIZATION;
+
+ // System.out.println("performaAction = " + requestedAction);
+
+ System.out.println("Sync started with thread = " + Thread.currentThread().getName()
+ + " at date = " + new Date(Calendar.getInstance().getTimeInMillis()));
+
+ try {
+ Thread.sleep(10000L);
+ } catch (InterruptedException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+
+ System.out.println("Sync done with thread = " + Thread.currentThread().getName()
+ + " at date = " + new Date(Calendar.getInstance().getTimeInMillis()));
+ internalState = SynchronizerState.IDLE;
+
+ System.out.println("Next Sync at = " + Thread.currentThread().getName()
+ + " at date = " + new Date(Calendar.getInstance().getTimeInMillis() + 30000L));
+
+
+ gate.release();
+
+ return OperationState.OK;
+ } else {
+ return OperationState.IGNORED_SYNC_NOT_IDLE;
+ }
+ }
+
+ @Override
+ public void registerEntitySynchronizer(IndexSynchronizer entitySynchronizer) {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void registerIndexValidator(IndexValidator indexValidator) {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void registerIndexCleaner(IndexCleaner indexCleaner) {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void shutdown() {
+ // TODO Auto-generated method stub
+ // System.out.println("shutdown");
+ }
+
+ @Override
+ public SynchronizerState getState() {
+ // System.out.println("getState()");
+ return SynchronizerState.IDLE;
+ }
+
+ @Override
+ public long getDelayInMs() {
+ // TODO Auto-generated method stub
+ return 1000L;
+ }
+
+ @Override
+ public void setDelayInMs(long delayInMs) {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public long getSyncFrequencyInMs() {
+ // TODO Auto-generated method stub
+ return 30000L;
+ }
+
+ @Override
+ public void setSyncFrequencyInMs(long syncFrequencyInMs) {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public Date getSyncStartTime() {
+// System.out.println("getSyncStateTime()");
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public void setSyncStartTime(Date syncStartTime) {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public Date getLastExecutionDate() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public void setLastExecutionDate(Date lastExecutionDate) {
+ // TODO Auto-generated method stub
+
+ }
+
+
+ @Override
+ public Calendar getCreationTime() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public String getNextSyncTime() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+
+ @Override
+ public boolean isPeriodicSyncEnabled() {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+
+ @Override
+ public boolean isRunOnceSyncEnabled() {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/synchronizer/entity/AggregationSuggestionEntityTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/synchronizer/entity/AggregationSuggestionEntityTest.java
new file mode 100644
index 0000000..ba3f38f
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/synchronizer/entity/AggregationSuggestionEntityTest.java
@@ -0,0 +1,75 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+
+package org.onap.aai.sparky.synchronizer.entity;
+
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Scanner;
+
+import org.junit.Test;
+import org.onap.aai.sparky.search.filters.config.FiltersConfig;
+import org.onap.aai.sparky.sync.entity.AggregationSuggestionEntity;
+
+public class AggregationSuggestionEntityTest {
+ public String getResourceFileContents(String filePath) {
+ StringBuilder result = new StringBuilder("");
+
+ ClassLoader classLoader = getClass().getClassLoader();
+ File file = new File(classLoader.getResource(filePath).getFile());
+
+ try (Scanner scanner = new Scanner(file)) {
+ while (scanner.hasNextLine()) {
+ String line = scanner.nextLine();
+ result.append(line).append("\n");
+ }
+ scanner.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ return result.toString();
+ }
+
+ @Test
+ public void testGetIndexDocumentJson() {
+ FiltersConfig filtersConfig = new FiltersConfig();
+ AggregationSuggestionEntity aggregationSuggestionEntity = new AggregationSuggestionEntity(filtersConfig);
+
+ List<String> filterIds = new ArrayList<>(Arrays.asList("1", "2", "7", "8"));
+ aggregationSuggestionEntity.setFilterIds(filterIds);
+
+ String expectedFilterListPayload = getResourceFileContents(
+ "filters/AggregationSuggestionEntity_getIndexDocumentJson_expected.json");
+
+ assertTrue(
+ aggregationSuggestionEntity.getAsJson().contains(expectedFilterListPayload.trim()));
+ }
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/synchronizer/entity/SuggestionSearchEntityTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/synchronizer/entity/SuggestionSearchEntityTest.java
new file mode 100644
index 0000000..0f145f5
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/synchronizer/entity/SuggestionSearchEntityTest.java
@@ -0,0 +1,187 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+
+package org.onap.aai.sparky.synchronizer.entity;
+
+import java.io.IOException;
+import java.util.ArrayList;
+
+import org.junit.BeforeClass;
+import org.onap.aai.sparky.search.filters.config.FiltersConfig;
+import org.onap.aai.sparky.sync.entity.SuggestionSearchEntity;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+public class SuggestionSearchEntityTest {
+ private SuggestionSearchEntity suggestionSearchEntity;
+ ObjectMapper mapper = new ObjectMapper();
+ private static FiltersConfig config = null;
+
+ @BeforeClass
+ public static void init() throws IOException {
+ config = new FiltersConfig();
+ config.setViewsFileName("src/test/resources/filters/aaiui_views.json");
+ config.setFiltersFileName("src/test/resources/filters/aaiui_filters.json");
+ config.setViewsConfig(config.readUiViewsConfig());
+ config.setFiltersConfig(config.readUiFiltersConfig());
+
+ }
+
+ public JsonNode getTestNodeForVnf_withProvAndOrchStatus() throws JsonProcessingException, IOException{
+ String str = "{"
+ + "\"vnf-id\": \"1\","
+ + "\"vnf-name\": \"2\","
+ + "\"vnf-type\": \"3\","
+ + "\"orchestration-status\": \"o1\","
+ + "\"prov-status\": \"p1\""
+ + "}";
+
+ return mapper.readTree(str);
+ }
+
+ public JsonNode getTestNodeForVnf_withOrchStatus() throws JsonProcessingException, IOException{
+ String str = "{"
+ + "\"vnf-id\": \"1\","
+ + "\"vnf-name\": \"2\","
+ + "\"vnf-type\": \"3\","
+ + "\"orchestration-status\": \"o1\""
+ + "}";
+
+ return mapper.readTree(str);
+ }
+
+ public JsonNode getFilterListForOrchestrationStatusOnly(String orcStat) throws JsonProcessingException, IOException{
+ String str = "{\"filterList\":[{\"filterId\":\"2\"},{\"filterId\":\"1\",\"filterValue\":"
+ + orcStat + "}]}";
+ return mapper.readTree(str);
+ }
+
+ public String getStrFilterListForOrchestrationStatusOnly(String orcStat)
+ throws JsonProcessingException, IOException{
+ String str = "{\"filterList\":[{\"filterId\":\"2\"},{\"filterId\":\"1\",\"filterValue\":"
+ + orcStat + "},"
+ + "{\"filterId\":\"7\"},"
+ + "{\"filterId\":\"8\"}"
+ + "]}";
+ return str;
+ }
+
+ public String getStrFilterListForOrcStatAndProvStat(String orcStat, String provStat)
+ throws JsonProcessingException, IOException{
+ String str = "{\"filterList\""
+ + ":[{\"filterId\":\"2\","
+ + "\"filterValue\":" + provStat
+ + "},{\"filterId\":\"1\",\"filterValue\":"
+ + orcStat + "},"
+ + "{\"filterId\":\"7\"},"
+ + "{\"filterId\":\"8\"}"
+ + "]}";
+ return str;
+ }
+
+ public ArrayList<String> getSingleElementOrcStatUniqueList(){
+ ArrayList<String> list = new ArrayList<String>();
+ list.add("orchestration-status");
+ return list;
+ }
+
+ public ArrayList<String> getTwoElementUniqueList(){
+ ArrayList<String> list = new ArrayList<String>();
+ list.add("prov-status");
+ list.add("orchestration-status");
+ return list;
+ }
+
+ // Testing the filters payload (for ES) when only one suggestible attribute is present
+ // Use case: testing a single-element set from the power set of all attributes
+ /*@Test
+ public void test_params_for_suggestions_with_orcStat_o1(){
+ suggestionSearchEntity = new SuggestionSearchEntity(SuggestionEntityLookup.getInstance(), config);
+ suggestionSearchEntity.setEntityType("generic-vnf");
+ JsonNode node = null;
+ try{
+ node = getTestNodeForVnf_withOrchStatus();
+ suggestionSearchEntity.setFilterBasedPayloadFromResponse(node,
+ suggestionSearchEntity.getEntityType(), this.getSingleElementOrcStatUniqueList());
+ JSONObject json = suggestionSearchEntity.getPayload();
+ JSONObject exectedFilterPayload = new JSONObject(
+ this.getStrFilterListForOrchestrationStatusOnly("o1"));
+
+ final JsonNode tree1 = mapper.readTree(json.toString());
+ final JsonNode tree2 = mapper.readTree(exectedFilterPayload.toString());
+
+ assertTrue("Filter list not equal. Found: " + json + ". Expected: " + exectedFilterPayload,
+ tree1.equals(tree2));
+
+ Map<String, String> inputOutput = suggestionSearchEntity.getInputOutputData();
+ Map<String, String> expectedInputOutput = new HashMap<String, String>();
+ expectedInputOutput.put("orchestration-status", "o1");
+ final JsonNode tree3 = mapper.readTree(mapper.writeValueAsString(inputOutput));
+ final JsonNode tree4 = mapper.readTree(mapper.writeValueAsString(expectedInputOutput));
+
+ assertTrue("inputs for suggestions are not equal", tree3.equals(tree4));
+
+ } catch (Exception e){
+ fail("Failed to get test node.");
+ }
+ }*/
+
+ //Testing the filters payload (for ES) when multiple suggestible attributes are present
+ // Use case: testing a 2-element set from the power set of all attributes
+ /*@Test
+ public void test_params_for_suggestions_with_orcStat_o1_provStat_p1(){
+ suggestionSearchEntity = new SuggestionSearchEntity();
+ suggestionSearchEntity.setEntityType("generic-vnf");
+ JsonNode node = null;
+ try{
+ node = getTestNodeForVnf_withProvAndOrchStatus();
+ suggestionSearchEntity.setFilterBasedPayloadFromResponse(node,
+ suggestionSearchEntity.getEntityType(), this.getTwoElementUniqueList());
+ JSONObject json = suggestionSearchEntity.getPayload();
+ JSONObject exectedFilterPayload = new JSONObject(
+ this.getStrFilterListForOrcStatAndProvStat("o1", "p1"));
+
+ final JsonNode tree1 = mapper.readTree(json.toString());
+ final JsonNode tree2 = mapper.readTree(exectedFilterPayload.toString());
+
+ assertTrue("Filter list not equal. Found: " + json + ". Expected: " + exectedFilterPayload,
+ tree1.equals(tree2));
+
+ Map<String, String> inputOutput = suggestionSearchEntity.getInputOutputData();
+ Map<String, String> expectedInputOutput = new HashMap<String, String>();
+ expectedInputOutput.put("orchestration-status", "o1");
+ expectedInputOutput.put("prov-status", "p1");
+ final JsonNode tree3 = mapper.readTree(mapper.writeValueAsString(inputOutput));
+ final JsonNode tree4 = mapper.readTree(mapper.writeValueAsString(expectedInputOutput));
+
+ assertTrue("inputs for suggestions are not equal", tree3.equals(tree4));
+
+ } catch (Exception e){
+ fail("Failed to get node.");
+ }
+ }*/
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/synchronizer/task/PerformActiveInventoryRetrievalTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/synchronizer/task/PerformActiveInventoryRetrievalTest.java
new file mode 100644
index 0000000..60586bd
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/synchronizer/task/PerformActiveInventoryRetrievalTest.java
@@ -0,0 +1,93 @@
+package org.onap.aai.sparky.synchronizer.task;
+
+import org.junit.BeforeClass;
+import org.onap.aai.sparky.sync.task.PerformActiveInventoryRetrieval;
+/*
+ *
+ * TODO-> RestClientBuilder is no longer being use neither is RestAuthenticationMode class
+ * need to be rewritten to use ONAP RestAuthenticationMode
+ */
+/*
+public class PerformActiveInventoryRetrievalTest {
+
+ private PerformActiveInventoryRetrieval sut;
+
+ @BeforeClass
+ public static void initBeforeClass() throws Exception {
+ /* Mock aai.properties values which are used by repairSelfLink(), which is used both to build this
+ * test's expected URI and also used by PerformActiveInventoryRetrieval.get() which is the method under test
+ *
+ ActiveInventoryRestConfig aaiRestConfig = new ActiveInventoryRestConfig(null);
+ ActiveInventoryConfig.getConfig().setAaiRestConfig(aaiRestConfig);
+ ActiveInventoryConfig.getConfig().getAaiRestConfig().setHost("localhost");
+ ActiveInventoryConfig.getConfig().getAaiRestConfig().setPort("8443");
+ ActiveInventoryConfig.getConfig().getAaiRestConfig().setAuthenticationMode(RestAuthenticationMode.SSL_CERT);
+ }
+
+
+/* @Test
+ public void testGet_relativeURI() throws Exception {
+ String uriToProcess = "/my/relative/uri"; // URI to perform test with
+
+ Use uriToProcess + repairSelfLink() method to build the URI that we expect to see:
+ "https://localhost:8443/my/relative/uri"
+ String expectedURI = ActiveInventoryConfig.getConfig().repairSelfLink(uriToProcess);
+
+ // Set up PerformActiveInventoryRetrieval dependencies
+ ActiveInventoryDataProvider aaiProvider = new ActiveInventoryAdapter(new OxmModelLoader(), new RestClientBuilder());
+ NetworkTransaction txn = new NetworkTransaction();
+ txn.setLink(uriToProcess);
+
+ sut = new PerformActiveInventoryRetrieval(txn, aaiProvider);
+ sut.setContextMap(new HashMap<>());
+
+ // Call method under test which should add the missing scheme/host/port to the relative path given in this test
+ sut.get();
+
+ assertEquals(expectedURI, txn.getOperationResult().getRequestLink());
+ }
+
+ @Test
+ public void testGet_relativeURIWithSchemaAndAuthority() throws Exception {
+ String uriToProcess = "https://localhost:8443/my/relative/uri"; // URI to perform test with
+
+ Use uriToProcess + repairSelfLink() method to build the URI that we expect to see:
+ "https://localhost:8443/my/relative/uri"
+ String expectedURI = ActiveInventoryConfig.getConfig().repairSelfLink(uriToProcess);
+
+ // Set up PerformActiveInventoryRetrieval dependencies
+ ActiveInventoryDataProvider aaiProvider = new ActiveInventoryAdapter(new OxmModelLoader(), new RestClientBuilder());
+ NetworkTransaction txn = new NetworkTransaction();
+ txn.setLink(uriToProcess);
+
+ sut = new PerformActiveInventoryRetrieval(txn, aaiProvider);
+ sut.setContextMap(new HashMap<>());
+
+ // Call method under test which shouldn't change the absolute path given in this test
+ sut.get();
+
+ assertEquals(expectedURI, txn.getOperationResult().getRequestLink());
+ }
+
+ @Test
+ public void testGet_emptyURI() throws Exception {
+ String uriToProcess = ""; // URI to perform test with
+
+ Use uriToProcess + repairSelfLink() method to build the URI that we expect to see:
+ "https://localhost:8443"
+ String expectedURI = ActiveInventoryConfig.getConfig().repairSelfLink(uriToProcess);
+
+ // Set up PerformActiveInventoryRetrieval dependencies
+ ActiveInventoryDataProvider aaiProvider = new ActiveInventoryAdapter(new OxmModelLoader(), new RestClientBuilder());
+ NetworkTransaction txn = new NetworkTransaction();
+ txn.setLink(uriToProcess);
+
+ sut = new PerformActiveInventoryRetrieval(txn, aaiProvider);
+ sut.setContextMap(new HashMap<>());
+
+ // Call method under test which should add the missing scheme/host/port to the empty URI given in this test
+ sut.get();
+
+ assertEquals(expectedURI, txn.getOperationResult().getRequestLink());
+ }
+}*/
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/util/CaptureLoggerAppender.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/util/CaptureLoggerAppender.java
new file mode 100644
index 0000000..443328e
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/util/CaptureLoggerAppender.java
@@ -0,0 +1,247 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+
+package org.onap.aai.sparky.util;
+
+import java.util.ArrayList;
+import java.util.Deque;
+import java.util.List;
+import java.util.concurrent.ConcurrentLinkedDeque;
+
+import ch.qos.logback.classic.spi.LoggingEvent;
+import ch.qos.logback.core.Appender;
+import ch.qos.logback.core.Context;
+import ch.qos.logback.core.LogbackException;
+import ch.qos.logback.core.filter.Filter;
+import ch.qos.logback.core.spi.FilterReply;
+import ch.qos.logback.core.status.Status;
+
+/**
+ * A test class used to provide a concrete log stub of the Log4j API interface. The goal is to
+ * transparently capture logging paths so we can add log validation during the junit validation
+ * without post-analyzing on-disk logs.
+ *
+ * @author DAVEA
+ *
+ */
+@SuppressWarnings("rawtypes")
+public class CaptureLoggerAppender implements Appender {
+
+ private Deque<LoggingEvent> capturedLogs;
+
+ /**
+ * Instantiates a new capture logger appender.
+ */
+ public CaptureLoggerAppender() {
+ capturedLogs = new ConcurrentLinkedDeque<LoggingEvent>();
+ }
+
+ /**
+ * Drain all logs.
+ *
+ * @return the list
+ */
+ public List<LoggingEvent> drainAllLogs() {
+ List<LoggingEvent> loggingEvents = new ArrayList<LoggingEvent>();
+
+ LoggingEvent event = null;
+
+ while (capturedLogs.peek() != null) {
+ event = capturedLogs.pop();
+ loggingEvents.add(event);
+ }
+
+ return loggingEvents;
+ }
+
+ /**
+ * Clears the capture logs double-ended queue and returns the size of the queue before it was
+ * cleared.
+ *
+ * @return int numCapturedLogs
+ */
+ public int clearAllLogs() {
+ int numCapturedLogs = capturedLogs.size();
+ capturedLogs.clear();
+ return numCapturedLogs;
+ }
+
+
+
+ /* (non-Javadoc)
+ * @see ch.qos.logback.core.spi.LifeCycle#start()
+ */
+ @Override
+ public void start() {}
+
+ /* (non-Javadoc)
+ * @see ch.qos.logback.core.spi.LifeCycle#stop()
+ */
+ @Override
+ public void stop() {}
+
+ @Override
+ public boolean isStarted() {
+ // TODO Auto-generated method stub
+ System.out.println("isStarted");
+ return false;
+ }
+
+ @Override
+ public void setContext(Context context) {
+ // TODO Auto-generated method stub
+ System.out.println("setContext");
+
+ }
+
+ @Override
+ public Context getContext() {
+ // TODO Auto-generated method stub
+ System.out.println("getContext");
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see ch.qos.logback.core.spi.ContextAware#addStatus(ch.qos.logback.core.status.Status)
+ */
+ @Override
+ public void addStatus(Status status) {
+ // TODO Auto-generated method stub
+ System.out.println("addStatus");
+ }
+
+ /* (non-Javadoc)
+ * @see ch.qos.logback.core.spi.ContextAware#addInfo(java.lang.String)
+ */
+ @Override
+ public void addInfo(String msg) {
+ // TODO Auto-generated method stub
+
+ }
+
+ /* (non-Javadoc)
+ * @see ch.qos.logback.core.spi.ContextAware#addInfo(java.lang.String, java.lang.Throwable)
+ */
+ @Override
+ public void addInfo(String msg, Throwable ex) {
+ // TODO Auto-generated method stub
+
+ }
+
+ /* (non-Javadoc)
+ * @see ch.qos.logback.core.spi.ContextAware#addWarn(java.lang.String)
+ */
+ @Override
+ public void addWarn(String msg) {
+ // TODO Auto-generated method stub
+
+ }
+
+ /* (non-Javadoc)
+ * @see ch.qos.logback.core.spi.ContextAware#addWarn(java.lang.String, java.lang.Throwable)
+ */
+ @Override
+ public void addWarn(String msg, Throwable ex) {
+ // TODO Auto-generated method stub
+
+ }
+
+ /* (non-Javadoc)
+ * @see ch.qos.logback.core.spi.ContextAware#addError(java.lang.String)
+ */
+ @Override
+ public void addError(String msg) {
+ // TODO Auto-generated method stub
+
+ }
+
+ /* (non-Javadoc)
+ * @see ch.qos.logback.core.spi.ContextAware#addError(java.lang.String, java.lang.Throwable)
+ */
+ @Override
+ public void addError(String msg, Throwable ex) {
+ // TODO Auto-generated method stub
+
+ }
+
+ /* (non-Javadoc)
+ * @see ch.qos.logback.core.spi.FilterAttachable#addFilter(ch.qos.logback.core.filter.Filter)
+ */
+ @Override
+ public void addFilter(Filter newFilter) {
+ // TODO Auto-generated method stub
+
+ }
+
+ /* (non-Javadoc)
+ * @see ch.qos.logback.core.spi.FilterAttachable#clearAllFilters()
+ */
+ @Override
+ public void clearAllFilters() {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public List getCopyOfAttachedFiltersList() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see ch.qos.logback.core.spi.FilterAttachable#getFilterChainDecision(java.lang.Object)
+ */
+ @Override
+ public FilterReply getFilterChainDecision(Object event) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public String getName() {
+ // TODO Auto-generated method stub
+ System.out.println("getName");
+ return "MOCK";
+ }
+
+ /* (non-Javadoc)
+ * @see ch.qos.logback.core.Appender#doAppend(java.lang.Object)
+ */
+ @Override
+ public void doAppend(Object event) throws LogbackException {
+ // TODO Auto-generated method stub
+ // System.out.println("doAppend(), event = " + event);
+ // System.out.println("event class = " + event.getClass().getSimpleName());
+ capturedLogs.add((LoggingEvent) event);
+ }
+
+ @Override
+ public void setName(String name) {
+ // TODO Auto-generated method stub
+ System.out.println("setName() name = " + name);
+
+ }
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/util/ExceptionHelper.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/util/ExceptionHelper.java
new file mode 100644
index 0000000..f05aed8
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/util/ExceptionHelper.java
@@ -0,0 +1,62 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+
+package org.onap.aai.sparky.util;
+
+/**
+ * The Class ExceptionHelper.
+ */
+public class ExceptionHelper {
+
+ /**
+ * Extract stack trace elements.
+ *
+ * @param maxNumberOfElementsToCapture the max number of elements to capture
+ * @param exc the exc
+ * @return the string
+ */
+ public static String extractStackTraceElements(int maxNumberOfElementsToCapture, Exception exc) {
+ StringBuilder sb = new StringBuilder(128);
+
+ StackTraceElement[] stackTraceElements = exc.getStackTrace();
+
+ if (stackTraceElements != null) {
+
+ /*
+ * We want to avoid an index out-of-bounds error, so we will make sure to only extract the
+ * number of frames from the stack trace that actually exist.
+ */
+
+ int numFramesToExtract = Math.min(maxNumberOfElementsToCapture, stackTraceElements.length);
+
+ for (int x = 0; x < numFramesToExtract; x++) {
+ sb.append(stackTraceElements[x]).append("\n");
+ }
+
+ }
+
+ return sb.toString();
+ }
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/util/HttpServletHelper.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/util/HttpServletHelper.java
new file mode 100644
index 0000000..081c93e
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/util/HttpServletHelper.java
@@ -0,0 +1,162 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+
+package org.onap.aai.sparky.util;
+
+import static org.junit.Assert.fail;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringReader;
+import java.nio.charset.StandardCharsets;
+import java.util.Collections;
+import java.util.Map;
+
+import javax.servlet.ReadListener;
+import javax.servlet.ServletInputStream;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.mockito.Mockito;
+
+/**
+ * The Class HttpServletHelper.
+ */
+public class HttpServletHelper {
+
+ public static HttpServletRequest getMockHttpServletRequest() {
+ return Mockito.mock(HttpServletRequest.class);
+ }
+
+ /**
+ * Sets the request payload.
+ *
+ * @param request the request
+ * @param mimeType the mime type
+ * @param payloadContent the payload content
+ */
+ public static void setRequestPayload(HttpServletRequest request, String mimeType,
+ String payloadContent) {
+
+ try {
+ Mockito.when(request.getContentType()).thenReturn(mimeType);
+
+
+ final ByteArrayInputStream bais =
+ new ByteArrayInputStream(payloadContent.getBytes(StandardCharsets.UTF_8));
+
+ ServletInputStream servletInputStream = new ServletInputStream() {
+
+ @Override
+ public int read() throws IOException {
+ return bais.read();
+ }
+
+ @Override
+ public boolean isFinished() {
+ return true;
+ }
+
+ @Override
+ public boolean isReady() {
+ return true;
+ }
+
+ @Override
+ public void setReadListener(ReadListener readListener) {
+ // TODO Auto-generated method stub
+
+ }
+ };
+
+ Mockito.when(request.getInputStream()).thenReturn(servletInputStream);
+
+ Mockito.when(request.getReader()).thenReturn(new BufferedReader(new StringReader(payloadContent)));
+
+ } catch (IOException ioe) {
+ fail(ExceptionHelper.extractStackTraceElements(5, ioe));
+ }
+
+ }
+
+ /**
+ * Gets the mock http servlet response.
+ *
+ * @param printWriter the print writer
+ * @return the mock http servlet response
+ */
+ public static HttpServletResponse getMockHttpServletResponse(PrintWriter printWriter) {
+ HttpServletResponse commonResponse = Mockito.mock(HttpServletResponse.class);
+
+ /*
+ * Use the StringWriter wrapped in a PrintWriter to redirect output stream to an in-memory
+ * buffer instead of an on-disk file.
+ */
+
+ try {
+ Mockito.when(commonResponse.getWriter()).thenReturn(printWriter);
+ } catch (IOException ioe) {
+ fail(ExceptionHelper.extractStackTraceElements(5, ioe));
+ }
+
+ return commonResponse;
+ }
+
+ /**
+ * Assign request uri.
+ *
+ * @param req the req
+ * @param requestUri the request uri
+ */
+ public static void assignRequestUri(HttpServletRequest req, String requestUri) {
+ Mockito.when(req.getRequestURI()).thenReturn(requestUri);
+ }
+
+ /**
+ * Assign request parameter name map.
+ *
+ * @param req the req
+ * @param paramNameValueMap the param name value map
+ */
+ public static void assignRequestParameterNameMap(HttpServletRequest req,
+ Map<String, String> paramNameValueMap) {
+ if (paramNameValueMap != null) {
+ Mockito.when(req.getParameterNames())
+ .thenReturn(Collections.enumeration(paramNameValueMap.keySet()));
+
+ for (String key : paramNameValueMap.keySet()) {
+ Mockito.when(req.getParameter(key)).thenReturn(paramNameValueMap.get(key));
+ }
+
+ }
+ }
+
+ public static void assignRequestHeader(HttpServletRequest req, String headerName, String headerValue) {
+ Mockito.when(req.getHeader(headerName)).thenReturn(headerValue);
+ }
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/util/LogValidator.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/util/LogValidator.java
new file mode 100644
index 0000000..a138846
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/util/LogValidator.java
@@ -0,0 +1,85 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+
+package org.onap.aai.sparky.util;
+
+import java.util.List;
+
+import org.slf4j.LoggerFactory;
+
+import ch.qos.logback.classic.Level;
+import ch.qos.logback.classic.spi.LoggingEvent;
+
+/**
+ * The Class LogValidator.
+ */
+public class LogValidator {
+
+ protected CaptureLoggerAppender logger = null;
+
+ /**
+ * Initialize logger.
+ *
+ * @param level the level
+ */
+ @SuppressWarnings("unchecked")
+ public void initializeLogger(Level level) {
+ ch.qos.logback.classic.Logger root = (ch.qos.logback.classic.Logger) LoggerFactory
+ .getLogger(ch.qos.logback.classic.Logger.ROOT_LOGGER_NAME);
+ root.detachAndStopAllAppenders();
+ logger = new CaptureLoggerAppender();
+ root.setLevel(level);
+ root.addAppender(logger);
+ }
+
+ public CaptureLoggerAppender getLogger() {
+ return logger;
+ }
+
+ /**
+ * Dump and count logs.
+ *
+ * @param logToConsole the log to console
+ * @return the int
+ */
+ public int dumpAndCountLogs(boolean logToConsole) {
+
+ List<LoggingEvent> logs = logger.drainAllLogs();
+
+ if (logs == null) {
+ return 0;
+ }
+
+ if (logToConsole) {
+ for (LoggingEvent e : logs) {
+ System.out.println(e);
+ }
+ }
+
+ return logs.size();
+
+ }
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/util/OxmModelAndProcessorHelper.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/util/OxmModelAndProcessorHelper.java
new file mode 100644
index 0000000..cebb494
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/util/OxmModelAndProcessorHelper.java
@@ -0,0 +1,143 @@
+package org.onap.aai.sparky.util;
+
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.onap.aai.sparky.config.SparkyResourceLoader;
+import org.onap.aai.sparky.config.oxm.CrossEntityReferenceLookup;
+import org.onap.aai.sparky.config.oxm.GeoEntityLookup;
+import org.onap.aai.sparky.config.oxm.OxmEntityContainerLookup;
+import org.onap.aai.sparky.config.oxm.OxmEntityLookup;
+import org.onap.aai.sparky.config.oxm.OxmModelLoader;
+import org.onap.aai.sparky.config.oxm.OxmModelProcessor;
+import org.onap.aai.sparky.config.oxm.SearchableEntityLookup;
+import org.onap.aai.sparky.config.oxm.SuggestionEntityLookup;
+import org.onap.aai.sparky.search.filters.config.FiltersConfig;
+import org.springframework.core.io.DefaultResourceLoader;
+
+public class OxmModelAndProcessorHelper {
+
+ public static int API_VERSION_OVERRIDE = -1;
+
+ private OxmModelLoader modelLoader;
+ private Set<OxmModelProcessor> processors;
+
+ private CrossEntityReferenceLookup crossEntityReferenceLookup;
+ private GeoEntityLookup geoEntityLookup;
+ private OxmEntityLookup oxmEntityLookup;
+ private SearchableEntityLookup searchableEntityLookup;
+ private SuggestionEntityLookup suggestionEntityLookup;
+ private OxmEntityContainerLookup oxmEntityContainerLookup;
+ private FiltersConfig filtersConfig;
+
+ private static OxmModelAndProcessorHelper instance = null;
+
+ private OxmModelAndProcessorHelper() throws IOException {
+
+ SparkyResourceLoader resourceLoader = new SparkyResourceLoader();
+ resourceLoader.setResourceLoader(new DefaultResourceLoader());
+
+ this.filtersConfig = new FiltersConfig();
+ this.filtersConfig.initializeFiltersDetailsConfig(resourceLoader.getResourceAsFile(SparkyTestConstants.FILTERS_JSON_FILE, false));
+ this.filtersConfig.initializeFiltersForViewsConfig(resourceLoader.getResourceAsFile(SparkyTestConstants.VIEWS_JSON_FILE, false));
+
+ this.crossEntityReferenceLookup = new CrossEntityReferenceLookup();
+ this.geoEntityLookup = new GeoEntityLookup();
+ this.oxmEntityLookup = new OxmEntityLookup();
+ this.searchableEntityLookup = new SearchableEntityLookup();
+ this.suggestionEntityLookup = new SuggestionEntityLookup(filtersConfig);
+ this.oxmEntityContainerLookup = new OxmEntityContainerLookup();
+
+ this.processors = new HashSet<OxmModelProcessor>();
+ processors.add(crossEntityReferenceLookup);
+ processors.add(geoEntityLookup);
+ processors.add(oxmEntityLookup);
+ processors.add(searchableEntityLookup);
+ processors.add(suggestionEntityLookup);
+ processors.add(oxmEntityContainerLookup);
+
+ this.modelLoader = new OxmModelLoader(API_VERSION_OVERRIDE, processors);
+ modelLoader.loadLatestOxmModel();
+ }
+
+ public static OxmModelAndProcessorHelper getInstance() throws IOException {
+ if (instance == null) {
+ instance = new OxmModelAndProcessorHelper();
+ }
+ return instance;
+ }
+
+ public OxmModelLoader getModelLoader() {
+ return modelLoader;
+ }
+
+ public void setModelLoader(OxmModelLoader modelLoader) {
+ this.modelLoader = modelLoader;
+ }
+
+ public Set<OxmModelProcessor> getProcessors() {
+ return processors;
+ }
+
+ public void setProcessors(Set<OxmModelProcessor> processors) {
+ this.processors = processors;
+ }
+
+ public CrossEntityReferenceLookup getCrossEntityReferenceLookup() {
+ return crossEntityReferenceLookup;
+ }
+
+ public void setCrossEntityReferenceLookup(CrossEntityReferenceLookup crossEntityReferenceLookup) {
+ this.crossEntityReferenceLookup = crossEntityReferenceLookup;
+ }
+
+ public GeoEntityLookup getGeoEntityLookup() {
+ return geoEntityLookup;
+ }
+
+ public void setGeoEntityLookup(GeoEntityLookup geoEntityLookup) {
+ this.geoEntityLookup = geoEntityLookup;
+ }
+
+ public OxmEntityLookup getOxmEntityLookup() {
+ return oxmEntityLookup;
+ }
+
+ public void setOxmEntityLookup(OxmEntityLookup oxmEntityLookup) {
+ this.oxmEntityLookup = oxmEntityLookup;
+ }
+
+ public SearchableEntityLookup getSearchableEntityLookup() {
+ return searchableEntityLookup;
+ }
+
+ public void setSearchableEntityLookup(SearchableEntityLookup searchableEntityLookup) {
+ this.searchableEntityLookup = searchableEntityLookup;
+ }
+
+ public SuggestionEntityLookup getSuggestionEntityLookup() {
+ return suggestionEntityLookup;
+ }
+
+ public void setSuggestionEntityLookup(SuggestionEntityLookup suggestionEntityLookup) {
+ this.suggestionEntityLookup = suggestionEntityLookup;
+ }
+
+ public FiltersConfig getFiltersConfig() {
+ return filtersConfig;
+ }
+
+ public void setFiltersConfig(FiltersConfig filtersConfig) {
+ this.filtersConfig = filtersConfig;
+ }
+
+ public OxmEntityContainerLookup getOxmEntityContainerLookup() {
+ return oxmEntityContainerLookup;
+ }
+
+ public void setOxmEntityContainerLookup(OxmEntityContainerLookup oxmEntityContainerLookup) {
+ this.oxmEntityContainerLookup = oxmEntityContainerLookup;
+ }
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/util/SparkyTestConstants.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/util/SparkyTestConstants.java
new file mode 100644
index 0000000..ffb27fa
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/util/SparkyTestConstants.java
@@ -0,0 +1,19 @@
+package org.onap.aai.sparky.util;
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+public class SparkyTestConstants {
+
+ /** Default to unix file separator if system property file.separator is null */
+ public static final String FILESEP =
+ (System.getProperty("file.separator") == null) ? "/" : System.getProperty("file.separator");
+
+ private static Path currentRelativePath = Paths.get("");
+ public static final String PATH_TO_TEST_RESOURCES = currentRelativePath.toAbsolutePath().toString()
+ + FILESEP + "src" + FILESEP + "test" + FILESEP + "resources";
+
+ public static final String PATH_TO_FILTERS_CONFIG = PATH_TO_TEST_RESOURCES + FILESEP + "filters";
+ public static final String FILTERS_JSON_FILE = PATH_TO_FILTERS_CONFIG + FILESEP + "aaiui_filters.json";
+ public static final String VIEWS_JSON_FILE = PATH_TO_FILTERS_CONFIG + FILESEP + "aaiui_views.json";
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/util/StringCollectionContainsMatcher.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/util/StringCollectionContainsMatcher.java
new file mode 100644
index 0000000..e8b3258
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/util/StringCollectionContainsMatcher.java
@@ -0,0 +1,39 @@
+package org.onap.aai.sparky.util;
+
+import java.util.List;
+
+import org.hamcrest.BaseMatcher;
+import org.hamcrest.Description;
+
+public class StringCollectionContainsMatcher extends BaseMatcher<List<String>> {
+
+ private String valueToCheck;
+
+ @SuppressWarnings({"unused", "unchecked"})
+ public StringCollectionContainsMatcher(String valToCheck) {
+ this.valueToCheck = valToCheck;
+ }
+
+ @Override
+ public boolean matches(Object arg0) {
+
+ @SuppressWarnings("unchecked")
+ List<String> argumentList = (List<String>) arg0;
+
+ for ( String listItem : argumentList ) {
+
+ if ( listItem.contains(valueToCheck)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ @Override
+ public void describeTo(Description arg0) {
+ // TODO Auto-generated method stub
+
+ }
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/util/SuggestionsPermutationTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/util/SuggestionsPermutationTest.java
new file mode 100644
index 0000000..6aa23b7
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/util/SuggestionsPermutationTest.java
@@ -0,0 +1,130 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.util;
+
+import static org.junit.Assert.assertTrue;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+
+import org.junit.Test;
+import org.onap.aai.sparky.util.SuggestionsPermutation;
+
+public class SuggestionsPermutationTest {
+
+ @Test
+ public void testGetUniqueListForSuggestions() {
+ List<String> inputList = new ArrayList<String>();
+ inputList.add("str1");
+ inputList.add("str2");
+ inputList.add("str3");
+
+ List<List<String>> expectedListOfLists = new ArrayList<List<String>>();
+ expectedListOfLists.add((new ArrayList<String>(){{add("str1");}}));
+ expectedListOfLists.add((new ArrayList<String>(){{add("str2");}}));
+ expectedListOfLists.add((new ArrayList<String>(){{add("str3");}}));
+ expectedListOfLists.add((new ArrayList<String>(){{add("str1");add("str2");}}));
+ expectedListOfLists.add((new ArrayList<String>(){{add("str1");add("str3");}}));
+ expectedListOfLists.add((new ArrayList<String>(){{add("str2");add("str3");}}));
+ expectedListOfLists.add((new ArrayList<String>(){{add("str1");add("str2");add("str3");}}));
+
+ int expectedCount = expectedListOfLists.size();
+ int actualCount = 0;
+ ArrayList<ArrayList<String>> actualListOfLists = SuggestionsPermutation.getNonEmptyUniqueLists(inputList);
+
+ for (List<String> list: expectedListOfLists){
+ for (ArrayList<String> actualList: actualListOfLists) {
+ if (new HashSet(list).equals (new HashSet(actualList)) ){
+ actualCount++;
+ }
+ }
+ }
+
+ assertTrue("Missing entries in the unique list of lists for input: " + inputList.toString()
+ + ". Found: "+ actualListOfLists.toString()
+ + " expected: " + expectedListOfLists.toString(), actualCount == expectedCount);
+ }
+
+ @Test
+ public void testGetListPermutations() {
+ List<String> inputList = new ArrayList<String>();
+ inputList.add("str1");
+ inputList.add("str2");
+ inputList.add("str3");
+
+ List<List<String>> expectedPermutations = new ArrayList<List<String>>();
+ expectedPermutations.add((new ArrayList<String>(){{add("str1");add("str2");add("str3");}}));
+ expectedPermutations.add((new ArrayList<String>(){{add("str2");add("str1");add("str3");}}));
+ expectedPermutations.add((new ArrayList<String>(){{add("str2");add("str3");add("str1");}}));
+ expectedPermutations.add((new ArrayList<String>(){{add("str1");add("str3");add("str2");}}));
+ expectedPermutations.add((new ArrayList<String>(){{add("str3");add("str1");add("str2");}}));
+ expectedPermutations.add((new ArrayList<String>(){{add("str3");add("str2");add("str1");}}));
+
+ int expectedCount = expectedPermutations.size();
+ int actualCount = 0;
+ List<List<String>> actualPermutations = SuggestionsPermutation.getListPermutations(inputList);
+
+ for (List<String> list: expectedPermutations){
+ for (List<String> actualList: actualPermutations) {
+ if (list.toString().equals(actualList.toString()) ){
+ actualCount++;
+ }
+ }
+ }
+
+ assertTrue("Missing entries in the permutation of list: "
+ + inputList.toString() + ". Found: "+ actualPermutations.toString()
+ + " expected: " + expectedPermutations.toString(), actualCount == expectedCount);
+ }
+
+ @Test
+ public void isValidSuggestionInputPermutation_verbose_successPath() {
+
+ List<String> x = new ArrayList<>(Arrays.asList("A", "B", "C", "D"));
+
+ ArrayList<ArrayList<String>> uniqueLists = SuggestionsPermutation.getNonEmptyUniqueLists(x);
+
+ assertTrue(uniqueLists.get(0).toString().equals("[A, B, C, D]"));
+ assertTrue(uniqueLists.get(1).toString().equals("[B, C, D]"));
+ assertTrue(uniqueLists.get(2).toString().equals("[A, C, D]"));
+ assertTrue(uniqueLists.get(3).toString().equals("[C, D]"));
+ assertTrue(uniqueLists.get(4).toString().equals("[A, B, D]"));
+ assertTrue(uniqueLists.get(5).toString().equals("[B, D]"));
+ assertTrue(uniqueLists.get(6).toString().equals("[A, D]"));
+ assertTrue(uniqueLists.get(7).toString().equals("[D]"));
+ assertTrue(uniqueLists.get(8).toString().equals("[A, B, C]"));
+ assertTrue(uniqueLists.get(9).toString().equals("[B, C]"));
+ assertTrue(uniqueLists.get(10).toString().equals("[A, C]"));
+ assertTrue(uniqueLists.get(11).toString().equals("[C]"));
+ assertTrue(uniqueLists.get(12).toString().equals("[A, B]"));
+ assertTrue(uniqueLists.get(13).toString().equals("[B]"));
+ assertTrue(uniqueLists.get(14).toString().equals("[A]"));
+ assertTrue(uniqueLists.size() == 15);
+
+ }
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/util/TestResourceLoader.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/util/TestResourceLoader.java
new file mode 100644
index 0000000..7b1b198
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/util/TestResourceLoader.java
@@ -0,0 +1,31 @@
+package org.onap.aai.sparky.util;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.net.URL;
+import java.nio.file.Files;
+
+import com.fasterxml.jackson.core.JsonParseException;
+import com.fasterxml.jackson.databind.JsonMappingException;
+
+public class TestResourceLoader {
+
+ public static String getTestResourceDataJson(String resourcePath)
+ throws JsonParseException, JsonMappingException, IOException {
+
+ // will look for resource using "src/test/resources" as the base folder
+ URL url = TestResourceLoader.class.getResource(resourcePath);
+ File file = new File(url.getFile());
+
+ byte[] payload = Files.readAllBytes(file.toPath());
+
+ if (payload.length == 0) {
+ throw new FileNotFoundException("Could not load '" + resourcePath + "' test data");
+ }
+
+ return new String(payload);
+
+ }
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/util/TreeWalkerTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/util/TreeWalkerTest.java
new file mode 100644
index 0000000..f6947cf
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/util/TreeWalkerTest.java
@@ -0,0 +1,563 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+
+package org.onap.aai.sparky.util;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.onap.aai.sparky.util.NodeUtils;
+import org.onap.aai.sparky.util.TreeWalker;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+/**
+ * The Class TreeWalkerTest.
+ */
+public class TreeWalkerTest {
+
+
+ /**
+ * Inits the.
+ *
+ * @throws Exception the exception
+ */
+ @Before
+ public void init() throws Exception {
+ }
+
+ /**
+ * Validate json node conversion null input.
+ */
+ @Test
+ public void validateJsonNodeConversionNullInput() {
+
+ TreeWalker walker = new TreeWalker();
+
+ try {
+ JsonNode convertedNode = walker.convertJsonToNode(null);
+ assertNull("Converted node should have be null", convertedNode);
+
+ } catch (JsonProcessingException exc) {
+ // expected
+ } catch (IOException exc) {
+ // expeted
+ }
+
+ }
+
+ /**
+ * Validate json node conversion empty non json input.
+ */
+ @Test
+ public void validateJsonNodeConversionEmptyNonJsonInput() {
+
+ TreeWalker walker = new TreeWalker();
+
+ try {
+ JsonNode convertedNode = walker.convertJsonToNode("");
+ assertNull("Converted node should have be null", convertedNode);
+
+ } catch (JsonProcessingException exc) {
+ // expected
+ } catch (IOException exc) {
+ // expeted
+ }
+
+ }
+
+ /**
+ * Validate json node conversion empty json input.
+ */
+ @Test
+ public void validateJsonNodeConversionEmptyJsonInput() {
+
+ TreeWalker walker = new TreeWalker();
+
+ try {
+ JsonNode convertedNode = walker.convertJsonToNode("{}");
+ assertNotNull("Converted node should not be null", convertedNode);
+
+ ObjectMapper objectMapper = new ObjectMapper();
+ String convertedNodeAsStr = objectMapper.writeValueAsString(convertedNode);
+
+ assertEquals("{}", convertedNodeAsStr);
+
+ } catch (JsonProcessingException exc) {
+ // expected
+ } catch (IOException exc) {
+ // expeted
+ }
+
+ }
+
+ /**
+ * Validate walk tree null input.
+ */
+ @Test
+ public void validateWalkTreeNullInput() {
+
+ TreeWalker walker = new TreeWalker();
+
+ List<String> paths = new ArrayList<String>();
+ walker.walkTree(paths, null);
+ assertEquals(0, paths.size());
+
+ }
+
+ /**
+ * Validate walk tree empty node.
+ */
+ @Test
+ public void validateWalkTreeEmptyNode() {
+
+ try {
+ TreeWalker walker = new TreeWalker();
+ List<String> paths = new ArrayList<String>();
+ walker.walkTree(paths, walker.convertJsonToNode("{}"));
+ assertEquals(0, paths.size());
+ } catch (JsonProcessingException exc) {
+ // expected
+ } catch (IOException exc) {
+ // expected
+ }
+
+ }
+
+ /**
+ * Validate walk tree one parent node.
+ */
+ @Test
+ public void validateWalkTreeOneParentNode() {
+
+ try {
+ TreeWalker walker = new TreeWalker();
+ List<String> paths = new ArrayList<String>();
+ walker.walkTree(paths, walker.convertJsonToNode("{ \"root\" : { } }"));
+ assertEquals(1, paths.size());
+ } catch (JsonProcessingException exc) {
+ // expected
+ } catch (IOException exc) {
+ // expected
+ }
+
+ }
+
+ /**
+ * Validate walk tree one parent node with object array.
+ */
+ @Test
+ public void validateWalkTreeOneParentNodeWithObjectArray() {
+
+ try {
+ String jsonStr =
+ "{\"Employee\":[{\"id\":\"101\",\"name\":\"Pushkar\",\"salary\":\"5000\"},"
+ + "{\"id\":\"102\",\"name\":\"Rahul\",\"salary\":\"4000\"},"
+ + "{\"id\":\"103\",\"name\":\"tanveer\",\"salary\":\"56678\"}]}";
+ TreeWalker walker = new TreeWalker();
+ List<String> paths = new ArrayList<String>();
+ walker.walkTree(paths, walker.convertJsonToNode(jsonStr));
+ assertEquals(9, paths.size());
+ } catch (JsonProcessingException exc) {
+ // expected
+ } catch (IOException exc) {
+ // expected
+ }
+
+ }
+
+ /**
+ * Validate walk tree one parent node with value array.
+ */
+ @Test
+ public void validateWalkTreeOneParentNodeWithValueArray() {
+
+ try {
+ String jsonStr = "{ \"colors\" : [ \"yellow\", \"blue\", \"red\" ] }";
+ TreeWalker walker = new TreeWalker();
+ List<String> paths = new ArrayList<String>();
+ walker.walkTree(paths, walker.convertJsonToNode(jsonStr));
+
+ assertEquals(3, paths.size());
+ } catch (JsonProcessingException exc) {
+ // expected
+ } catch (IOException exc) {
+ // expected
+ }
+
+ }
+
+ /**
+ * Test walk for complex entity type aai entity node descriptors.
+ */
+ @Test
+ public void testWalkForComplexEntityType_AaiEntityNodeDescriptors() {
+
+ try {
+ String jsonStr =
+ "{ \"generalNodeClass\": { \"class\": \"aai-entity-node general-node\","
+ + " \"visualElements\": [ { \"type\": \"circle\","
+ + " \"class\": \"outer\", \"svgAttributes\": {"
+ + " \"r\": \"20\" } }, {"
+ + " \"type\": \"circle\", \"class\": \"inner\", "
+ + " \"svgAttributes\": { \"r\": \"10\" "
+ + "} }, { \"type\": \"text\", "
+ + "\"class\": \"id-type-label\", \"displayKey\": \"itemType\", "
+ + " \"shapeAttributes\": { \"offset\": { "
+ + " \"x\": \"0\", \"y\": \"30\" } "
+ + " } }, { \"type\": \"text\", "
+ + " \"class\": \"id-value-label\", \"displayKey\":"
+ + " \"itemNameValue\", \"shapeAttributes\": { "
+ + " \"offset\": { \"x\": \"0\", "
+ + " \"y\": \"40\" } } } ] "
+ + " }, \"searchedNodeClass\": { \"class\": \"aai-entity-node search-node\","
+ + " \"visualElements\": [ { \"type\": \"circle\","
+ + " \"class\": \"outer\", \"svgAttributes\": { "
+ + " \"r\": \"20\" } }, { "
+ + " \"type\": \"circle\", \"class\": \"inner\", "
+ + " \"svgAttributes\": { \"r\": \"10\" }"
+ + " }, { \"type\": \"text\", "
+ + "\"class\": \"id-type-label\", \"displayKey\": \"itemType\", "
+ + " \"shapeAttributes\": { \"offset\": { "
+ + " \"x\": \"0\", \"y\": \"30\" }"
+ + " } }, { \"type\": \"text\", "
+ + " \"class\": \"id-value-label\", "
+ + "\"displayKey\": \"itemNameValue\", \"shapeAttributes\": {"
+ + " \"offset\": { \"x\": \"0\","
+ + " \"y\": \"40\" } }"
+ + " } ] }, \"selectedSearchedNodeClass\": { "
+ + "\"class\": \"aai-entity-node selected-search-node\", \"visualElements\": ["
+ + " { \"type\": \"circle\", "
+ + "\"class\": \"outer\", \"svgAttributes\": {"
+ + " \"r\": \"20\" } }, {"
+ + " \"type\": \"circle\", \"class\": \"inner\","
+ + " \"svgAttributes\": { \"r\": \"10\" "
+ + " } }, { \"type\": \"text\", "
+ + " \"class\": \"id-type-label\", \"displayKey\": \"itemType\","
+ + " \"shapeAttributes\": { \"offset\": {"
+ + " \"x\": \"0\", \"y\": \"30\""
+ + " } } }, { "
+ + " \"type\": \"text\", \"class\": \"id-value-label\", "
+ + " \"displayKey\": \"itemNameValue\", \"shapeAttributes\": {"
+ + " \"offset\": { \"x\": \"0\", "
+ + " \"y\": \"40\" } } } ]"
+ + " }, \"selectedNodeClass\": { \"class\":"
+ + " \"aai-entity-node selected-node\","
+ + " \"visualElements\": [ { \"type\": \"circle\","
+ + " \"class\": \"outer\", \"svgAttributes\": {"
+ + " \"r\": \"20\" } }, {"
+ + " \"type\": \"circle\", \"class\": \"inner\","
+ + " \"svgAttributes\": { \"r\": \"10\" "
+ + " } }, { \"type\": \"text\", "
+ + " \"class\": \"id-type-label\", \"displayKey\": \"itemType\","
+ + " \"shapeAttributes\": { \"offset\": "
+ + "{ "
+ + " \"x\": \"0\", \"y\": \"30\" } "
+ + " } }, { \"type\": \"text\","
+ + " \"class\": \"id-value-label\", \"displayKey\":"
+ + " \"itemNameValue\", \"shapeAttributes\": { "
+ + "\"offset\": { \"x\": \"0\", "
+ + "\"y\": \"40\" } } } ] }}";
+ TreeWalker walker = new TreeWalker();
+ List<String> paths = new ArrayList<String>();
+ walker.walkTree(paths, walker.convertJsonToNode(jsonStr));
+
+ assertEquals(68, paths.size());
+
+ /*
+ * Example of expected value
+ *
+ * generalNodeClass.class=aai-entity-node general-node
+ * generalNodeClass.visualElements.type=circle generalNodeClass.visualElements.class=outer
+ * generalNodeClass.visualElements.svgAttributes.r=20
+ * generalNodeClass.visualElements.type=circle generalNodeClass.visualElements.class=inner
+ * generalNodeClass.visualElements.svgAttributes.r=10
+ * generalNodeClass.visualElements.type=text
+ * generalNodeClass.visualElements.class=id-type-label
+ * generalNodeClass.visualElements.displayKey=itemType
+ * generalNodeClass.visualElements.shapeAttributes.offset.x=0
+ * generalNodeClass.visualElements.shapeAttributes.offset.y=30
+ * generalNodeClass.visualElements.type=text
+ * generalNodeClass.visualElements.class=id-value-label
+ * generalNodeClass.visualElements.displayKey=itemNameValue
+ * generalNodeClass.visualElements.shapeAttributes.offset.x=0
+ * generalNodeClass.visualElements.shapeAttributes.offset.y=40
+ * searchedNodeClass.class=aai-entity-node search-node
+ * searchedNodeClass.visualElements.type=circle searchedNodeClass.visualElements.class=outer
+ * searchedNodeClass.visualElements.svgAttributes.r=20
+ * searchedNodeClass.visualElements.type=circle searchedNodeClass.visualElements.class=inner
+ * searchedNodeClass.visualElements.svgAttributes.r=10
+ * searchedNodeClass.visualElements.type=text
+ * searchedNodeClass.visualElements.class=id-type-label
+ * searchedNodeClass.visualElements.displayKey=itemType
+ * searchedNodeClass.visualElements.shapeAttributes.offset.x=0
+ * searchedNodeClass.visualElements.shapeAttributes.offset.y=30
+ * searchedNodeClass.visualElements.type=text
+ * searchedNodeClass.visualElements.class=id-value-label
+ * searchedNodeClass.visualElements.displayKey=itemNameValue
+ * searchedNodeClass.visualElements.shapeAttributes.offset.x=0
+ * searchedNodeClass.visualElements.shapeAttributes.offset.y=40
+ * selectedSearchedNodeClass.class=aai-entity-node selected-search-node
+ * selectedSearchedNodeClass.visualElements.type=circle
+ * selectedSearchedNodeClass.visualElements.class=outer
+ * selectedSearchedNodeClass.visualElements.svgAttributes.r=20
+ * selectedSearchedNodeClass.visualElements.type=circle
+ * selectedSearchedNodeClass.visualElements.class=inner
+ * selectedSearchedNodeClass.visualElements.svgAttributes.r=10
+ * selectedSearchedNodeClass.visualElements.type=text
+ * selectedSearchedNodeClass.visualElements.class=id-type-label
+ * selectedSearchedNodeClass.visualElements.displayKey=itemType
+ * selectedSearchedNodeClass.visualElements.shapeAttributes.offset.x=0
+ * selectedSearchedNodeClass.visualElements.shapeAttributes.offset.y=30
+ * selectedSearchedNodeClass.visualElements.type=text
+ * selectedSearchedNodeClass.visualElements.class=id-value-label
+ * selectedSearchedNodeClass.visualElements.displayKey=itemNameValue
+ * selectedSearchedNodeClass.visualElements.shapeAttributes.offset.x=0
+ * selectedSearchedNodeClass.visualElements.shapeAttributes.offset.y=40
+ * selectedNodeClass.class=aai-entity-node selected-node
+ * selectedNodeClass.visualElements.type=circle selectedNodeClass.visualElements.class=outer
+ * selectedNodeClass.visualElements.svgAttributes.r=20
+ * selectedNodeClass.visualElements.type=circle selectedNodeClass.visualElements.class=inner
+ * selectedNodeClass.visualElements.svgAttributes.r=10
+ * selectedNodeClass.visualElements.type=text
+ * selectedNodeClass.visualElements.class=id-type-label
+ * selectedNodeClass.visualElements.displayKey=itemType
+ * selectedNodeClass.visualElements.shapeAttributes.offset.x=0
+ * selectedNodeClass.visualElements.shapeAttributes.offset.y=30
+ * selectedNodeClass.visualElements.type=text
+ * selectedNodeClass.visualElements.class=id-value-label
+ * selectedNodeClass.visualElements.displayKey=itemNameValue
+ * selectedNodeClass.visualElements.shapeAttributes.offset.x=0
+ * selectedNodeClass.visualElements.shapeAttributes.offset.y=40
+ */
+
+ } catch (JsonProcessingException exc) {
+ // expected
+ } catch (IOException exc) {
+ // expected
+ }
+
+ }
+
+ /**
+ * Test complex object inversion equality.
+ */
+ @Test
+ public void testComplexObjectInversionEquality() {
+
+ /**
+ * Dave Adams (1-Nov-2016):
+ *
+ * Ok.. I agree...weird title of the test-case. This test is focused on the isEqual equality
+ * test within the NodeUtils helper class which compares the sorted structural paths of two Json
+ * Object representations. I attempted to normalize unordered structures to produce an equality
+ * result, as there doesn't seem to be any natural equality test between two JsonNode objects
+ * that I could find to date.
+ *
+ * Basically, this test is confirming that if the same object values are present in different
+ * orders, they are effectively the same Json Object representation, and pass, at least my
+ * structural value equality test.
+ *
+ * I reordered the aaiEntityNodeDescriptors top level class types, and change the order of the
+ * x,y coordinates to be y,x. Same values different order. Once again, the expectation is that
+ * both representations are objectively equal, they just have different json representations.
+ */
+
+ try {
+ String n1Str =
+ "{ \"generalNodeClass\": { \"class\": \"aai-entity-node general-node\","
+ + " \"visualElements\": [ { \"type\": \"circle\","
+ + " \"class\": \"outer\", \"svgAttributes\": {"
+ + " \"r\": \"20\" } }, {"
+ + " \"type\": \"circle\", \"class\": \"inner\","
+ + " \"svgAttributes\": { \"r\": \"10\""
+ + " } }, { \"type\": \"text\","
+ + " \"class\": \"id-type-label\", \"displayKey\":"
+ + " \"itemType\", \"shapeAttributes\": { \"offset\":"
+ + " { \"x\": \"0\", \"y\": \"30\""
+ + " } } }, {"
+ + " \"type\": \"text\", \"class\": \"id-value-label\","
+ + " \"displayKey\": \"itemNameValue\","
+ + " \"shapeAttributes\": { \"offset\":"
+ + " { \"x\": \"0\", \"y\": \"40\""
+ + " } } } ] },"
+ + " \"searchedNodeClass\": { \"class\": \"aai-entity-node search-node\","
+ + " \"visualElements\": [ { \"type\": \"circle\","
+ + " \"class\": \"outer\", \"svgAttributes\": {"
+ + " \"r\": \"20\" } }, {"
+ + " \"type\": \"circle\", \"class\": \"inner\","
+ + " \"svgAttributes\": { \"r\": \"10\""
+ + " } }, { \"type\": \"text\","
+ + " \"class\": \"id-type-label\", \"displayKey\":"
+ + " \"itemType\", \"shapeAttributes\": { \"offset\": {"
+ + " \"x\": \"0\", \"y\": \"30\""
+ + " } } }, {"
+ + " \"type\": \"text\", \"class\": \"id-value-label\","
+ + " \"displayKey\": \"itemNameValue\","
+ + " \"shapeAttributes\": { \"offset\": {"
+ + " \"x\": \"0\", \"y\": \"40\""
+ + " } } } ] },"
+ + " \"selectedSearchedNodeClass\": { \"class\":"
+ + " \"aai-entity-node selected-search-node\", \"visualElements\": ["
+ + " { \"type\": \"circle\", \"class\":"
+ + " \"outer\", \"svgAttributes\": { \"r\": \"20\""
+ + " } }, { \"type\": \"circle\","
+ + " \"class\": \"inner\", \"svgAttributes\": {"
+ + " \"r\": \"10\" } }, {"
+ + " \"type\": \"text\", \"class\": \"id-type-label\","
+ + " \"displayKey\": \"itemType\", \"shapeAttributes\": {"
+ + " \"offset\": { \"x\": \"0\","
+ + " \"y\": \"30\" } }"
+ + " }, { \"type\": \"text\","
+ + " \"class\": \"id-value-label\","
+ + " \"displayKey\": \"itemNameValue\","
+ + " \"shapeAttributes\": { \"offset\": {"
+ + " \"x\": \"0\", \"y\": \"40\""
+ + " } } } ] },"
+ + " \"selectedNodeClass\": { \"class\": \"aai-entity-node selected-node\","
+ + " \"visualElements\": [ { \"type\": \"circle\","
+ + " \"class\": \"outer\", \"svgAttributes\": {"
+ + " \"r\": \"20\" } }, {"
+ + " \"type\": \"circle\", \"class\": \"inner\","
+ + " \"svgAttributes\": { \"r\": \"10\""
+ + " } }, { \"type\": \"text\","
+ + " \"class\": \"id-type-label\", \"displayKey\":"
+ + " \"itemType\", \"shapeAttributes\": {"
+ + " \"offset\": { \"x\": \"0\","
+ + " \"y\": \"30\" }"
+ + " } }, { \"type\": \"text\","
+ + " \"class\": \"id-value-label\", \"displayKey\":"
+ + " \"itemNameValue\", \"shapeAttributes\": {"
+ + " \"offset\": { \"x\": \"0\","
+ + " \"y\": \"40\" } }"
+ + " } ] }}";
+ String n2Str =
+ "{ \"searchedNodeClass\": { \"class\": \"aai-entity-node search-node\","
+ + " \"visualElements\": [ { \"type\": \"circle\","
+ + " \"class\": \"outer\", \"svgAttributes\": {"
+ + " \"r\": \"20\" } },"
+ + " { \"type\": \"circle\","
+ + " \"class\": \"inner\", \"svgAttributes\": {"
+ + " \"r\": \"10\" } }, {"
+ + " \"type\": \"text\", \"class\": \"id-type-label\","
+ + " \"displayKey\": \"itemType\", \"shapeAttributes\": {"
+ + " \"offset\": { \"y\": \"30\","
+ + " \"x\": \"0\" } }"
+ + " }, { \"type\": \"text\","
+ + " \"class\": \"id-value-label\","
+ + " \"displayKey\": \"itemNameValue\","
+ + " \"shapeAttributes\": { \"offset\": {"
+ + " \"y\": \"40\", \"x\": \"0\""
+ + " } } } ] },"
+ + " \"selectedSearchedNodeClass\": { \"class\":"
+ + " \"aai-entity-node selected-search-node\", \"visualElements\": ["
+ + " { \"type\": \"circle\", \"class\":"
+ + " \"outer\", \"svgAttributes\": { \"r\": \"20\""
+ + " } }, { \"type\": \"circle\","
+ + " \"class\": \"inner\", \"svgAttributes\": {"
+ + " \"r\": \"10\" } }, {"
+ + " \"type\": \"text\", \"class\": \"id-type-label\","
+ + " \"displayKey\": \"itemType\", \"shapeAttributes\": {"
+ + " \"offset\": { \"y\": \"30\","
+ + " \"x\": \"0\" } }"
+ + " }, { \"type\": \"text\","
+ + " \"class\": \"id-value-label\","
+ + " \"displayKey\": \"itemNameValue\","
+ + " \"shapeAttributes\": { \"offset\": {"
+ + " \"y\": \"40\", \"x\": \"0\""
+ + " } } } ] },"
+ + " \"selectedNodeClass\": { \"class\": \"aai-entity-node selected-node\","
+ + " \"visualElements\": [ { \"type\": \"circle\","
+ + " \"class\": \"outer\", \"svgAttributes\": {"
+ + " \"r\": \"20\" } }, {"
+ + " \"type\": \"circle\", \"class\": \"inner\","
+ + " \"svgAttributes\": { \"r\": \"10\""
+ + " } }, { \"type\": \"text\","
+ + " \"class\": \"id-type-label\","
+ + " \"displayKey\": \"itemType\", \"shapeAttributes\": {"
+ + " \"offset\": { \"y\": \"30\","
+ + " \"x\": \"0\" } }"
+ + " }, { \"type\": \"text\","
+ + " \"class\": \"id-value-label\","
+ + " \"displayKey\": \"itemNameValue\","
+ + " \"shapeAttributes\": { \"offset\": {"
+ + " \"y\": \"40\", \"x\": \"0\""
+ + " } } } ] },"
+ + " \"generalNodeClass\": { \"class\":"
+ + " \"aai-entity-node general-node\", \"visualElements\": ["
+ + " { \"type\": \"circle\","
+ + " \"class\": \"outer\", \"svgAttributes\": {"
+ + " \"r\": \"20\" } },"
+ + " { \"type\": \"circle\","
+ + " \"class\": \"inner\", \"svgAttributes\": {"
+ + " \"r\": \"10\" } },"
+ + " { \"type\": \"text\","
+ + " \"class\": \"id-type-label\", \"displayKey\":"
+ + " \"itemType\", \"shapeAttributes\": {"
+ + " \"offset\": { \"y\": \"30\","
+ + " \"x\": \"0\" }"
+ + " } }, {"
+ + " \"type\": \"text\","
+ + " \"class\": \"id-value-label\", \"displayKey\":"
+ + " \"itemNameValue\", \"shapeAttributes\": {"
+ + " \"offset\": { \"y\": \"40\","
+ + " \"x\": \"0\" }"
+ + " } } ] }}";
+
+ TreeWalker walker = new TreeWalker();
+ List<String> n1Paths = new ArrayList<String>();
+ List<String> n2Paths = new ArrayList<String>();
+
+ JsonNode n1 = walker.convertJsonToNode(n1Str);
+ JsonNode n2 = walker.convertJsonToNode(n2Str);
+ walker.walkTree(n1Paths, n1);
+ walker.walkTree(n2Paths, n2);
+
+ assertEquals(68, n1Paths.size());
+ assertEquals(68, n2Paths.size());
+
+ assertTrue(NodeUtils.isEqual(n1, n2));
+
+ } catch (JsonProcessingException exc) {
+ // expected
+ } catch (IOException exc) {
+ // expected
+ }
+
+ }
+
+
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/BaseVisualizationContextTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/BaseVisualizationContextTest.java
new file mode 100644
index 0000000..5c027da
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/BaseVisualizationContextTest.java
@@ -0,0 +1,5 @@
+package org.onap.aai.sparky.viewandinspect;
+
+public class BaseVisualizationContextTest {
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/BaseVisualizationServiceTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/BaseVisualizationServiceTest.java
new file mode 100644
index 0000000..e51c629
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/BaseVisualizationServiceTest.java
@@ -0,0 +1,75 @@
+package org.onap.aai.sparky.viewandinspect;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.onap.aai.sparky.config.oxm.OxmEntityLookup;
+import org.onap.aai.sparky.config.oxm.OxmModelLoader;
+import org.onap.aai.sparky.dal.ActiveInventoryAdapter;
+import org.onap.aai.sparky.dal.ElasticSearchAdapter;
+import org.onap.aai.sparky.dal.GizmoAdapter;
+import org.onap.aai.sparky.subscription.config.SubscriptionConfig;
+import org.onap.aai.sparky.sync.config.ElasticSearchEndpointConfig;
+import org.onap.aai.sparky.sync.config.ElasticSearchSchemaConfig;
+import org.onap.aai.sparky.util.OxmModelAndProcessorHelper;
+import org.onap.aai.sparky.viewandinspect.config.VisualizationConfigs;
+import org.onap.aai.sparky.viewandinspect.entity.QueryRequest;
+import org.onap.aai.sparky.viewandinspect.services.BaseVisualizationService;
+import org.onap.aai.sparky.viewandinspect.util.SchemaVisualizationTestDataBuilder;
+
+public class BaseVisualizationServiceTest {
+ private ActiveInventoryAdapter mockAaiAdapter;
+ private ElasticSearchAdapter mockEsAdapter;
+ private VisualizationConfigs visualizationConfigs;
+ private SubscriptionConfig subConfig;
+ private ElasticSearchEndpointConfig endpointEConfig;
+ private ElasticSearchSchemaConfig schemaEConfig;
+ private OxmEntityLookup oxmEntityLookup;
+ private GizmoAdapter mockGizmoAdapter;
+
+ private BaseVisualizationService baseVisService;
+
+ @Before
+ public void init() throws Exception {
+ this.mockAaiAdapter = Mockito.mock(ActiveInventoryAdapter.class);
+ this.mockAaiAdapter = Mockito.mock(ActiveInventoryAdapter.class);
+ this.mockEsAdapter = Mockito.mock(ElasticSearchAdapter.class);
+ this.mockGizmoAdapter = Mockito.mock(GizmoAdapter.class);
+ this.visualizationConfigs = new VisualizationConfigs();
+ this.subConfig = new SubscriptionConfig();
+ this.endpointEConfig = new ElasticSearchEndpointConfig();
+ this.schemaEConfig = new ElasticSearchSchemaConfig();
+ this.oxmEntityLookup = OxmModelAndProcessorHelper.getInstance().getOxmEntityLookup();
+
+ OxmModelLoader modelLoader = OxmModelAndProcessorHelper.getInstance().getModelLoader();
+
+ this.baseVisService = new BaseVisualizationService(modelLoader, visualizationConfigs,
+ mockAaiAdapter, mockGizmoAdapter, mockEsAdapter, endpointEConfig, schemaEConfig, 1,
+ oxmEntityLookup, subConfig);
+ }
+
+ @Test
+ public void testAnalyzeQueryRequestBody() {
+ QueryRequest validResquest = baseVisService.analyzeQueryRequestBody(SchemaVisualizationTestDataBuilder.getQueryRequest());
+ assertEquals(SchemaVisualizationTestDataBuilder.ROOT_NODE_HASH_ID, validResquest.getHashId());
+
+ QueryRequest nullRequest = baseVisService.analyzeQueryRequestBody("This String should make the request return null eh!");
+ assertEquals(null, nullRequest);
+ }
+
+ @Test
+ public void testBuildVisualizationUsingGenericQuery() {
+
+ initializeMocksForBuildVisualizationUsingGenericQueryTest();
+
+ QueryRequest rootNodeQuery = baseVisService.analyzeQueryRequestBody(SchemaVisualizationTestDataBuilder.getQueryRequest());
+
+ }
+
+ private void initializeMocksForBuildVisualizationUsingGenericQueryTest() {
+ Mockito.when(mockAaiAdapter.queryActiveInventoryWithRetries(Mockito.anyString(), Mockito.anyString(), Mockito.anyInt())).thenReturn(null);
+ }
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/SchemaVisualizationProcessorTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/SchemaVisualizationProcessorTest.java
new file mode 100644
index 0000000..83e3ee0
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/SchemaVisualizationProcessorTest.java
@@ -0,0 +1,78 @@
+package org.onap.aai.sparky.viewandinspect;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.IOException;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.Exchange;
+import org.apache.camel.Message;
+import org.apache.camel.impl.DefaultCamelContext;
+import org.apache.camel.impl.DefaultExchange;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.onap.aai.sparky.util.HttpServletHelper;
+import org.onap.aai.sparky.viewandinspect.entity.QueryRequest;
+import org.onap.aai.sparky.viewandinspect.services.VisualizationService;
+import org.onap.aai.sparky.viewandinspect.util.SchemaVisualizationTestDataBuilder;
+
+import com.fasterxml.jackson.annotation.JsonInclude.Include;
+import com.fasterxml.jackson.core.JsonParseException;
+import com.fasterxml.jackson.databind.JsonMappingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+public class SchemaVisualizationProcessorTest {
+
+ SchemaVisualizationProcessor schemaVisProcessor;
+ VisualizationService mockVisualizationService;
+
+ private Exchange exchange;
+ private CamelContext camelContext;
+ private Message mockRequestMessage;
+
+ @Before
+ public void init() throws Exception {
+ schemaVisProcessor = new SchemaVisualizationProcessor();
+
+ mockVisualizationService = Mockito.mock(VisualizationService.class);
+
+ camelContext = new DefaultCamelContext();
+ exchange = new DefaultExchange(camelContext);
+
+ mockRequestMessage = Mockito.mock(Message.class);
+
+ exchange.setIn(mockRequestMessage);
+
+ }
+
+ @Test
+ public void testProcessVisualizationRequest() throws JsonParseException, JsonMappingException, IOException {
+
+ String queryRequest = SchemaVisualizationTestDataBuilder.getQueryRequest();
+ HttpServletRequest request = Mockito.mock(HttpServletRequest.class);
+ HttpServletHelper.setRequestPayload(request, "application/json", queryRequest);
+
+ Mockito.when(request.getRequestURI()).thenReturn("fakeUri");
+ Mockito.when(request.getLocalPort()).thenReturn(8001);
+ Mockito.when(mockRequestMessage.getBody(Mockito.eq(HttpServletRequest.class))).thenReturn(request);
+ Mockito.when(mockRequestMessage.getBody(Mockito.eq(String.class))).thenReturn(queryRequest);
+
+ ObjectMapper nonEmptyMapper = new ObjectMapper();
+ nonEmptyMapper.setSerializationInclusion(Include.NON_EMPTY);
+ QueryRequest queryBody = nonEmptyMapper.readValue(queryRequest, QueryRequest.class);
+
+ Mockito.when(mockVisualizationService.analyzeQueryRequestBody(Mockito.anyString())).thenReturn(queryBody);
+ Mockito.when(mockVisualizationService.buildVisualizationUsingGenericQuery(Mockito.anyObject())).thenReturn(SchemaVisualizationTestDataBuilder.getSchemaVisResult());
+
+ schemaVisProcessor.setVisualizationService(mockVisualizationService);
+ schemaVisProcessor.processVisualizationRequest(exchange);
+
+ assertEquals("{}", exchange.getOut().getBody(String.class));
+ assertEquals(200, exchange.getOut().getHeader(Exchange.HTTP_RESPONSE_CODE));
+
+ }
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/SearchAdapterTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/SearchAdapterTest.java
new file mode 100644
index 0000000..5ddf07e
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/SearchAdapterTest.java
@@ -0,0 +1,87 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+
+package org.onap.aai.sparky.viewandinspect;
+/*
+import static org.mockito.Matchers.anyObject;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.same;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+
+import org.junit.Before;
+import org.onap.aai.sparky.dal.rest.RestClientBuilder;
+
+import com.sun.jersey.api.client.Client;
+import com.sun.jersey.api.client.ClientResponse;
+import com.sun.jersey.api.client.WebResource;
+import com.sun.jersey.api.client.WebResource.Builder;
+
+
+/**
+ * The Class SearchAdapterTest.
+ *
+ *
+ *TODO -> rewrite the test as it no longer uses RestClientBuilder
+public class SearchAdapterTest {
+
+ private RestClientBuilder clientBuilderMock;
+ private Client mockClient;
+ private ClientResponse mockClientResponse;
+ private WebResource mockWebResource;
+ private Builder mockBuilder;
+
+
+
+ /**
+ * Inits the.
+ *
+ * @throws Exception the exception
+ *
+ @Before
+ public void init() throws Exception {
+
+ /*
+ * common collaborator mocking setup
+ *
+
+ clientBuilderMock = mock(RestClientBuilder.class);
+ mockClient = mock(Client.class);
+ mockClientResponse = mock(ClientResponse.class);
+ mockWebResource = mock(WebResource.class);
+ mockBuilder = mock(Builder.class);
+
+ doReturn(mockClient).when(clientBuilderMock).getClient();
+ doReturn(mockWebResource).when(mockClient).resource(anyString());
+ doReturn(mockBuilder).when(mockWebResource).accept(anyString());
+ doReturn(mockBuilder).when(mockBuilder).header(anyString(), anyObject());
+
+ doReturn(mockClientResponse).when(mockBuilder).get(same(ClientResponse.class));
+ doReturn(mockClientResponse).when(mockBuilder).put(same(ClientResponse.class), anyObject());
+ doReturn(mockClientResponse).when(mockBuilder).post(same(ClientResponse.class), anyObject());
+ doReturn(mockClientResponse).when(mockBuilder).delete(same(ClientResponse.class));
+ }
+
+}*/ \ No newline at end of file
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/SearchResponseTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/SearchResponseTest.java
new file mode 100644
index 0000000..7975c13
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/SearchResponseTest.java
@@ -0,0 +1,92 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+
+package org.onap.aai.sparky.viewandinspect;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.onap.aai.sparky.search.SearchResponse;
+import org.onap.aai.sparky.viewandinspect.entity.EntityEntry;
+
+/**
+ * The Class SearchResponseTest.
+ */
+@RunWith(MockitoJUnitRunner.class)
+public class SearchResponseTest {
+
+ /**
+ * Inits the.
+ *
+ * @throws Exception the exception
+ */
+ @Before
+ public void init() throws Exception {}
+
+ /**
+ * Validate basic construction.
+ */
+ @Test
+ public void validateBasicConstruction() {
+
+ SearchResponse response = new SearchResponse();
+
+ //response.setNumReturned(1);
+ response.setProcessingTimeInMs(512);
+ //response.setTotalFound(50);
+
+ List<EntityEntry> entities = new ArrayList<EntityEntry>();
+ //response.setEntities(entities);
+
+ EntityEntry e1 = new EntityEntry();
+ e1.setEntityPrimaryKeyValue("e1");
+ e1.setEntityType("e1");
+ e1.setSearchTags("e1");
+
+ //response.addEntityEntry(e1);
+
+ EntityEntry e2 = new EntityEntry();
+
+ e2.setEntityPrimaryKeyValue("e2");
+ e2.setEntityType("e2");
+ e2.setSearchTags("e2");
+
+ //response.addEntityEntry(e2);
+
+ //assertEquals(1, response.getNumReturned());
+ //assertEquals(512, response.getProcessingTimeInMs());
+ //assertEquals(50, response.getTotalFound());
+
+ //List<EntityEntry> responseEntities = response.getEntities();
+
+ //assertEquals(2, responseEntities.size());
+
+ }
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/SearchServletTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/SearchServletTest.java
new file mode 100644
index 0000000..69c408c
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/SearchServletTest.java
@@ -0,0 +1,992 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+
+package org.onap.aai.sparky.viewandinspect;
+
+/*
+import org.openecomp.sparky.config.oxm.OxmEntityDescriptor;
+import org.openecomp.sparky.config.oxm.OxmModelLoader;
+import org.openecomp.sparky.dal.elasticsearch.SearchAdapter;
+import org.openecomp.sparky.dal.elasticsearch.entity.AutoSuggestDocumentEntity;
+import org.openecomp.sparky.dal.elasticsearch.entity.AutoSuggestDocumentEntityFields;
+import org.openecomp.sparky.dal.elasticsearch.entity.AutoSuggestElasticHitEntity;
+import org.openecomp.sparky.dal.elasticsearch.entity.AutoSuggestElasticHitsEntity;
+import org.openecomp.sparky.dal.elasticsearch.entity.AutoSuggestElasticSearchResponse;
+import org.openecomp.sparky.dal.elasticsearch.entity.BucketEntity;
+import org.openecomp.sparky.dal.elasticsearch.entity.ElasticHitsEntity;
+import org.openecomp.sparky.dal.elasticsearch.entity.ElasticSearchAggegrationResponse;
+import org.openecomp.sparky.dal.elasticsearch.entity.ElasticSearchAggregation;
+import org.openecomp.sparky.dal.elasticsearch.entity.ElasticSearchCountResponse;
+import org.openecomp.sparky.dal.elasticsearch.entity.PayloadEntity;
+import org.openecomp.sparky.dal.rest.OperationResult;
+import org.openecomp.sparky.dal.sas.config.SearchServiceConfig;
+import org.openecomp.sparky.dal.sas.entity.EntityCountResponse;
+import org.openecomp.sparky.dal.sas.entity.GroupByAggregationResponseEntity;
+import org.openecomp.sparky.dal.sas.entity.SearchAbstractionEntityBuilder;
+import org.openecomp.sparky.search.VnfSearchService;
+import org.openecomp.sparky.search.config.SuggestionConfig;
+import org.openecomp.sparky.search.filters.FilteredSearchHelper;
+import org.openecomp.sparky.search.filters.entity.UiFilterEntity;
+import org.openecomp.sparky.search.filters.entity.UiFilterValueEntity;
+import org.openecomp.sparky.search.filters.entity.UiFiltersEntity;
+import org.openecomp.sparky.suggestivesearch.SuggestionEntity;
+import org.openecomp.sparky.util.ExceptionHelper;
+import org.openecomp.sparky.util.HttpServletHelper;
+import org.openecomp.sparky.util.NodeUtils;
+import org.openecomp.sparky.viewandinspect.entity.QuerySearchEntity;
+import org.openecomp.sparky.viewandinspect.entity.SearchResponse;
+import org.slf4j.MDC;
+
+import org.onap.aai.cl.mdc.MdcContext;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.google.common.net.MediaType;
+
+
+/**
+ * The Class SearchServletTest.
+ */
+
+/*public class SearchServletTest {
+
+ private static final String VNF_ROUTE = "vnf";
+ private static final String VIEW_INSPECT_ROUTE = "viewInspect";
+
+ private HttpServletRequest commonRequest = null;
+ private HttpServletResponse commonResponse = null;
+ private PrintWriter printWriter = null;
+ private StringWriter responseStringWriter = null;
+ private SearchServiceWrapper searchWrapper = null;
+ private SearchAdapter searchAdapter = null;
+ private VnfSearchService vnfSearchService = null;
+ private ObjectMapper mapper = null;
+ private SecureRandom rand = null;
+ private OxmModelLoader loader;
+ private Map<String, OxmEntityDescriptor> descriptors = null;
+ private SuggestionConfig suggestionConfig = null;
+ private SearchServiceConfig esConfig = null;
+
+ @BeforeClass
+ public static void initBeforeClass() throws IOException {
+ if (null == System.getProperty("CONFIG_HOME")) {
+ /* Set "CONFIG_HOME" environment variable so path of filter & view schema files are correct when
+ they're loaded during SearchServiceWrapper instantiation */
+/* String configHomePath = (new File(".").getCanonicalPath() + "/appconfig-local").replace('\\', '/');
+ System.setProperty("CONFIG_HOME", configHomePath);
+ }
+ }
+
+ /**
+ * Inits the.
+ *
+ * @throws Exception the exception
+ */
+/* @Before
+ public void init() throws Exception {
+ commonRequest = HttpServletHelper.getMockHttpServletRequest();
+ responseStringWriter = new StringWriter();
+ printWriter = new PrintWriter(responseStringWriter);
+ commonResponse = HttpServletHelper.getMockHttpServletResponse(printWriter);
+ mapper = new ObjectMapper();
+
+ // permit serialization of objects with no members
+ mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
+
+ rand = new SecureRandom();
+
+ loader = Mockito.mock(OxmModelLoader.class);
+ descriptors = new HashMap<String, OxmEntityDescriptor>();
+
+ esConfig = new SearchServiceConfig();
+ suggestionConfig = SuggestionConfig.getConfig();
+
+ // Use SearchServiceWrapper and VnfSearchService for suggestionConfig
+ Map<String, String> svcs = new HashMap<String, String>();
+ svcs.put("autosuggestIndexname", "SearchServiceWrapper");
+ svcs.put("indexName", "VnfSearchService");
+ suggestionConfig.setSearchIndexToSearchService(svcs);
+
+ esConfig.setIndexName("esi-localhost");
+ esConfig.setType("default");
+
+ searchAdapter = Mockito.mock(SearchAdapter.class);
+ vnfSearchService = Mockito.mock(VnfSearchService.class);
+
+ initializeEntityDescriptors();
+
+ searchWrapper = new SearchServiceWrapper();
+ searchWrapper.setSasConfig(esConfig);
+ searchWrapper.setSearch(searchAdapter);
+ searchWrapper.setVnfSearch(vnfSearchService);
+ searchWrapper.setSuggestionConfig(suggestionConfig);
+ searchWrapper.setOxmModelLoader(loader);
+ }
+
+ @Test
+ public void validateAccessors() {
+ assertNotNull("Vnf Search Service should not be null", searchWrapper.getVnfSearch());
+ }
+
+ @Test
+ public void validateInitializer() {
+
+ try {
+ assertNotNull("Oxm Model loader should not be null", searchWrapper.getOxmModelLoader());
+ assertNotNull("SearchAbstractionConfig should not be null", searchWrapper.getSasConfig());
+ assertNotNull("SearchAdapter should not be null", searchWrapper.getSearch());
+ assertNotNull("Suggestion Config should not be null", searchWrapper.getSuggestionConfig());
+ assertNotNull("VnfSearchService should not be null", searchWrapper.getVnfSearch());
+
+ searchWrapper.setOxmModelLoader(null);
+ searchWrapper.setSasConfig(null);
+ searchWrapper.setSearch(null);
+ searchWrapper.setSuggestionConfig(null);
+ searchWrapper.setVnfSearch(null);
+
+ assertNull("Oxm Model loader should be null", searchWrapper.getOxmModelLoader());
+ assertNull("SearchAbstractionConfig should be null", searchWrapper.getSasConfig());
+ assertNull("SearchAdapter should be null", searchWrapper.getSearch());
+ assertNull("Suggestion Config should be null", searchWrapper.getSuggestionConfig());
+ assertNull("VnfSearchService should be null", searchWrapper.getVnfSearch());
+
+ } catch (Exception exc) {
+ fail("Servlet Initialization Failed with error = " + exc.getMessage());
+ }
+
+ }
+
+ /**
+ * Test doGet() and doPost() for a non-existent end-point. A test objective would be
+ * to either return a 404 Not Found.
+ */
+ /* @Test
+ public void validateMdcContextLoggingVariablesWhenExplicitlySet() {
+
+ final String transactionId = "1234";
+ final String serviceName = "AAI-UI";
+ final String partnerName = "SparkyApp";
+
+ HttpServletHelper.assignRequestHeader(commonRequest, "X-TransactionId", transactionId);
+ HttpServletHelper.assignRequestHeader(commonRequest, "X-FromAppId", partnerName);
+
+ HttpServletHelper.assignRequestUri(commonRequest, "search/this/path/does/not/exist/");
+
+ try {
+
+ /*
+ * Testing the doGet() operation will hit the doPost() operation in the servlet as well
+ */
+
+ /* OperationResult result = doEvaluationTestMDC(true, commonRequest, commonResponse);
+
+ assertEquals(transactionId,MDC.get(MdcContext.MDC_REQUEST_ID));
+ assertEquals(serviceName,MDC.get(MdcContext.MDC_SERVICE_NAME));
+ assertEquals(partnerName,MDC.get(MdcContext.MDC_PARTNER_NAME));
+
+ } catch (Exception exc) {
+ exc.printStackTrace();
+ fail("Unexpected exception = " + exc.getLocalizedMessage());
+ }
+
+ }
+
+ /**
+ * Test doGet() and doPost() for a non-existent end-point. A test objective would be
+ * to either return a 404 Not Found.
+ */
+ /* @Test
+ public void validateMdcContextLoggingVariablesWhenNotExplicitlySet() {
+
+ /*final String transactionId = "1234";
+ final String serviceName = "AAI-UI";
+ final String partnerName = "SparkyApp";
+
+ HttpServletHelper.assignRequestHeader(commonRequest, "X-TransactionId", transactionId);
+ HttpServletHelper.assignRequestHeader(commonRequest, "X-FromAppId", serviceName);*/
+
+/* HttpServletHelper.assignRequestUri(commonRequest, "search/this/path/does/not/exist/");
+
+ try {
+
+ /*
+ * Testing the doGet() operation will hit the doPost() operation in the servlet as well
+ */
+
+ /* OperationResult result = doEvaluationTestMDC(true, commonRequest, commonResponse);
+
+ assertNotNull(MDC.get(MdcContext.MDC_REQUEST_ID));
+ assertNotNull(MDC.get(MdcContext.MDC_SERVICE_NAME));
+ assertNotNull(MDC.get(MdcContext.MDC_PARTNER_NAME));
+
+ } catch (Exception exc) {
+ exc.printStackTrace();
+ fail("Unexpected exception = " + exc.getLocalizedMessage());
+ }
+
+ }
+
+
+
+ /**
+ * Test doGet() and doPost() for a non-existent end-point.
+ */
+ /* @Test
+ public void validateViewAndInspectSearchError_invalidRequestUri() {
+
+ HttpServletHelper.assignRequestUri(commonRequest, "search/this/path/does/not/exist/");
+
+ try {
+
+ /*
+ * Testing the doGet() operation will hit the doPost() operation in the servlet as well
+ */
+/*
+ OperationResult result = doEvaluation(true, commonRequest, commonResponse);
+ assertEquals(404, result.getResultCode());
+ assertTrue(result.getResult().contains("Ignored request-uri"));
+
+ } catch (Exception exc) {
+ exc.printStackTrace();
+ fail("Unexpected exception = " + exc.getLocalizedMessage());
+ }
+
+ }
+
+ /**
+ * Test doGet() and doPost() for Unified Query Search success path
+ */
+/* @Test
+ public void validateQuerySearch_successPath() {
+
+ try {
+
+ QuerySearchEntity searchEntity = new QuerySearchEntity();
+ searchEntity.setMaxResults("10");
+ searchEntity.setQueryStr("the quick brown fox");
+
+ HttpServletHelper.assignRequestUri(commonRequest, "search/querysearch");
+ HttpServletHelper.setRequestPayload(commonRequest, MediaType.JSON_UTF_8.toString(),
+ NodeUtils.convertObjectToJson(searchEntity, false));
+
+
+ // set search-abstraction-response that we expect to get back from real system, but stubbed through a mock
+ // to fulfill collaborator behavior
+
+ OperationResult mockedEntitySearchResponse = new OperationResult();
+ mockedEntitySearchResponse.setResultCode(200);
+ mockedEntitySearchResponse.setResult(NodeUtils.convertObjectToJson(
+ SearchAbstractionEntityBuilder.getSuccessfulEntitySearchResponse(), false));
+
+ // TODO: make parameters expect certain values to lock in invocation attempt against a specific input sequence
+ Mockito.when(searchAdapter.doPost(anyString(), anyString(), anyString()))
+ .thenReturn(mockedEntitySearchResponse);
+
+ List<SuggestionEntity> autoSuggestions = new ArrayList<SuggestionEntity>();
+
+ autoSuggestions.add(new SuggestionEntity("1234", "vnf", "VNFs", null));
+ autoSuggestions.add(new SuggestionEntity("1111", "vnf", "Created VNFs", null));
+ autoSuggestions.add(new SuggestionEntity("1122", "vnf", "ACTIVE VNFs", null));
+ autoSuggestions.add(new SuggestionEntity("2233", "vnf", "ACTIVE and Error VNFs", null));
+ autoSuggestions.add(new SuggestionEntity("3344", "vnf", "ACTIVE and NOT ORCHESTRATED VNFs", null));
+ autoSuggestions.add(new SuggestionEntity("4455", "vnf", "ACTIVE and Running VNFs", null));
+ autoSuggestions.add(new SuggestionEntity("5566", "vnf", "Activated VNFs", null));
+ autoSuggestions.add(new SuggestionEntity("6677", "vnf", "CAPPED VNFs", null));
+ autoSuggestions.add(new SuggestionEntity("7788", "vnf", "CAPPED and Created VNFs", null));
+
+ Mockito.when(vnfSearchService.getSuggestionsResults(Mockito.anyObject(), Mockito.anyInt()))
+ .thenReturn(autoSuggestions);
+
+ /*
+ * Testing the doGet() operation will hit the doPost() operation in the servlet as well
+ */
+/*
+ OperationResult result = doEvaluation(true, commonRequest, commonResponse);
+
+
+ assertEquals(200, result.getResultCode());
+
+ SearchResponse searchResponse = mapper.readValue(result.getResult(), SearchResponse.class);
+
+ assertEquals(10, searchResponse.getTotalFound());
+
+ int numVnf = 0;
+ int numViewInspect = 0;
+
+ for ( SuggestionEntity suggestion : searchResponse.getSuggestions()) {
+
+ if ( VNF_ROUTE.equals(suggestion.getRoute())) {
+ numVnf++;
+ } else if ( VIEW_INSPECT_ROUTE.equals(suggestion.getRoute())) {
+ numViewInspect++;
+ }
+ }
+
+ assertEquals(5, numVnf);
+ assertEquals(5, numViewInspect);
+
+ //assertTrue(result.getResult().contains("Ignored request-uri"));
+
+ } catch (Exception exc) {
+ fail("Unexpected exception = " + exc.getLocalizedMessage());
+ }
+
+ }
+
+ /**
+ * Test doGet() and doPost() for Unified Query Search success path
+ */
+ /*@Test
+ @Ignore
+ public void validateSummaryByEntityTypeCount_successPath() {
+
+ try {
+
+ HttpServletHelper.assignRequestUri(commonRequest, "search/summarybyentitytype/count");
+
+ Map<String,String> payloadFields = new HashMap<String,String>();
+ payloadFields.put("hashId", "662d1b57c31df70d7ef57ec53c0ace81578ec77b6bc5de055a57c7547ec122dd");
+ payloadFields.put("groupby", "orchestration-status");
+
+ HttpServletHelper.setRequestPayload(commonRequest, MediaType.JSON_UTF_8.toString(), NodeUtils.convertObjectToJson(payloadFields, false));
+
+ /*
+ * In this test we don't want to mock the vnf search service, only it's collaborator
+ * interactions with a REST endpoint.
+ */
+ /* vnfSearchService = new VnfSearchService();
+ vnfSearchService.setSearch(searchAdapter);
+ searchWrapper.setVnfSearch(vnfSearchService);
+
+ /*
+ * The first network response to mock is the one to elastic search to get the suggestion entity by hash id
+ *
+ * http://localhost:9200/entityautosuggestindex-localhost/_search
+ * {"query":{"term":{"_id":"2172a3c25ae56e4995038ffbc1f055692bfc76c0b8ceda1205bc745a9f7a805d"}}}
+ */
+ /*
+ AutoSuggestElasticSearchResponse elasticResponse = new AutoSuggestElasticSearchResponse();
+
+ elasticResponse.setTook(1);
+
+ elasticResponse.setTimedOut(false);
+ elasticResponse.addShard("total", "5");
+ elasticResponse.addShard("successful", "5");
+ elasticResponse.addShard("failed", "0");
+
+ AutoSuggestElasticHitEntity elasticHit = new AutoSuggestElasticHitEntity();
+ elasticHit.setIndex("entityautosuggestindex-localhost");
+ elasticHit.setType("default");
+ elasticHit.setId("2172a3c25ae56e4995038ffbc1f055692bfc76c0b8ceda1205bc745a9f7a805d");
+ elasticHit.setScore("1");
+
+ AutoSuggestDocumentEntityFields suggestDocFields = new AutoSuggestDocumentEntityFields();
+ suggestDocFields.addInput("VNFs");
+ suggestDocFields.addInput("generic-vnfs");
+ suggestDocFields.setOutput("VNFs");
+ suggestDocFields.setPayload(new PayloadEntity());
+ suggestDocFields.setWeight(100);
+
+ AutoSuggestDocumentEntity autoSuggestDoc = new AutoSuggestDocumentEntity();
+ autoSuggestDoc.setFields(suggestDocFields);
+
+ elasticHit.setSource(autoSuggestDoc);
+
+ AutoSuggestElasticHitsEntity hits = new AutoSuggestElasticHitsEntity();
+ hits.addHit(elasticHit);
+
+ elasticResponse.setHits(hits);
+
+
+ OperationResult mockedSearchResponse = new OperationResult();
+ mockedSearchResponse.setResultCode(200);
+
+ mockedSearchResponse.setResult(NodeUtils.convertObjectToJson(elasticResponse, false));
+
+
+ /*
+ * The second response is the count API dip to elastic search
+ */
+ /*
+ ElasticSearchCountResponse countResponse = new ElasticSearchCountResponse();
+ countResponse.setCount(3170);
+ countResponse.addShard("total", "5");
+ countResponse.addShard("successful", "5");
+ countResponse.addShard("failed", "0");
+
+ OperationResult searchResponseForCount = new OperationResult();
+ searchResponseForCount.setResultCode(200);
+
+ searchResponseForCount.setResult(NodeUtils.convertObjectToJson(countResponse, false));
+
+ // TODO: make parameters expect certain values to lock in invocation attempt against a specific input sequence
+ Mockito.when(searchAdapter.doPost(anyString(), anyString(), anyString()))
+ .thenReturn(mockedSearchResponse).thenReturn(searchResponseForCount);
+
+
+ /*
+ * Testing the doGet() operation will hit the doPost() operation in the servlet as well
+ */
+/*
+ OperationResult result = doEvaluation(true, commonRequest, commonResponse);
+
+
+ assertEquals(200, result.getResultCode());
+
+ //
+ //{"shards":{"total":"5","failed":"0","successful":"5"},"count":3170}
+
+ EntityCountResponse entityCountResponse = mapper.readValue(result.getResult(), EntityCountResponse.class);
+
+ assertEquals(3170, entityCountResponse.getCount());
+
+ } catch (Exception exc) {
+ fail("Unexpected exception = " + exc.getLocalizedMessage());
+ }
+
+ }
+
+
+ /**
+ * Test doGet() and doPost() for Unified Query Search success path
+ */
+ /*@Test
+ @Ignore
+ public void validateSummaryByEntityType_successPath() {
+
+ try {
+
+ HttpServletHelper.assignRequestUri(commonRequest, "search/summarybyentitytype");
+
+ Map<String,String> payloadFields = new HashMap<String,String>();
+ payloadFields.put("hashId", "662d1b57c31df70d7ef57ec53c0ace81578ec77b6bc5de055a57c7547ec122dd");
+ payloadFields.put("groupby", "orchestration-status");
+
+ HttpServletHelper.setRequestPayload(commonRequest, MediaType.JSON_UTF_8.toString(), NodeUtils.convertObjectToJson(payloadFields, false));
+
+ /*
+ * In this test we don't want to mock the vnf search service, only it's collaborator
+ * interactions with a REST endpoint.
+ */
+ /* vnfSearchService = new VnfSearchService();
+ vnfSearchService.setSearch(searchAdapter);
+ searchWrapper.setVnfSearch(vnfSearchService);
+
+ /*
+ * The first network response to mock is the one to elastic search to get the suggestion entity by hash id
+ *
+ * http://localhost:9200/entityautosuggestindex-localhost/_search
+ * {"query":{"term":{"_id":"2172a3c25ae56e4995038ffbc1f055692bfc76c0b8ceda1205bc745a9f7a805d"}}}
+ */
+
+ /* AutoSuggestElasticSearchResponse elasticResponse = new AutoSuggestElasticSearchResponse();
+
+ elasticResponse.setTook(1);
+
+ elasticResponse.setTimedOut(false);
+ elasticResponse.addShard("total", "5");
+ elasticResponse.addShard("successful", "5");
+ elasticResponse.addShard("failed", "0");
+
+ AutoSuggestElasticHitEntity elasticHit = new AutoSuggestElasticHitEntity();
+ elasticHit.setIndex("entityautosuggestindex-localhost");
+ elasticHit.setType("default");
+ elasticHit.setId("2172a3c25ae56e4995038ffbc1f055692bfc76c0b8ceda1205bc745a9f7a805d");
+ elasticHit.setScore("1");
+
+ AutoSuggestDocumentEntityFields suggestDocFields = new AutoSuggestDocumentEntityFields();
+ suggestDocFields.addInput("VNFs");
+ suggestDocFields.addInput("generic-vnfs");
+ suggestDocFields.setOutput("VNFs");
+ suggestDocFields.setPayload(new PayloadEntity());
+ suggestDocFields.setWeight(100);
+
+ AutoSuggestDocumentEntity autoSuggestDoc = new AutoSuggestDocumentEntity();
+ autoSuggestDoc.setFields(suggestDocFields);
+
+ elasticHit.setSource(autoSuggestDoc);
+
+ AutoSuggestElasticHitsEntity hits = new AutoSuggestElasticHitsEntity();
+ hits.addHit(elasticHit);
+
+ elasticResponse.setHits(hits);
+
+
+ OperationResult mockedSearchResponse = new OperationResult();
+ mockedSearchResponse.setResultCode(200);
+
+ mockedSearchResponse.setResult(NodeUtils.convertObjectToJson(elasticResponse, false));
+
+
+ /*
+ * The second response is the aggregation API dip to elastic search
+ */
+ /*
+ ElasticSearchAggegrationResponse aggResponse = new ElasticSearchAggegrationResponse();
+
+ aggResponse.setTook(20);
+ aggResponse.setTimedOut(false);
+
+ aggResponse.addShard("total","5");
+ aggResponse.addShard("successful","5");
+ aggResponse.addShard("failed","0");
+
+ ElasticHitsEntity hitsEntity = new ElasticHitsEntity();
+
+ hitsEntity.setTotal(3170);
+ hitsEntity.setMaxScore(0);
+
+ aggResponse.setHits(hitsEntity);
+
+ ElasticSearchAggregation defaultAggregation = new ElasticSearchAggregation();
+
+ defaultAggregation.setDocCountErrorUpperBound(0);
+ defaultAggregation.setSumOtherDocCount(0);
+ defaultAggregation.addBucket(new BucketEntity("created",1876));
+ defaultAggregation.addBucket(new BucketEntity("Created",649));
+ defaultAggregation.addBucket(new BucketEntity("Activated",158));
+ defaultAggregation.addBucket(new BucketEntity("active",59));
+ defaultAggregation.addBucket(new BucketEntity("NOT ORCHESTRATED",42));
+ defaultAggregation.addBucket(new BucketEntity("Pending-Create",10));
+ defaultAggregation.addBucket(new BucketEntity("Running",9));
+ defaultAggregation.addBucket(new BucketEntity("Configured",7));
+ defaultAggregation.addBucket(new BucketEntity("pending-create",7));
+ defaultAggregation.addBucket(new BucketEntity("Error",3));
+ defaultAggregation.addBucket(new BucketEntity("planned",3));
+ defaultAggregation.addBucket(new BucketEntity("PLANNED",2));
+ defaultAggregation.addBucket(new BucketEntity("ERROR",1));
+ defaultAggregation.addBucket(new BucketEntity("RUNNING",1));
+ defaultAggregation.addBucket(new BucketEntity("example-orchestration-status-val-6176",1));
+
+ aggResponse.addAggregation("default", defaultAggregation);
+
+ OperationResult searchResponseForAggregation = new OperationResult();
+ searchResponseForAggregation.setResultCode(200);
+
+ searchResponseForAggregation.setResult(NodeUtils.convertObjectToJson(aggResponse, false));
+
+ // TODO: make parameters expect certain values to lock in invocation attempt against a specific input sequence
+ Mockito.when(searchAdapter.doPost(anyString(), anyString(), anyString()))
+ .thenReturn(mockedSearchResponse).thenReturn(searchResponseForAggregation);
+
+
+ /*
+ * Testing the doGet() operation will hit the doPost() operation in the servlet as well
+ */
+/*
+ OperationResult result = doEvaluation(true, commonRequest, commonResponse);
+
+
+ assertEquals(200, result.getResultCode());
+
+ //
+ //{"shards":{"total":"5","failed":"0","successful":"5"},"count":3170}
+
+ GroupByAggregationResponseEntity groupByResponse = mapper.readValue(result.getResult(), GroupByAggregationResponseEntity.class);
+
+ assertEquals(2828, groupByResponse.getAggEntity().getTotalChartHits());
+ assertEquals(15, groupByResponse.getAggEntity().getBuckets().size());
+
+ } catch (Exception exc) {
+ fail("Unexpected exception = " + exc.getLocalizedMessage());
+ }
+ }
+
+ @Test
+ public void validateHandleDiscoverSearchFilters_vnfSearchViewName() throws IOException {
+ String requestBody = "{ \"viewName\" : \"VnfSearch\" }";
+ String expectedResponse = "{\"filters\":[{\"filterId\":\"1\",\"filterName\":\"Orchestration-Status\",\"displayName\":\"Orchestration Status\",\"dataType\":\"list\"},{\"filterId\":\"2\",\"filterName\":\"Prov-Status\",\"displayName\":\"Provisioning Status\",\"dataType\":\"list\"}]}";
+
+ HttpServletHelper.assignRequestUri(commonRequest, "search/discoverFilters");
+ HttpServletHelper.setRequestPayload(commonRequest, MediaType.JSON_UTF_8.toString(), requestBody);
+
+ OperationResult result = doEvaluation(true, commonRequest, commonResponse);
+
+ assertEquals(expectedResponse, result.getResult().trim());
+ }
+
+ @Test
+ public void validateFilterAggregation_successPath() {
+ String requestBodyFilePath = "filters/filterAggregationEndpoint_successPath_requestBody.json";
+ String expectedResponseFilePath = "filters/filterAggregationEndpoint_successPath_expectedResponse.json";
+ String operationResultFilePath = "filters/filterAggregationEndpoint_successPath_operationResult.json";
+
+ String requestBody = getResourceFileContents(requestBodyFilePath);
+ String expectedResponse = getResourceFileContents(expectedResponseFilePath);
+
+ HttpServletHelper.assignRequestUri(commonRequest, "search/filterAggregation");
+ HttpServletHelper.setRequestPayload(commonRequest, MediaType.JSON_UTF_8.toString(), requestBody);
+
+ OperationResult operationResult = new OperationResult();
+ operationResult.setResult(getResourceFileContents(operationResultFilePath));
+
+ vnfSearchService = new VnfSearchService();
+ vnfSearchService.setSearch(searchAdapter);
+ searchWrapper.setVnfSearch(vnfSearchService);
+
+ Mockito.when(searchAdapter.doPost(anyString(), anyString(), anyString())).thenReturn(operationResult);
+
+ OperationResult result = doEvaluation(true, commonRequest, commonResponse);
+
+ assertEquals(expectedResponse.trim(), result.getResult().trim());
+ }
+
+ @Test
+ public void validateFilterAggregation_emptyRequestFilterArray() throws IOException {
+ String requestBodyFilePath = "filters/filterAggregationEndpoint_emptyRequestFilterArray_requestBody.json";
+ String expectedResponseFilePath = "filters/filterAggregationEndpoint_emptyRequestFilterArray_expectedResponse.json";
+
+ String requestBody = getResourceFileContents(requestBodyFilePath);
+ String expectedResponse = getResourceFileContents(expectedResponseFilePath);
+
+ HttpServletHelper.assignRequestUri(commonRequest, "search/filterAggregation");
+ HttpServletHelper.setRequestPayload(commonRequest, MediaType.JSON_UTF_8.toString(), requestBody);
+
+ vnfSearchService = new VnfSearchService();
+ vnfSearchService.setSearch(searchAdapter);
+ searchWrapper.setVnfSearch(vnfSearchService);
+
+ OperationResult result = doEvaluation(true, commonRequest, commonResponse);
+
+ assertEquals(expectedResponse.trim(), result.getResult().trim());
+ }
+
+ @Test
+ public void validateFilterAggregation_emptyRequestBody() throws IOException {
+ String expectedResponseFilePath = "filters/filterAggregationEndpoint_emptyRequestBody_expectedResponse.json";
+
+ String expectedResponse = getResourceFileContents(expectedResponseFilePath);
+
+ HttpServletHelper.assignRequestUri(commonRequest, "search/filterAggregation");
+ HttpServletHelper.setRequestPayload(commonRequest, MediaType.JSON_UTF_8.toString(), "{}");
+
+ vnfSearchService = new VnfSearchService();
+ vnfSearchService.setSearch(searchAdapter);
+ searchWrapper.setVnfSearch(vnfSearchService);
+
+ OperationResult result = doEvaluation(true, commonRequest, commonResponse);
+
+ assertEquals(expectedResponse.trim(), result.getResult().trim());
+ }
+
+ @Test
+ public void validateHandleDiscoverSearchFilters_diuiViewName() throws IOException {
+ String requestBody = "{ \"viewName\" : \"dataIntegrity\" }";
+ String expectedResponse = "{\"filters\":[{\"filterId\":\"3\",\"filterName\":\"Severity\",\"displayName\":\"Severity\",\"dataType\":\"list\"},{\"filterId\":\"4\",\"filterName\":\"Category\",\"displayName\":\"Category\",\"dataType\":\"list\"},{\"filterId\":\"5\",\"filterName\":\"Date\",\"displayName\":\"Date\",\"dataType\":\"date\"},{\"filterId\":\"6\",\"filterName\":\"EntityType\",\"displayName\":\"Entity Type\",\"dataType\":\"list\"}]}";
+
+ HttpServletHelper.assignRequestUri(commonRequest, "search/discoverFilters");
+ HttpServletHelper.setRequestPayload(commonRequest, MediaType.JSON_UTF_8.toString(), requestBody);
+
+ OperationResult result = doEvaluation(true, commonRequest, commonResponse);
+
+ assertEquals(expectedResponse, result.getResult().trim());
+ }
+
+ @Test
+ public void validateHandleDiscoverSearchFilterValues_validId() throws IOException {
+ String requestBody = "{ \"filterIdList\" : [ { \"filterId\" : \"1\" } ] }";
+ String expectedResponse = "{\"filters\":[{\"filterId\":\"1\",\"filterName\":\"Orchestration-Status\",\"displayName\":\"Orchestration Status\",\"dataType\":\"list\",\"filterValueList\":[{\"filterValue\":\"created\",\"displayName\":\"created\"}]}]}";
+
+ HttpServletHelper.assignRequestUri(commonRequest, "search/discoverFilterValues");
+ HttpServletHelper.setRequestPayload(commonRequest, MediaType.JSON_UTF_8.toString(), requestBody);
+
+ FilteredSearchHelper filteredSearchHelper = Mockito.mock(FilteredSearchHelper.class);
+ searchWrapper.setFilteredSearchHelper(filteredSearchHelper);
+
+ UiFilterValueEntity uiFilterValueEntity = new UiFilterValueEntity(null, "created", "created");
+
+ UiFilterEntity uiFilterEntity = new UiFilterEntity();
+ uiFilterEntity.setDataType("list");
+ uiFilterEntity.setDisplayName("Orchestration Status");
+ uiFilterEntity.setFilterId("1");
+ uiFilterEntity.setFilterName("Orchestration-Status");
+ uiFilterEntity.addFilterValue(uiFilterValueEntity);
+
+ UiFiltersEntity uiFiltersEntity = new UiFiltersEntity();
+ uiFiltersEntity.addFilter(uiFilterEntity);
+
+ Mockito.when(filteredSearchHelper.doFilterEnumeration(Mockito.anyList()))
+ .thenReturn(uiFiltersEntity);
+
+ OperationResult result = doEvaluation(true, commonRequest, commonResponse);
+
+ assertEquals(expectedResponse, result.getResult().trim());
+ }
+
+ @Test
+ public void validateHandleDiscoverSearchFilterValues_multipleValidIds() throws IOException {
+ String requestBody = "{ \"filterIdList\" : [ { \"filterId\" : \"1\" }, { \"filterId\" : \"2\" } ] }";
+ String expectedResponse = "{\"filters\":[{\"filterId\":\"1\",\"filterName\":\"Orchestration-Status\",\"displayName\":\"Orchestration Status\",\"dataType\":\"list\",\"filterValueList\":[{\"filterValue\":\"created\",\"displayName\":\"created\"}]},{\"filterId\":\"2\",\"filterName\":\"Prov-Status\",\"displayName\":\"Provisioning Status\",\"dataType\":\"list\",\"filterValueList\":[{\"filterValue\":\"active\",\"displayName\":\"active\"}]}]}";
+
+ HttpServletHelper.assignRequestUri(commonRequest, "search/discoverFilterValues");
+ HttpServletHelper.setRequestPayload(commonRequest, MediaType.JSON_UTF_8.toString(), requestBody);
+
+ FilteredSearchHelper filteredSearchHelper = Mockito.mock(FilteredSearchHelper.class);
+ searchWrapper.setFilteredSearchHelper(filteredSearchHelper);
+
+ UiFiltersEntity uiFiltersEntity = new UiFiltersEntity();
+
+ UiFilterValueEntity uiFilter1ValueEntity = new UiFilterValueEntity(null, "created", "created");
+ UiFilterEntity uiFilterEntity1 = new UiFilterEntity();
+ uiFilterEntity1.setDataType("list");
+ uiFilterEntity1.setDisplayName("Orchestration Status");
+ uiFilterEntity1.setFilterId("1");
+ uiFilterEntity1.setFilterName("Orchestration-Status");
+ uiFilterEntity1.addFilterValue(uiFilter1ValueEntity);
+ uiFiltersEntity.addFilter(uiFilterEntity1);
+
+ UiFilterValueEntity uiFilter2ValueEntity = new UiFilterValueEntity(null, "active", "active");
+ UiFilterEntity uiFilterEntity2 = new UiFilterEntity();
+ uiFilterEntity2.setDataType("list");
+ uiFilterEntity2.setDisplayName("Provisioning Status");
+ uiFilterEntity2.setFilterId("2");
+ uiFilterEntity2.setFilterName("Prov-Status");
+ uiFilterEntity2.addFilterValue(uiFilter2ValueEntity);
+ uiFiltersEntity.addFilter(uiFilterEntity2);
+
+ Mockito.when(filteredSearchHelper.doFilterEnumeration(Mockito.anyList()))
+ .thenReturn(uiFiltersEntity);
+
+ OperationResult result = doEvaluation(true, commonRequest, commonResponse);
+
+ assertEquals(expectedResponse, result.getResult().trim());
+ }
+
+ @Test
+ public void validateHandleDiscoverSearchFilterValues_invalidId() throws IOException {
+ String requestBody = "{ \"filterIdList\" : [ { \"filterId\" : \"999\" } ] }";
+ String expectedResponse = "{\"filters\":[]}";
+
+ HttpServletHelper.assignRequestUri(commonRequest, "search/discoverFilterValues");
+ HttpServletHelper.setRequestPayload(commonRequest, MediaType.JSON_UTF_8.toString(), requestBody);
+
+ OperationResult result = doEvaluation(true, commonRequest, commonResponse);
+
+ assertEquals(expectedResponse, result.getResult().trim());
+ }
+
+ @Test
+ public void validateHandleDiscoverSearchFilterValues_validIdAndInvalidId() throws IOException {
+ String requestBody = "{ \"filterIdList\" : [ { \"filterId\" : \"1\" }, { \"filterId\" : \"999\" } ] }";
+ String expectedResponse = "{\"filters\":[{\"filterId\":\"1\",\"filterName\":\"Orchestration-Status\",\"displayName\":\"Orchestration Status\",\"dataType\":\"list\",\"filterValueList\":[{\"filterValue\":\"created\",\"displayName\":\"created\"}]}]}";
+
+ HttpServletHelper.assignRequestUri(commonRequest, "search/discoverFilterValues");
+ HttpServletHelper.setRequestPayload(commonRequest, MediaType.JSON_UTF_8.toString(), requestBody);
+
+ FilteredSearchHelper filteredSearchHelper = Mockito.mock(FilteredSearchHelper.class);
+ searchWrapper.setFilteredSearchHelper(filteredSearchHelper);
+
+ UiFilterValueEntity uiFilterValueEntity = new UiFilterValueEntity(null, "created", "created");
+
+ UiFilterEntity uiFilterEntity = new UiFilterEntity();
+ uiFilterEntity.setDataType("list");
+ uiFilterEntity.setDisplayName("Orchestration Status");
+ uiFilterEntity.setFilterId("1");
+ uiFilterEntity.setFilterName("Orchestration-Status");
+ uiFilterEntity.addFilterValue(uiFilterValueEntity);
+
+ UiFiltersEntity uiFiltersEntity = new UiFiltersEntity();
+ uiFiltersEntity.addFilter(uiFilterEntity);
+
+ Mockito.when(filteredSearchHelper.doFilterEnumeration(Mockito.anyList()))
+ .thenReturn(uiFiltersEntity);
+
+ OperationResult result = doEvaluation(true, commonRequest, commonResponse);
+
+ assertEquals(expectedResponse, result.getResult().trim());
+ }
+
+ /**
+ * Builds the resource entity descriptor.
+ *
+ * @param entityType the entity type
+ * @param attributeNames the attribute names
+ * @param searchableAttributes the searchable attributes
+ * @return the oxm entity descriptor
+ */
+/* @SuppressWarnings("unchecked")
+ private OxmEntityDescriptor buildResourceEntityDescriptor(String entityType,
+ String attributeNames, String searchableAttributes) {
+ OxmEntityDescriptor descriptor = new OxmEntityDescriptor();
+ descriptor.setEntityName(entityType);
+
+ if (attributeNames != null) {
+ descriptor.setPrimaryKeyAttributeName(Arrays.asList(attributeNames.split(",")));
+ }
+
+ if (searchableAttributes != null) {
+ descriptor.setSearchableAttributes(Arrays.asList(searchableAttributes.split(",")));
+ }
+
+ return descriptor;
+ }
+
+ /**
+ * Initialize entity descriptors.
+ */
+ /*private void initializeEntityDescriptors() {
+ descriptors.put("customer",
+ buildResourceEntityDescriptor("customer", "service-instance-id", "f1,f2,f3"));
+ }
+
+ /**
+ * Builds the view and inspect search request.
+ *
+ * @param maxResults the max results
+ * @param queryStr the query str
+ * @return the string
+ * @throws JsonProcessingException the json processing exception
+ */
+ /* public String buildViewAndInspectSearchRequest(Integer maxResults, String queryStr)
+ throws JsonProcessingException {
+
+ /*
+ * { "maxResults" : "10", "searchStr" : "<search bar text>" }
+ */
+/*
+ ObjectNode rootNode = mapper.createObjectNode();
+
+ if (maxResults != null) {
+ rootNode.put("maxResults", maxResults);
+ }
+
+ if (queryStr != null) {
+ rootNode.put("queryStr", queryStr);
+ }
+
+ return NodeUtils.convertObjectToJson(rootNode, true);
+
+ }
+
+ public String getResourceFileContents(String filePath) {
+ StringBuilder result = new StringBuilder("");
+
+ ClassLoader classLoader = getClass().getClassLoader();
+ File file = new File(classLoader.getResource(filePath).getFile());
+
+ try (Scanner scanner = new Scanner(file)) {
+ while (scanner.hasNextLine()) {
+ String line = scanner.nextLine();
+ result.append(line).append("\n");
+ }
+
+ scanner.close();
+
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ return result.toString();
+ }
+
+
+ /**
+ * Do evaluation.
+ *
+ * @param doGet the do get
+ * @param req the req
+ * @param res the res
+ * @return the string
+ *//*
+ private OperationResult doEvaluationTestMDC(boolean doGet, HttpServletRequest req, HttpServletResponse res) {
+
+ /*
+ * Test method invocation
+ */
+/*
+ SearchServlet searchServlet = new SearchServlet();
+ try {
+ searchServlet.init();
+ } catch (ServletException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ ArgumentCaptor<Integer> responseCodeCaptor = ArgumentCaptor.forClass(Integer.class);
+
+ try {
+ if (doGet) {
+ searchServlet.doGet(req, res);
+ } else {
+ searchServlet.doPost(req, res);
+ }
+ } catch (ServletException exc) {
+ fail(ExceptionHelper.extractStackTraceElements(5, exc));
+ } catch (IOException exc) {
+ fail(ExceptionHelper.extractStackTraceElements(5, exc));
+ }
+
+ responseStringWriter.flush();
+ Mockito.verify(commonResponse, Mockito.atLeast(1)).setStatus(responseCodeCaptor.capture());
+
+ OperationResult result = new OperationResult();
+
+ result.setResultCode(responseCodeCaptor.getValue());
+ result.setResult(responseStringWriter.toString());
+
+ return result;
+
+ }
+
+ /**
+ * Do evaluation.
+ *
+ * @param doGet the do get
+ * @param req the req
+ * @param res the res
+ * @return the string
+ *//*
+ private OperationResult doEvaluation(boolean doGet, HttpServletRequest req, HttpServletResponse res) {
+
+ /*
+ * Test method invocation
+ */
+ /* ArgumentCaptor<Integer> responseCodeCaptor = ArgumentCaptor.forClass(Integer.class);
+
+ try {
+ if (doGet) {
+ searchWrapper.doGet(req, res);
+ } else {
+ searchWrapper.doPost(req, res);
+ }
+ } catch (ServletException exc) {
+ fail(ExceptionHelper.extractStackTraceElements(5, exc));
+ } catch (IOException exc) {
+ fail(ExceptionHelper.extractStackTraceElements(5, exc));
+ }
+
+ responseStringWriter.flush();
+ Mockito.verify(commonResponse, Mockito.atLeast(1)).setStatus(responseCodeCaptor.capture());
+
+ OperationResult result = new OperationResult();
+
+ result.setResultCode(responseCodeCaptor.getValue());
+ result.setResult(responseStringWriter.toString());
+
+ return result;
+
+ }
+
+}*/
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/SearchableGroupsTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/SearchableGroupsTest.java
new file mode 100644
index 0000000..3aaf17a
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/SearchableGroupsTest.java
@@ -0,0 +1,73 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+
+package org.onap.aai.sparky.viewandinspect;
+
+/**
+ * The Class SearchableGroupsTest.
+ */
+public class SearchableGroupsTest {
+
+ static final String TEST_RESOURCE_PATH = "/src/test/resources";
+
+ static final String GOOD_TEST_CONFIG = "{\"groups\": [" + "{" + "\"group-name\" : \"inventory\","
+ + "\"search-paths\" : [\"cloud-infrastructure\", \"business\", \"network\"]" + "}," + "{"
+ + "\"group-name\" : \"cloud-infrastructure\","
+ + "\"search-paths\" : [\"complexes\", \"cloud-regions\", \"pservers\"]" + "}" + "]" + "}";
+ /*
+ * @Before public void init() throws NoSuchFieldException, SecurityException,
+ * IllegalArgumentException, IllegalAccessException { Field instance =
+ * SearchableGroups.class.getDeclaredField("instance"); instance.setAccessible(true);
+ * instance.set(null, null); }
+ *
+ * @Test public void test_FileNotFound() throws ElasticSearchOperationException {
+ * System.setProperty("AJSC_HOME", ""); SearchableGroups testGroups =
+ * SearchableGroups.getTestInstance(); assertTrue(testGroups.getGroups().isEmpty()); }
+ *
+ * @Test public void test_FileFoundWithProperlyFormatedConfig() throws
+ * ElasticSearchOperationException { ResolverUtils testUtils =
+ * Mockito.mock(ResolverUtils.class);
+ * Mockito.when(testUtils.getConfigSettings(anyString())).thenReturn(GOOD_TEST_CONFIG);
+ * SearchableGroups testGroups = SearchableGroups.getTestInstance();
+ *
+ * testGroups.setUtils(testUtils); testGroups.initSearchableGroups();
+ *
+ * assertFalse(testGroups.getGroups().isEmpty());
+ *
+ * assertFalse(testGroups.getSearchableGroups("inventory").isEmpty()); }
+ *
+ * @Test public void test_FileFoundGroupDoesNotExist() throws
+ * ElasticSearchOperationException {
+ * ResolverUtils testUtils = Mockito.mock(ResolverUtils.class);
+ * Mockito.when(testUtils.getConfigSettings(anyString())).thenReturn(GOOD_TEST_CONFIG);
+ * SearchableGroups testGroups = SearchableGroups.getTestInstance();
+ *
+ * testGroups.setUtils(testUtils); testGroups.initSearchableGroups();
+ *
+ * assertFalse(testGroups.getGroups().isEmpty());
+ *
+ * assertEquals(null, testGroups.getSearchableGroups("Test")); }
+ */
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/ViewAndInspectSearchRequestTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/ViewAndInspectSearchRequestTest.java
new file mode 100644
index 0000000..7c05143
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/ViewAndInspectSearchRequestTest.java
@@ -0,0 +1,81 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+
+package org.onap.aai.sparky.viewandinspect;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.onap.aai.sparky.search.entity.QuerySearchEntity;
+
+/**
+ * The Class ViewAndInspectSearchRequestTest.
+ */
+@RunWith(MockitoJUnitRunner.class)
+public class ViewAndInspectSearchRequestTest {
+
+ /**
+ * Inits the.
+ *
+ * @throws Exception the exception
+ */
+ @Before
+ public void init() throws Exception {}
+
+ /**
+ * Validate basic construction.
+ */
+ @Test
+ public void validateBasicConstruction() {
+
+ QuerySearchEntity request = new QuerySearchEntity();
+
+ // test constructor defaults
+ assertNull(request.getQueryStr());
+ assertEquals("10", request.getMaxResults());
+
+ request.setMaxResults("500");
+ assertEquals("500", request.getMaxResults());
+
+ assertNull(request.getSearchTerms());
+
+ request.setQueryStr("");
+ assertEquals(1, request.getSearchTerms().length);
+
+ request.setQueryStr("t1");
+ assertEquals(1, request.getSearchTerms().length);
+
+ request.setQueryStr("t1 t2 t3");
+ assertEquals(3, request.getSearchTerms().length);
+
+ }
+
+}
+
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/VisualizationTransformerTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/VisualizationTransformerTest.java
new file mode 100644
index 0000000..3f5988f
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/VisualizationTransformerTest.java
@@ -0,0 +1,77 @@
+package org.onap.aai.sparky.viewandinspect;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.onap.aai.sparky.config.oxm.OxmEntityLookup;
+import org.onap.aai.sparky.subscription.config.SubscriptionConfig;
+import org.onap.aai.sparky.util.OxmModelAndProcessorHelper;
+import org.onap.aai.sparky.viewandinspect.config.VisualizationConfigs;
+import org.onap.aai.sparky.viewandinspect.entity.ActiveInventoryNode;
+import org.onap.aai.sparky.viewandinspect.entity.GraphMeta;
+import org.onap.aai.sparky.viewandinspect.entity.SparkyGraphNode;
+import org.onap.aai.sparky.viewandinspect.services.VisualizationTransformer;
+import org.onap.aai.sparky.viewandinspect.util.SchemaVisualizationTestDataBuilder;
+
+import com.fasterxml.jackson.core.JsonParseException;
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.JsonMappingException;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+public class VisualizationTransformerTest {
+
+ VisualizationTransformer testTransformer;
+ VisualizationConfigs visConfig;
+ SubscriptionConfig subConfig;
+ GraphMeta graphMeta;
+ OxmEntityLookup oxmEntityLookup;
+
+
+ @Before
+ public void init() throws Exception {
+ this.visConfig = new VisualizationConfigs();
+ this.subConfig = new SubscriptionConfig();
+ this.graphMeta = new GraphMeta();
+ this.oxmEntityLookup = OxmModelAndProcessorHelper.getInstance().getOxmEntityLookup();
+
+ this.testTransformer = new VisualizationTransformer(visConfig, subConfig);
+ }
+
+ @Test
+ public void testGenerateVisualizationOutput() throws JsonParseException, JsonMappingException, IOException {
+ ObjectMapper mapper = new ObjectMapper();
+ mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
+
+ JsonNode elasticValue = mapper.readValue(SchemaVisualizationTestDataBuilder.getRawRootNode(), JsonNode.class);
+
+ }
+
+ public ActiveInventoryNode generateActiveInventoryNode(String id, String type, String selfLink, String primaryKeyName, String primaryKeyValue) {
+ ActiveInventoryNode testAin = new ActiveInventoryNode(visConfig, oxmEntityLookup);
+
+ testAin.setNodeId(id);
+ testAin.setEntityType(type);
+ testAin.setSelfLink(selfLink);
+ testAin.setPrimaryKeyName(primaryKeyName);
+ testAin.setPrimaryKeyValue(primaryKeyValue);
+
+ return testAin;
+ }
+
+ public SparkyGraphNode generateSparkyGraphNode(ActiveInventoryNode ain) {
+
+ SparkyGraphNode testSparkyGraphNode = new SparkyGraphNode(ain, visConfig, subConfig);
+
+ return testSparkyGraphNode;
+ }
+
+ public Map<String, ActiveInventoryNode> generateFlatNodeArray() {
+ Map<String, ActiveInventoryNode> nodeArray = new HashMap<String, ActiveInventoryNode>();
+
+ return nodeArray;
+ }
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/config/VisualizationConfigTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/config/VisualizationConfigTest.java
new file mode 100644
index 0000000..5dbf7bb
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/config/VisualizationConfigTest.java
@@ -0,0 +1,62 @@
+package org.onap.aai.sparky.viewandinspect.config;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.ArrayList;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class VisualizationConfigTest {
+
+
+ private VisualizationConfigs visualConfig;
+ private ArrayList<String> shallowEntities;
+
+ @Before
+ public void init() throws Exception {
+ visualConfig = new VisualizationConfigs();
+ shallowEntities = new ArrayList<String>();
+
+ }
+
+
+ @Test
+ public void updateValues() {
+
+ visualConfig.setShallowEntities(shallowEntities);
+ assertNotNull(visualConfig.getShallowEntities());
+ visualConfig.setMakeAllNeighborsBidirectional(true);
+ assertTrue(visualConfig.makeAllNeighborsBidirectional());
+ visualConfig.setSelectedSearchedNodeClassName("selectedsearchedNodeClass");
+ assertNotNull(visualConfig.getSelectedSearchedNodeClassName());
+ visualConfig.setGeneralNodeClassName("generalNodeClass");
+ assertNotNull(visualConfig.getGeneralNodeClassName());
+ visualConfig.setSearchNodeClassName("searchedNodeClass");
+ assertNotNull(visualConfig.getSearchNodeClassName());
+ visualConfig.setAaiEntityNodeDescriptors("/etc/aaiEntityNodeDescriptors.json");
+ assertNotNull(visualConfig.getAaiEntityNodeDescriptors());
+ visualConfig.setVisualizationDebugEnabled(true);
+ assertTrue(visualConfig.isVisualizationDebugEnabled());
+ visualConfig.setMaxSelfLinkTraversalDepth(3);
+ assertEquals(3,visualConfig.getMaxSelfLinkTraversalDepth());
+ visualConfig.setNumOfThreadsToFetchNodeIntegrity(25);
+ assertEquals(25,visualConfig.getNumOfThreadsToFetchNodeIntegrity());
+ assertNotNull(visualConfig.toString());
+ visualConfig.setAaiEntityNodeDescriptors(null);
+ assertNull(visualConfig.getAaiEntityNodeDescriptors());
+ visualConfig.setGeneralNodeClassName(null);
+ assertNull(visualConfig.getGeneralNodeClassName());
+ visualConfig.setSearchNodeClassName(null);
+ assertNull(visualConfig.getSearchNodeClassName());
+ visualConfig.setSelectedSearchedNodeClassName(null);
+ assertNull(visualConfig.getSelectedSearchedNodeClassName());
+ assertNotNull(visualConfig.toString());
+
+
+ }
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/ActiveInventoryNodeTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/ActiveInventoryNodeTest.java
new file mode 100644
index 0000000..8469d1a
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/ActiveInventoryNodeTest.java
@@ -0,0 +1,128 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+
+package org.onap.aai.sparky.viewandinspect.entity;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.ArrayList;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.onap.aai.restclient.client.OperationResult;
+import org.onap.aai.sparky.config.oxm.OxmEntityLookup;
+import org.onap.aai.sparky.viewandinspect.config.VisualizationConfigs;
+
+public class ActiveInventoryNodeTest {
+
+ private ActiveInventoryNode activeInventoryNode;
+ private ArrayList<String> lst = new ArrayList<String>();
+ private OperationResult opResult;
+ private VisualizationConfigs visualConfig;
+ private OxmEntityLookup oxmEntityLookup;
+
+ @Before
+ public void init() throws Exception {
+
+ visualConfig = new VisualizationConfigs();
+ oxmEntityLookup = new OxmEntityLookup();
+ activeInventoryNode = new ActiveInventoryNode(visualConfig,oxmEntityLookup);
+
+ }
+
+ @Test
+ public void successfulInitializationAndUpdate() {
+
+ activeInventoryNode.addQueryParam("query-1");
+ activeInventoryNode.clearQueryParams();
+ activeInventoryNode.addQueryParams(lst);
+ assertNotNull(activeInventoryNode.getQueryParams());
+ assertNull(activeInventoryNode.getOxmModelLoader());
+ activeInventoryNode.setSelfLinkDeterminationPending(true);
+ assertTrue(activeInventoryNode.isSelfLinkDeterminationPending());
+ assertNotNull(activeInventoryNode.getState());
+ assertNotNull(activeInventoryNode.getComplexGroups());
+ assertNotNull(activeInventoryNode.getRelationshipLists());
+ activeInventoryNode.setOpResult(opResult);
+ assertNull(activeInventoryNode.getOpResult());
+ activeInventoryNode.setPrimaryKeyName("PrimaryKeyName");
+ assertNotNull(activeInventoryNode.getPrimaryKeyName());
+ activeInventoryNode.setNodeDepth(2);
+ assertEquals(2,activeInventoryNode.getNodeDepth());
+ activeInventoryNode.setvisualizationConfig(visualConfig);
+ assertNotNull(activeInventoryNode.getvisualizationConfigs());
+ activeInventoryNode.setNodeValidated(true);
+ assertTrue(activeInventoryNode.isNodeValidated());
+ activeInventoryNode.setPrimaryKeyValue("PrimaryKeyValue");
+ assertNotNull(activeInventoryNode.getPrimaryKeyValue());
+ activeInventoryNode.setIgnoredByFilter(true);
+ assertTrue(activeInventoryNode.isIgnoredByFilter());
+ activeInventoryNode.setNodeIssue(true);
+ assertTrue(activeInventoryNode.isNodeIssue());
+ activeInventoryNode.setProcessedNeighbors(true);
+ assertTrue(activeInventoryNode.hasProcessedNeighbors());
+ activeInventoryNode.setResolvedSelfLink(true);
+ assertTrue(activeInventoryNode.hasResolvedSelfLink());
+ activeInventoryNode.addInboundNeighbor("InBoundNodeID");
+ activeInventoryNode.addOutboundNeighbor("OutBoundNodeID");
+ assertTrue(activeInventoryNode.hasNeighbors());
+ activeInventoryNode.addInboundNeighbor(null);
+ activeInventoryNode.addOutboundNeighbor(null);
+ assertNotNull(activeInventoryNode.getInboundNeighbors());
+ assertNotNull(activeInventoryNode.getOutboundNeighbors());
+ assertTrue(activeInventoryNode.isAtMaxDepth());
+ activeInventoryNode.setSelfLinkPendingResolve(true);
+ assertTrue(activeInventoryNode.isSelfLinkPendingResolve());
+ activeInventoryNode.setRootNode(true);
+ assertTrue(activeInventoryNode.isRootNode());
+ activeInventoryNode.setSelflinkRetrievalFailure(true);
+ assertTrue(activeInventoryNode.isSelflinkRetrievalFailure());
+ activeInventoryNode.setSelfLinkProcessed(true);
+ assertTrue(activeInventoryNode.getSelfLinkProcessed());
+ activeInventoryNode.setNodeIntegrityProcessed(true);
+ assertTrue(activeInventoryNode.getNodeIntegrityProcessed());
+ assertFalse(activeInventoryNode.isDirectSelfLink());
+ activeInventoryNode.setProcessingErrorOccurred(true);
+ assertTrue(activeInventoryNode.isProcessingErrorOccurred());
+ activeInventoryNode.setNodeId("NodeId-1");
+ assertNotNull(activeInventoryNode.getNodeId());
+ activeInventoryNode.setSelfLink("selfLinkSet");
+ assertNotNull(activeInventoryNode.getSelfLink());
+ activeInventoryNode.setEntityType("EntityId-1");
+ assertNotNull(activeInventoryNode.getEntityType());
+ assertNotNull(activeInventoryNode.dumpNodeTree(true));
+ assertNotNull(activeInventoryNode.getProcessingErrorCauses());
+ assertNull(activeInventoryNode.calculateEditAttributeUri("Invalid-link"));
+ assertNull(activeInventoryNode.calculateEditAttributeUri("aai/v[\\d]/"));
+ activeInventoryNode.processPathedSelfLinkResponse("jsonResp","startNodeType","startNodeResourceKey");
+ activeInventoryNode.processPathedSelfLinkResponse(null,"startNodeType","startNodeResourceKey");
+ activeInventoryNode.processPathedSelfLinkResponse("","startNodeType","startNodeResourceKey");
+
+ }
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/D3VisualizationOutputTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/D3VisualizationOutputTest.java
new file mode 100644
index 0000000..e1b9931
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/D3VisualizationOutputTest.java
@@ -0,0 +1,46 @@
+package org.onap.aai.sparky.viewandinspect.entity;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.ArrayList;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.onap.aai.sparky.viewandinspect.config.VisualizationConfigs;
+
+public class D3VisualizationOutputTest {
+
+ private D3VisualizationOutput d3visualization;
+ private InlineMessage inlineMessage;
+ private GraphMeta graphMeta;
+ private ArrayList<SparkyGraphNode> nodes;
+ private ArrayList<SparkyGraphLink> links;
+
+ @Before
+ public void init() throws Exception {
+
+ d3visualization = new D3VisualizationOutput();
+ nodes = new ArrayList<SparkyGraphNode>();
+ links = new ArrayList<SparkyGraphLink>();
+ graphMeta = new GraphMeta();
+ inlineMessage = new InlineMessage("level-1","Violation");
+ }
+
+
+ @Test
+ public void updateValues() {
+
+ d3visualization.setInlineMessage(inlineMessage);
+ assertNotNull(d3visualization.getInlineMessage());
+ d3visualization.addLinks(links);
+ d3visualization.addNodes(nodes);
+ d3visualization.setGraphMeta(graphMeta);
+ assertNotNull(d3visualization.getGraphMeta());
+ d3visualization.pegCounter("pegCounter-1");
+
+ }
+
+} \ No newline at end of file
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/EntityEntryTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/EntityEntryTest.java
new file mode 100644
index 0000000..9584d2b
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/EntityEntryTest.java
@@ -0,0 +1,94 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+
+package org.onap.aai.sparky.viewandinspect.entity;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.io.IOException;
+import java.security.NoSuchAlgorithmException;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.onap.aai.sparky.viewandinspect.entity.EntityEntry;
+
+/**
+ * The Class EntityEntryTest.
+ */
+@RunWith(MockitoJUnitRunner.class)
+public class EntityEntryTest {
+
+ /**
+ * Inits the.
+ *
+ * @throws Exception the exception
+ */
+ @Before
+ public void init() throws Exception {}
+
+ /**
+ * Validate basic construction.
+ *
+ * @throws NoSuchAlgorithmException the no such algorithm exception
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ @Test
+ public void validateBasicConstruction() throws NoSuchAlgorithmException, IOException {
+
+ EntityEntry entityEntry = new EntityEntry();
+
+ entityEntry.setEntityType("ShinyEntityType");
+ entityEntry.setEntityPrimaryKeyValue("primary_key_value");
+ entityEntry.setSearchTags("t1 t2 t3");
+ entityEntry.setEntityId("Id-1");
+
+ assertEquals("ShinyEntityType", entityEntry.getEntityType());
+ assertEquals("primary_key_value", entityEntry.getEntityPrimaryKeyValue());
+ assertEquals("t1 t2 t3", entityEntry.getSearchTags());
+ assertEquals("Id-1",entityEntry.getEntityId());
+ assertNotNull(entityEntry.toString());
+
+ }
+
+ @Test
+ public void nullEntry() throws NoSuchAlgorithmException, IOException {
+
+ EntityEntry nullEntityEntry = new EntityEntry();
+
+ nullEntityEntry.setEntityType(null);
+ nullEntityEntry.setEntityPrimaryKeyValue(null);
+ nullEntityEntry.setSearchTags(null);
+ nullEntityEntry.setEntityId(null);
+
+ assertNotNull(nullEntityEntry.toString());
+
+ }
+
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/GraphMetaTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/GraphMetaTest.java
new file mode 100644
index 0000000..bd4e454
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/GraphMetaTest.java
@@ -0,0 +1,61 @@
+package org.onap.aai.sparky.viewandinspect.entity;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+
+import org.junit.Before;
+import org.junit.Test;
+import org.onap.aai.sparky.viewandinspect.EntityTypeAggregation;
+
+import com.fasterxml.jackson.databind.node.JsonNodeFactory;
+
+public class GraphMetaTest {
+
+ private GraphMeta graphMeta;
+ private EntityTypeAggregation entitySummary;
+ private com.fasterxml.jackson.databind.JsonNode aaiEntityNodeDescriptors;
+
+
+ @Before
+ public void init() throws Exception {
+
+ graphMeta = new GraphMeta();
+ entitySummary = new EntityTypeAggregation();
+ aaiEntityNodeDescriptors = JsonNodeFactory.instance.objectNode();
+
+ }
+
+
+ @Test
+ public void updateValues() {
+
+ graphMeta.setEntitySummary(entitySummary);
+ assertNotNull(graphMeta.getEntitySummary());
+ graphMeta.setAaiEntityNodeDescriptors(aaiEntityNodeDescriptors);
+ assertNotNull(graphMeta.getAaiEntityNodeDescriptors());
+
+ graphMeta.setNumLinksResolvedSuccessfullyFromCache(3);
+ assertEquals(3,graphMeta.getNumLinksResolvedSuccessfullyFromCache());
+ graphMeta.setNumLinksResolvedSuccessfullyFromServer(25);
+ assertEquals(25,graphMeta.getNumLinksResolvedSuccessfullyFromServer());
+ graphMeta.setNumLinkResolveFailed(3);
+ assertEquals(3,graphMeta.getNumLinkResolveFailed());
+ graphMeta.setNumNodes(25);
+ assertEquals(25,graphMeta.getNumNodes());
+ graphMeta.setNumLinks(3);
+ assertEquals(3,graphMeta.getNumLinks());
+ graphMeta.setRenderTimeInMs(25);
+ assertEquals(25,graphMeta.getRenderTimeInMs());
+ assertNotNull(graphMeta.toString());
+
+ graphMeta.setEntitySummary(null);
+ assertNull(graphMeta.getEntitySummary());
+ graphMeta.setAaiEntityNodeDescriptors(null);
+ assertNull(graphMeta.getAaiEntityNodeDescriptors());
+ assertNotNull(graphMeta.toString());
+
+ }
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/GraphRequestTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/GraphRequestTest.java
new file mode 100644
index 0000000..7eebb23
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/GraphRequestTest.java
@@ -0,0 +1,61 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+
+package org.onap.aai.sparky.viewandinspect.entity;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.onap.aai.sparky.viewandinspect.entity.GraphRequest;
+
+public class GraphRequestTest {
+
+ private GraphRequest graphRequest;
+
+ @Before
+ public void init() throws Exception {
+ graphRequest = new GraphRequest();
+
+ }
+
+ @Test
+ public void updateValues() {
+
+ graphRequest.setHashId("364c836b7f4c0d2a5b917693719741fa5e576b3da818a");
+ assertNotNull(graphRequest.getHashId());
+ graphRequest.setIncludeGraphMeta(true);
+ assertTrue(graphRequest.isIncludeGraphMeta());
+ assertNotNull(graphRequest.toString());
+ graphRequest.setHashId(null);
+ assertNull(graphRequest.getHashId());
+ assertNotNull(graphRequest.toString());
+
+
+ }
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/InlineMessageTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/InlineMessageTest.java
new file mode 100644
index 0000000..eebc821
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/InlineMessageTest.java
@@ -0,0 +1,55 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+
+package org.onap.aai.sparky.viewandinspect.entity;
+
+import static org.junit.Assert.assertNotNull;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.onap.aai.sparky.viewandinspect.entity.InlineMessage;
+
+public class InlineMessageTest {
+
+ private InlineMessage inlineMsg;
+
+ @Before
+ public void init() throws Exception {
+ inlineMsg = new InlineMessage("InlineMessage1","InlineMessage2");
+
+ }
+
+ @Test
+ public void successfulInitializationAndUpdate() {
+
+ inlineMsg.setLevel("Level-1");
+ assertNotNull(inlineMsg.getLevel());
+ inlineMsg.setMessage("InlineMessage3");
+ assertNotNull(inlineMsg.getMessage());
+ assertNotNull(inlineMsg.toString());
+ }
+
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/JsonNodeLinkTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/JsonNodeLinkTest.java
new file mode 100644
index 0000000..86b9014
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/JsonNodeLinkTest.java
@@ -0,0 +1,57 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+
+package org.onap.aai.sparky.viewandinspect.entity;
+/*
+import static org.junit.Assert.assertNotNull;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.onap.aai.sparky.viewandinspect.entity.JsonNodeLink;
+
+public class JsonNodeLinkTest {
+
+ private JsonNodeLink jsonNodeLink;
+
+ @Before
+ public void init() throws Exception {
+ jsonNodeLink = new JsonNodeLink();
+
+ }
+
+ @Test
+ public void updateValues() {
+
+ jsonNodeLink.setId("ID-1");
+ assertNotNull(jsonNodeLink.getId());
+ jsonNodeLink.setSource("SourceSet");
+ assertNotNull(jsonNodeLink.getSource());
+ jsonNodeLink.setTarget("targetSet");
+ assertNotNull(jsonNodeLink.getTarget());
+ assertNotNull(jsonNodeLink.toString());
+ }
+
+}
+*/ \ No newline at end of file
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/NodeDebugTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/NodeDebugTest.java
new file mode 100644
index 0000000..b8450be
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/NodeDebugTest.java
@@ -0,0 +1,57 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+
+package org.onap.aai.sparky.viewandinspect.entity;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.onap.aai.sparky.viewandinspect.entity.NodeDebug;
+
+public class NodeDebugTest {
+
+
+
+ private NodeDebug nodeDebug;
+
+ @Before
+ public void init() throws Exception {
+ nodeDebug = new NodeDebug();
+
+ }
+
+ @Test
+ public void updateValues() {
+
+ nodeDebug.setProcessingErrorCauses("NullPointerException");
+ assertNotNull(nodeDebug.getProcessingErrorCauses());
+ nodeDebug.setProcessingError(true);
+ assertTrue(nodeDebug.isProcessingError());
+ nodeDebug.setMaxTraversalDepthReached(true);
+ assertTrue(nodeDebug.isMaxTraversalDepthReached());
+ }
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/NodeMetaTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/NodeMetaTest.java
new file mode 100644
index 0000000..7ebe3c6
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/NodeMetaTest.java
@@ -0,0 +1,88 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+
+package org.onap.aai.sparky.viewandinspect.entity;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.onap.aai.sparky.viewandinspect.config.VisualizationConfigs;
+import org.onap.aai.sparky.viewandinspect.enumeration.NodeProcessingState;
+
+public class NodeMetaTest {
+
+ private NodeMeta nodeMeta;
+ private NodeProcessingState nodeProcessingState;
+ private NodeDebug nodeDebug;
+ private VisualizationConfigs visualizationConfigs;
+
+ @Before
+ public void init() throws Exception {
+ this.visualizationConfigs = new VisualizationConfigs();
+ nodeMeta = new NodeMeta(visualizationConfigs);
+ nodeDebug = new NodeDebug();
+
+ }
+
+ @Test
+ public void updateValues() {
+
+ nodeMeta.setAtMaxDepth(true);
+ assertTrue(nodeMeta.isAtMaxDepth());
+ nodeMeta.setSelfLinkResolved(true);
+ assertTrue(nodeMeta.isSelfLinkResolved());
+ nodeMeta.setProcessingState(nodeProcessingState.READY);
+ assertNotNull(nodeMeta.getProcessingState());
+ nodeMeta.setProcessingErrorOccurred(true);
+ assertTrue(nodeMeta.isProcessingErrorOccurred());
+ nodeMeta.setHasNeighbors(true);
+ assertTrue(nodeMeta.isHasNeighbors());
+ nodeMeta.setNeighborsProcessed(true);
+ assertTrue(nodeMeta.isNeighborsProcessed());
+ nodeMeta.setNodeDepth(3);
+ assertEquals(3,nodeMeta.getNodeDepth());
+ nodeMeta.setNodeDebug(nodeDebug);
+ assertNotNull(nodeMeta.getNodeDebug());
+ nodeMeta.setClassName("generalNodeClass");
+ assertNotNull(nodeMeta.getClassName());
+ nodeMeta.setNumInboundNeighbors(34);
+ assertEquals(34,nodeMeta.getNumInboundNeighbors());
+ nodeMeta.setNumOutboundNeighbors(43);
+ assertEquals(43,nodeMeta.getNumOutboundNeighbors());
+ nodeMeta.setSelfLinkResponseTimeInMs(43);
+ assertEquals(43,nodeMeta.getSelfLinkResponseTimeInMs());
+ nodeMeta.setNodeIssue(true);
+ assertTrue(nodeMeta.isNodeIssue());
+ nodeMeta.setNodeValidated(true);
+ assertTrue(nodeMeta.isNodeValidated());
+ nodeMeta.setSearchTarget(true);
+ assertTrue(nodeMeta.isSearchTarget());
+
+
+ }
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/NodeProcessingTransactionTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/NodeProcessingTransactionTest.java
new file mode 100644
index 0000000..a50ea3b
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/NodeProcessingTransactionTest.java
@@ -0,0 +1,62 @@
+package org.onap.aai.sparky.viewandinspect.entity;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.ArrayList;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.onap.aai.restclient.client.OperationResult;
+import org.onap.aai.sparky.config.oxm.OxmEntityLookup;
+import org.onap.aai.sparky.viewandinspect.config.VisualizationConfigs;
+
+public class NodeProcessingTransactionTest {
+
+
+ private NodeProcessingTransaction nodeProcessingTransaction;
+ private ActiveInventoryNode activeInventoryNode;
+ private ArrayList<String> lst = new ArrayList<String>();
+ private OperationResult opResult;
+ private VisualizationConfigs visualConfig;
+ private OxmEntityLookup oxmEntityLookup;
+
+ @Before
+ public void init() throws Exception {
+
+ visualConfig = new VisualizationConfigs();
+ oxmEntityLookup = new OxmEntityLookup();
+ opResult = new OperationResult();
+ activeInventoryNode = new ActiveInventoryNode(visualConfig,oxmEntityLookup);
+ nodeProcessingTransaction = new NodeProcessingTransaction();
+
+ }
+
+
+ @Test
+ public void updateValues() {
+
+ nodeProcessingTransaction.setRequestParameters("");
+ assertNotNull(nodeProcessingTransaction.getRequestParameters());
+ nodeProcessingTransaction.setProcessingNode(activeInventoryNode);
+ assertNotNull(nodeProcessingTransaction.getProcessingNode());
+ nodeProcessingTransaction.setOpResult(opResult);
+ assertNotNull(nodeProcessingTransaction.getOpResult());
+ assertNull(nodeProcessingTransaction.getSelfLink());
+ assertNotNull(nodeProcessingTransaction.getSelfLinkWithModifiers());
+ assertTrue(nodeProcessingTransaction.processingErrorOccurred());
+ assertNotNull(nodeProcessingTransaction.toString());
+ nodeProcessingTransaction.setProcessingNode(null);
+ assertNull(nodeProcessingTransaction.getProcessingNode());
+ nodeProcessingTransaction.setOpResult(null);
+ assertNull(nodeProcessingTransaction.getOpResult());
+ assertNull(nodeProcessingTransaction.getSelfLink());
+ assertNull(nodeProcessingTransaction.getSelfLinkWithModifiers());
+ assertNotNull(nodeProcessingTransaction.toString());
+
+ }
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/QueryParamsTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/QueryParamsTest.java
new file mode 100644
index 0000000..d1bd60b
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/QueryParamsTest.java
@@ -0,0 +1,56 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+
+package org.onap.aai.sparky.viewandinspect.entity;
+
+
+import static org.junit.Assert.assertNotNull;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.onap.aai.sparky.viewandinspect.entity.QueryParams;
+
+public class QueryParamsTest {
+
+ private QueryParams parameterQuery;
+
+ @Before
+ public void init() throws Exception {
+ parameterQuery = new QueryParams();
+
+ }
+
+ @Test
+ public void updateValues() {
+
+ parameterQuery.setSearchTargetPrimaryKeyValues("Internet Network");
+ assertNotNull(parameterQuery.getSearchTargetPrimaryKeyValues());
+ parameterQuery.setSearchTargetNodeId("Internet Network");
+ assertNotNull(parameterQuery.getSearchTargetNodeId());
+ }
+
+
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/QueryRequestTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/QueryRequestTest.java
new file mode 100644
index 0000000..fca4051
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/QueryRequestTest.java
@@ -0,0 +1,54 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+
+package org.onap.aai.sparky.viewandinspect.entity;
+
+import static org.junit.Assert.assertNotNull;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.onap.aai.sparky.viewandinspect.entity.QueryRequest;
+
+public class QueryRequestTest {
+
+ private QueryRequest requestQuery;
+
+ @Before
+ public void init() throws Exception {
+ requestQuery = new QueryRequest();
+
+ }
+
+ @Test
+ public void updateValues() {
+
+ requestQuery.setHashId("claymore-service-tree");
+ assertNotNull(requestQuery.getHashId());
+ assertNotNull(requestQuery.toString());
+ requestQuery.setHashId(null);
+ assertNotNull(requestQuery.toString());
+ }
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/RelatedToPropertyTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/RelatedToPropertyTest.java
new file mode 100644
index 0000000..48a724b
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/RelatedToPropertyTest.java
@@ -0,0 +1,54 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+
+package org.onap.aai.sparky.viewandinspect.entity;
+
+import static org.junit.Assert.assertNotNull;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.onap.aai.sparky.viewandinspect.entity.RelatedToProperty;
+
+public class RelatedToPropertyTest {
+
+ private RelatedToProperty relatedToProperty;
+
+ @Before
+ public void init() throws Exception {
+ relatedToProperty = new RelatedToProperty();
+
+ }
+
+ @Test
+ public void successfulInitializationAndUpdate() {
+
+ relatedToProperty.setPropertyKey("PropertyKey-1");
+ assertNotNull(relatedToProperty.getPropertyKey());
+ relatedToProperty.setPropertyValue("PropertyValue-1");
+ assertNotNull(relatedToProperty.getPropertyValue());
+ assertNotNull(relatedToProperty.toString());
+ }
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/RelationshipDataTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/RelationshipDataTest.java
new file mode 100644
index 0000000..e20e720
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/RelationshipDataTest.java
@@ -0,0 +1,54 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+
+package org.onap.aai.sparky.viewandinspect.entity;
+
+
+import static org.junit.Assert.assertNotNull;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.onap.aai.sparky.viewandinspect.entity.RelationshipData;
+
+public class RelationshipDataTest {
+
+ private RelationshipData relationshipData;
+
+ @Before
+ public void init() throws Exception {
+ relationshipData = new RelationshipData();
+
+ }
+
+ @Test
+ public void updateValues() {
+
+ relationshipData.setRelationshipKey("RelationshipKey");
+ assertNotNull(relationshipData.getRelationshipKey());
+ relationshipData.setRelationshipValue("RelationshipValues");
+ assertNotNull(relationshipData.getRelationshipValue());
+ assertNotNull(relationshipData.toString());
+ }
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/RelationshipListTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/RelationshipListTest.java
new file mode 100644
index 0000000..3e81dbf
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/RelationshipListTest.java
@@ -0,0 +1,32 @@
+package org.onap.aai.sparky.viewandinspect.entity;
+
+import static org.junit.Assert.assertNotNull;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class RelationshipListTest {
+
+
+ private Relationship[] relationship;
+ private RelationshipList relationshipList;
+
+
+ @Before
+ public void init() throws Exception {
+
+ relationship = new Relationship[] {};
+ relationshipList = new RelationshipList();
+
+ }
+
+
+ @Test
+ public void updateValues() {
+
+ relationshipList.setRelationshipList(relationship);
+ assertNotNull(relationshipList.getRelationshipList());
+ assertNotNull(relationshipList.toString());
+ }
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/RelationshipTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/RelationshipTest.java
new file mode 100644
index 0000000..2aeffe9
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/RelationshipTest.java
@@ -0,0 +1,43 @@
+package org.onap.aai.sparky.viewandinspect.entity;
+
+import static org.junit.Assert.assertNotNull;
+
+
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class RelationshipTest {
+
+
+ private Relationship relationship;
+ private RelationshipData[] relationshipData;
+ private RelatedToProperty[] relatedToProperty;
+
+
+ @Before
+ public void init() throws Exception {
+
+ relationshipData = new RelationshipData[] {};
+ relatedToProperty = new RelatedToProperty[] {};
+ relationship = new Relationship();
+
+ }
+
+
+ @Test
+ public void updateValues() {
+
+ relationship.setRelatedLink("");
+ assertNotNull(relationship.getRelatedLink());
+ relationship.setRelatedTo("selectedsearchedNodeClass");
+ assertNotNull(relationship.getRelatedTo());
+ relationship.setRelationshipData(relationshipData);
+ assertNotNull(relationship.getRelationshipData());
+ relationship.setRelatedToProperty(relatedToProperty);
+ assertNotNull(relationship.getRelatedToProperty());
+ assertNotNull(relationship.toString());
+
+ }
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/SearchResponseTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/SearchResponseTest.java
new file mode 100644
index 0000000..6c08c8c
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/SearchResponseTest.java
@@ -0,0 +1,52 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+
+package org.onap.aai.sparky.viewandinspect.entity;
+
+import static org.junit.Assert.assertNotNull;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.onap.aai.sparky.search.SearchResponse;
+
+public class SearchResponseTest {
+
+ private SearchResponse searchResponse;
+
+ @Before
+ public void init() throws Exception {
+ searchResponse = new SearchResponse();
+
+ }
+
+ @Test
+ public void updateValues() {
+
+ assertNotNull(searchResponse.toString());
+ searchResponse.setSuggestions(null);
+ assertNotNull(searchResponse.toString());
+
+ }
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/SearchableEntityListTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/SearchableEntityListTest.java
new file mode 100644
index 0000000..d2c6513
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/SearchableEntityListTest.java
@@ -0,0 +1,44 @@
+package org.onap.aai.sparky.viewandinspect.entity;
+
+import static org.junit.Assert.assertNotNull;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.onap.aai.sparky.sync.entity.SearchableEntity;
+
+public class SearchableEntityListTest {
+
+
+ private SearchableEntityList searchableEntityList;
+ private ArrayList<SearchableEntity> searchable;
+ private SearchableEntity entity;
+ private HashMap<String,String> searchTags;
+
+ @Before
+ public void init() throws Exception {
+
+ searchable = new ArrayList<SearchableEntity>();
+ entity = new SearchableEntity();
+ searchableEntityList = new SearchableEntityList();
+ searchTags = new HashMap<String,String>();
+
+ }
+
+
+ @SuppressWarnings("static-access")
+ @Test
+ public void updateValues() {
+
+ searchableEntityList.setEntities(searchable);
+ assertNotNull(searchableEntityList.getEntities());
+ searchableEntityList.addEntity(entity);
+ searchableEntityList.buildEntity("","","",searchTags);
+ assertNotNull(searchableEntityList.getSearchTagMap("tagtagtag"));
+ assertNotNull(searchableEntityList.toString());
+ }
+
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/SelfLinkDeterminationTransactionTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/SelfLinkDeterminationTransactionTest.java
new file mode 100644
index 0000000..8dd862a
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/SelfLinkDeterminationTransactionTest.java
@@ -0,0 +1,68 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+
+package org.onap.aai.sparky.viewandinspect.entity;
+
+import static org.junit.Assert.assertNotNull;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.onap.aai.restclient.client.OperationResult;
+import org.onap.aai.sparky.config.oxm.OxmEntityLookup;
+import org.onap.aai.sparky.viewandinspect.config.VisualizationConfigs;
+
+
+public class SelfLinkDeterminationTransactionTest {
+
+ private SelfLinkDeterminationTransaction selfLinkDeterminationTransaction;
+ private OperationResult opResult;
+ private ActiveInventoryNode activeInventoryNode;
+ private VisualizationConfigs visualizationConfigs;
+ private OxmEntityLookup oxmEntityLookup;
+
+ @Before
+ public void init() throws Exception {
+ selfLinkDeterminationTransaction = new SelfLinkDeterminationTransaction();
+ opResult = new OperationResult();
+ oxmEntityLookup = new OxmEntityLookup();
+ activeInventoryNode = new ActiveInventoryNode(visualizationConfigs, oxmEntityLookup);
+
+ }
+
+ @Test
+ public void updateValues() {
+
+ selfLinkDeterminationTransaction.setParentNodeId("ID-1");
+ assertNotNull(selfLinkDeterminationTransaction.getParentNodeId());
+ selfLinkDeterminationTransaction.setOpResult(opResult);
+ assertNotNull(selfLinkDeterminationTransaction.getOpResult());
+ selfLinkDeterminationTransaction.setQueryString("QueryString");
+ assertNotNull(selfLinkDeterminationTransaction.getQueryString());
+ selfLinkDeterminationTransaction.setEntityUrl("EntityURL");
+ assertNotNull(selfLinkDeterminationTransaction.getEntityUrl());
+ selfLinkDeterminationTransaction.setNewNode(activeInventoryNode);
+ assertNotNull(selfLinkDeterminationTransaction.getNewNode());
+ }
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/SparkyGraphLinkTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/SparkyGraphLinkTest.java
new file mode 100644
index 0000000..20d6825
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/SparkyGraphLinkTest.java
@@ -0,0 +1,56 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+
+package org.onap.aai.sparky.viewandinspect.entity;
+
+import static org.junit.Assert.assertNotNull;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.onap.aai.sparky.viewandinspect.entity.SparkyGraphLink;
+
+public class SparkyGraphLinkTest {
+
+ private SparkyGraphLink jsonNodeLink;
+
+ @Before
+ public void init() throws Exception {
+ jsonNodeLink = new SparkyGraphLink();
+
+ }
+
+ @Test
+ public void updateValues() {
+
+ jsonNodeLink.setId("ID-1");
+ assertNotNull(jsonNodeLink.getId());
+ jsonNodeLink.setSource("SourceSet");
+ assertNotNull(jsonNodeLink.getSource());
+ jsonNodeLink.setTarget("targetSet");
+ assertNotNull(jsonNodeLink.getTarget());
+ assertNotNull(jsonNodeLink.toString());
+ }
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/SparkyGraphNodeTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/SparkyGraphNodeTest.java
new file mode 100644
index 0000000..a9a10c5
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/SparkyGraphNodeTest.java
@@ -0,0 +1,81 @@
+package org.onap.aai.sparky.viewandinspect.entity;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import java.util.HashMap;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.onap.aai.sparky.config.oxm.OxmEntityLookup;
+import org.onap.aai.sparky.subscription.config.SubscriptionConfig;
+import org.onap.aai.sparky.viewandinspect.config.VisualizationConfigs;
+
+public class SparkyGraphNodeTest {
+
+
+ private SparkyGraphNode graphNode;
+ private ActiveInventoryNode activeInventoryNode;
+ private SubscriptionConfig subscriptionConfigs;
+ private VisualizationConfigs visualConfigs;
+ private OxmEntityLookup oxmEntityLookup;
+ private HashMap<String,String> itemProperties;
+ private NodeMeta nodeMeta;
+
+ @Before
+ public void init() throws Exception {
+
+ oxmEntityLookup = new OxmEntityLookup();
+ visualConfigs = new VisualizationConfigs();
+ subscriptionConfigs = new SubscriptionConfig();
+ nodeMeta = new NodeMeta(visualConfigs);
+ itemProperties = new HashMap<String,String>();
+ activeInventoryNode = new ActiveInventoryNode(visualConfigs,oxmEntityLookup);
+
+ graphNode = new SparkyGraphNode(activeInventoryNode,visualConfigs,subscriptionConfigs);
+
+ }
+
+
+ @Test
+ public void updateValues() {
+
+ graphNode.setId("graphID");
+ assertNotNull(graphNode.getId());
+ assertFalse(graphNode.isRootNode());
+ graphNode.setItemNameKey("selectedsearchedNodeClass");
+ assertNotNull(graphNode.getItemNameKey());
+ graphNode.setItemNameValue("generalNodeClass");
+ assertNotNull(graphNode.getItemNameValue());
+ graphNode.setResourceKey("searchedNodeClass");
+ assertNotNull(graphNode.getResourceKey());
+ graphNode.setItemType("/etc/aaiEntityNodeDescriptors.json");
+ assertNotNull(graphNode.getItemType());
+
+ graphNode.setItemProperties(itemProperties);
+ assertNotNull(graphNode.getItemProperties());
+ graphNode.setNodeMeta(nodeMeta);
+ assertNotNull(graphNode.getNodeMeta());
+ assertNotNull(graphNode.toString());
+
+ graphNode.setId(null);
+ assertNull(graphNode.getId());
+ assertFalse(graphNode.isRootNode());
+ graphNode.setItemNameKey(null);
+ assertNull(graphNode.getItemNameKey());
+ graphNode.setItemNameValue(null);
+ assertNull(graphNode.getItemNameValue());
+ graphNode.setResourceKey(null);
+ assertNull(graphNode.getResourceKey());
+ graphNode.setItemType(null);
+ assertNull(graphNode.getItemType());
+ graphNode.setItemProperties(null);
+ assertNull(graphNode.getItemProperties());
+ graphNode.setNodeMeta(null);
+ assertNull(graphNode.getNodeMeta());
+ assertNotNull(graphNode.toString());
+
+ }
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/services/BaseVisualizationContextTest.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/services/BaseVisualizationContextTest.java
new file mode 100644
index 0000000..09ca3a3
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/services/BaseVisualizationContextTest.java
@@ -0,0 +1,273 @@
+package org.onap.aai.sparky.viewandinspect.services;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.security.SecureRandom;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ExecutorService;
+
+import org.hamcrest.Matcher;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Matchers;
+import org.mockito.Mockito;
+import org.onap.aai.cl.api.Logger;
+import org.onap.aai.cl.eelf.LoggerFactory;
+import org.onap.aai.cl.mdc.MdcContext;
+import org.onap.aai.restclient.client.OperationResult;
+import org.onap.aai.sparky.config.oxm.OxmEntityLookup;
+import org.onap.aai.sparky.config.oxm.OxmModelLoader;
+import org.onap.aai.sparky.config.oxm.OxmModelProcessor;
+import org.onap.aai.sparky.dal.ActiveInventoryAdapter;
+import org.onap.aai.sparky.dal.rest.config.RestEndpointConfig;
+import org.onap.aai.sparky.sync.entity.SearchableEntity;
+import org.onap.aai.sparky.util.NodeUtils;
+import org.onap.aai.sparky.util.StringCollectionContainsMatcher;
+import org.onap.aai.sparky.util.TestResourceLoader;
+import org.onap.aai.sparky.viewandinspect.config.VisualizationConfigs;
+import org.onap.aai.sparky.viewandinspect.entity.ActiveInventoryNode;
+import org.onap.aai.sparky.viewandinspect.entity.QueryParams;
+import org.onap.aai.sparky.viewandinspect.enumeration.NodeProcessingState;
+
+
+public class BaseVisualizationContextTest {
+
+ private static SecureRandom secureRandom = new SecureRandom();
+ private static Logger LOG = LoggerFactory.getInstance().getLogger(BaseVisualizationContextTest.class);
+
+ private BaseVisualizationContext baseVisualizationContext;
+ private ExecutorService aaiExecutorService;
+ private VisualizationConfigs visualizationConfig;
+
+ private OxmEntityLookup oxmEntityLookup;
+
+ private ActiveInventoryAdapter aaiAdapter;
+ private RestEndpointConfig aaiRestEndPointConfig;
+
+ @Before
+ public void init() throws Exception {
+
+ aaiExecutorService = NodeUtils.createNamedExecutor("SLNC-WORKER", 5, LOG);
+ visualizationConfig = new VisualizationConfigs();
+
+ ArrayList<String> shallowEntities = new ArrayList<String>();
+ shallowEntities.add("cloud-region");
+
+ visualizationConfig.setShallowEntities(shallowEntities);
+ visualizationConfig.setMaxSelfLinkTraversalDepth(2);
+
+ oxmEntityLookup = new OxmEntityLookup();
+
+ aaiAdapter = Mockito.mock(ActiveInventoryAdapter.class);
+
+
+ Set<OxmModelProcessor> processors = new HashSet<OxmModelProcessor>();
+
+ processors.add(oxmEntityLookup);
+
+
+ OxmModelLoader oxmModelLoader = new OxmModelLoader(-1, processors);
+ oxmModelLoader.loadLatestOxmModel();
+
+ aaiRestEndPointConfig = new RestEndpointConfig();
+ aaiRestEndPointConfig.setNumRequestRetries(5);
+
+ Mockito.when(aaiAdapter.getEndpointConfig()).thenReturn(aaiRestEndPointConfig);
+
+ MdcContext.initialize("" + secureRandom.nextLong(), "AAI-UI", "", "partner-name",
+ "localhost:4242");
+
+ // all our resources are prefixed already, so the repairSelfLink shouldn't do anything to the link
+ Mockito.when(aaiAdapter.repairSelfLink(Matchers.contains(""))).thenReturn("");
+
+
+ }
+
+ private Matcher<List<String>> listContainsValue(String expectedValue) {
+ return new StringCollectionContainsMatcher(expectedValue);
+ }
+
+
+ @Test
+ public void validateBasicConstruction() throws Exception {
+
+ long contextId = secureRandom.nextLong();
+
+ baseVisualizationContext = new BaseVisualizationContext(contextId, aaiAdapter,
+ aaiExecutorService, visualizationConfig, oxmEntityLookup);
+
+ assertEquals(contextId, baseVisualizationContext.getContextId());
+
+ }
+
+ @Test
+ public void validateSmallGraphAssembly() throws Exception {
+
+ /**
+ * We have a tiny graph that we will validate assembly of:
+ *
+ * <li>customer -> tenant
+ * <li>customer -> service-subscription
+ * <li>service-subscription -> service-instance-1
+ * <li>service-subscription -> service-instance-2
+ *
+ * At the end of this success path, we should have 5 nodes in the node cache. Once we have this
+ * flow we can experiment with error paths involving resource download failures to ensure graph
+ * nodes are in the correct state and that expected nodes are successfully represented in the
+ * cache.
+ */
+
+ long contextId = secureRandom.nextLong();
+
+ baseVisualizationContext = new BaseVisualizationContext(contextId, aaiAdapter,
+ aaiExecutorService, visualizationConfig, oxmEntityLookup);
+
+ SearchableEntity searchableEntity = new SearchableEntity();
+ String customerSelfLink =
+ "https://server.proxy:8443/aai/v11/business/customers/customer/customer-4";
+ String customerNodeId = NodeUtils.generateUniqueShaDigest(customerSelfLink);
+
+ searchableEntity.setId(customerNodeId);
+ searchableEntity.setEntityType("customer");
+ searchableEntity.setEntityPrimaryKeyValue("customer-4");
+ searchableEntity.setLink(customerSelfLink);
+
+ QueryParams queryParams = new QueryParams();
+ queryParams.setSearchTargetNodeId(customerNodeId);
+ queryParams.setSearchTargetPrimaryKeyValues("customer-4");
+
+ // aai customer resource dip
+
+ Mockito
+ .when(aaiAdapter.queryActiveInventoryWithRetries(
+ Matchers.contains("customer-4"), Mockito.anyString(),
+ Mockito.anyInt()))
+ .thenReturn(new OperationResult(200, TestResourceLoader.getTestResourceDataJson(
+ "/sync/aai/aai-resources/customer/customer-4.json")));
+
+ // aai tenant resource dip
+
+ Mockito
+ .when(aaiAdapter.queryActiveInventoryWithRetries(
+ Matchers.contains("tenant/tenant-1"), Mockito.anyString(),
+ Mockito.anyInt()))
+ .thenReturn(new OperationResult(200, TestResourceLoader.getTestResourceDataJson(
+ "/sync/aai/aai-resources/tenant/tenant-1.json")));
+
+ // generic-queries for service-subscription
+
+ Mockito
+ .when(aaiAdapter.getGenericQueryForSelfLink(Matchers.contains("service-subscription"),
+ Matchers.argThat(listContainsValue("service-subscription.service-type:service-subscription-2"))))
+ .thenReturn(
+ "https://server.proxy:8443/aai/v11/search/generic-query/service-subscription-2");
+
+ Mockito
+ .when(aaiAdapter.queryActiveInventoryWithRetries(
+ Matchers.contains("generic-query/service-subscription-2"), Mockito.anyString(), Mockito.anyInt()))
+ .thenReturn(new OperationResult(200, TestResourceLoader
+ .getTestResourceDataJson("/sync/aai/aai-traversal/generic-query/service-subscription/service-subscription-2.json")));
+
+ // generic-queries for service-instance-1
+
+ Mockito
+ .when(aaiAdapter.getGenericQueryForSelfLink(Matchers.contains("service-instance"),
+ Matchers.argThat(
+ listContainsValue("service-instance-id:service-instance-54"))))
+ .thenReturn(
+ "https://server.proxy:8443/aai/v11/search/generic-query/service-instance-id/service-instance-54");
+
+ Mockito
+ .when(aaiAdapter.queryActiveInventoryWithRetries(
+ Matchers
+ .contains("generic-query/service-instance-id/service-instance-54"),
+ Mockito.anyString(), Mockito.anyInt()))
+ .thenReturn(new OperationResult(200, TestResourceLoader.getTestResourceDataJson(
+ "/sync/aai/aai-traversal/generic-query/service-instance/service-instance-54.json")));
+
+ // generic-queries for service-instance-2
+
+ Mockito
+ .when(aaiAdapter.getGenericQueryForSelfLink(Matchers.contains("service-instance"),
+ Matchers.argThat(
+ listContainsValue("service-instance-id:service-instance-55"))))
+ .thenReturn(
+ "https://server.proxy:8443/aai/v11/search/generic-query/service-instance-id/service-instance-55");
+
+ Mockito
+ .when(aaiAdapter.queryActiveInventoryWithRetries(
+ Matchers
+ .contains("generic-query/service-instance-id/service-instance-55"),
+ Mockito.anyString(), Mockito.anyInt()))
+ .thenReturn(new OperationResult(200, TestResourceLoader.getTestResourceDataJson(
+ "/sync/aai/aai-traversal/generic-query/service-instance/service-instance-55.json")));
+
+
+
+ // start the test
+
+ baseVisualizationContext.processSelfLinks(searchableEntity, queryParams);
+
+ /*
+ * validation can be in the form of validating nodes + relationships from the node cache
+ * baseVisualizationContext.getNodeCache();
+ */
+
+ Map<String, ActiveInventoryNode> nodeCache = baseVisualizationContext.getNodeCache();
+
+ assertEquals(5, nodeCache.size());
+ assertNotNull(nodeCache.get(customerNodeId));
+ assertEquals("customer", nodeCache.get(customerNodeId).getEntityType());
+
+ // verify node collection nodes
+
+ ActiveInventoryNode customerNode = nodeCache.get("da4101ad19b3c380a1c12ffeda8ab390e1489fb4a22a392c9a1939db63c3dec5");
+ ActiveInventoryNode ssNode = nodeCache.get("f4ceaf19459993c4fc9438a7579dd20d786109f4455e38682c579045b7ae615e");
+ ActiveInventoryNode tenantNode = nodeCache.get("4735439b29e446b339535668238076e4b392eaa3eec218936e12f735179bc55e");
+ ActiveInventoryNode s1 = nodeCache.get("f975ab453b142197af5d0173e0a9cf2aa22d10502f8ad655c8d17de81b066e8f");
+ ActiveInventoryNode s2 = nodeCache.get("de77ef8f76dd6f19662b163527ff839891b9596cac655e3143fdd7ad39e2e4e3");
+
+ assertNotNull( customerNode );
+ assertNotNull( ssNode );
+ assertNotNull( tenantNode );
+ assertNotNull( s1 );
+ assertNotNull( s2 );
+
+ // verify node depths
+
+ assertEquals( 0, customerNode.getNodeDepth() );
+ assertEquals( 1, ssNode.getNodeDepth() );
+
+ /*
+ * I think there is a bug in the way the node depth is represented due to the enforcement of
+ * bidirectional links being disabled. We may have to circle back to this behavior at some point
+ * and re-verify that the behavior works properly.
+ */
+
+ assertEquals( 2, tenantNode.getNodeDepth() );
+ assertEquals( 2, s1.getNodeDepth() );
+ assertEquals( 2, s2.getNodeDepth() );
+
+ // verify node states
+
+ assertEquals( NodeProcessingState.READY, customerNode.getState() );
+ assertEquals( NodeProcessingState.READY, ssNode.getState() );
+
+ /*
+ * these nodes have a NEIGHBORS_UNPROCESSED state because the max traversal depth was hit before
+ * processing all the nested relationships. I think what we should look at is advancing the state
+ * to READY if in fact there are no relationships to process, which I think could be the case
+ * sometimes.
+ */
+ assertEquals( NodeProcessingState.NEIGHBORS_UNPROCESSED, tenantNode.getState() );
+ assertEquals( NodeProcessingState.NEIGHBORS_UNPROCESSED, s1.getState() );
+ assertEquals( NodeProcessingState.NEIGHBORS_UNPROCESSED, s2.getState() );
+
+ }
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/sync/ViewInspectGizmoEntitySynchronizer.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/sync/ViewInspectGizmoEntitySynchronizer.java
new file mode 100644
index 0000000..6d63a8a
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/sync/ViewInspectGizmoEntitySynchronizer.java
@@ -0,0 +1,792 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.viewandinspect.sync;
+
+import static java.util.concurrent.CompletableFuture.supplyAsync;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Deque;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentLinkedDeque;
+import java.util.concurrent.ExecutorService;
+import java.util.function.Supplier;
+
+import org.onap.aai.cl.api.Logger;
+import org.onap.aai.cl.eelf.LoggerFactory;
+import org.onap.aai.cl.mdc.MdcContext;
+import org.onap.aai.restclient.client.OperationResult;
+import org.onap.aai.sparky.config.oxm.OxmEntityContainerLookup;
+import org.onap.aai.sparky.config.oxm.OxmEntityDescriptor;
+import org.onap.aai.sparky.config.oxm.OxmEntityLookup;
+import org.onap.aai.sparky.config.oxm.SearchableEntityLookup;
+import org.onap.aai.sparky.config.oxm.SearchableOxmEntityDescriptor;
+import org.onap.aai.sparky.dal.GizmoAdapter;
+import org.onap.aai.sparky.dal.NetworkTransaction;
+import org.onap.aai.sparky.dal.rest.HttpMethod;
+import org.onap.aai.sparky.logging.AaiUiMsgs;
+import org.onap.aai.sparky.sync.AbstractEntitySynchronizer;
+import org.onap.aai.sparky.sync.IndexSynchronizer;
+import org.onap.aai.sparky.sync.config.ElasticSearchSchemaConfig;
+import org.onap.aai.sparky.sync.config.NetworkStatisticsConfig;
+import org.onap.aai.sparky.sync.entity.MergableEntity;
+import org.onap.aai.sparky.sync.entity.SearchableEntity;
+import org.onap.aai.sparky.sync.entity.SelfLinkDescriptor;
+import org.onap.aai.sparky.sync.enumeration.OperationState;
+import org.onap.aai.sparky.sync.enumeration.SynchronizerState;
+import org.onap.aai.sparky.sync.task.PerformElasticSearchPut;
+import org.onap.aai.sparky.sync.task.PerformElasticSearchRetrieval;
+import org.onap.aai.sparky.sync.task.PerformElasticSearchUpdate;
+import org.onap.aai.sparky.sync.task.PerformGizmoRetrieval;
+import org.onap.aai.sparky.util.NodeUtils;
+import org.slf4j.MDC;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectReader;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+
+/**
+ * The Class SearchableEntitySynchronizer.
+ */
+public class ViewInspectGizmoEntitySynchronizer extends AbstractEntitySynchronizer
+ implements IndexSynchronizer {
+
+ /**
+ * The Class RetrySearchableEntitySyncContainer.
+ */
+ private class RetrySearchableEntitySyncContainer {
+ NetworkTransaction txn;
+ SearchableEntity se;
+
+ /**
+ * Instantiates a new retry searchable entity sync container.
+ *
+ * @param txn the txn
+ * @param se the se
+ */
+ public RetrySearchableEntitySyncContainer(NetworkTransaction txn, SearchableEntity se) {
+ this.txn = txn;
+ this.se = se;
+ }
+
+ public NetworkTransaction getNetworkTransaction() {
+ return txn;
+ }
+
+ public SearchableEntity getSearchableEntity() {
+ return se;
+ }
+ }
+
+ private static final Logger LOG =
+ LoggerFactory.getInstance().getLogger(ViewInspectGizmoEntitySynchronizer.class);
+
+ private boolean allWorkEnumerated;
+ private Deque<SelfLinkDescriptor> selflinks;
+ private Deque<RetrySearchableEntitySyncContainer> retryQueue;
+ private Map<String, Integer> retryLimitTracker;
+ protected ExecutorService esPutExecutor;
+ private OxmEntityLookup oxmEntityLookup;
+ private SearchableEntityLookup searchableEntityLookup;
+ private GizmoAdapter gizmoAdapter;
+ private OxmEntityContainerLookup entityContainerLookup;
+
+ /**
+ * Instantiates a new searchable entity synchronizer.
+ *
+ * @param indexName the index name
+ * @throws Exception the exception
+ */
+ public ViewInspectGizmoEntitySynchronizer(ElasticSearchSchemaConfig schemaConfig,
+ int internalSyncWorkers, int gizmoWorkers, int esWorkers, NetworkStatisticsConfig aaiStatConfig,
+ NetworkStatisticsConfig esStatConfig, OxmEntityLookup oxmEntityLookup,
+ SearchableEntityLookup searchableEntityLookup, OxmEntityContainerLookup entityContainerLookup) throws Exception {
+ super(LOG, "SES", internalSyncWorkers, gizmoWorkers, esWorkers, schemaConfig.getIndexName(),
+ aaiStatConfig, esStatConfig);
+
+ this.oxmEntityLookup = oxmEntityLookup;
+ this.searchableEntityLookup = searchableEntityLookup;
+ this.entityContainerLookup = entityContainerLookup;
+ this.allWorkEnumerated = false;
+ this.selflinks = new ConcurrentLinkedDeque<SelfLinkDescriptor>();
+ this.retryQueue = new ConcurrentLinkedDeque<RetrySearchableEntitySyncContainer>();
+ this.retryLimitTracker = new ConcurrentHashMap<String, Integer>();
+ this.synchronizerName = "Searchable Entity Synchronizer";
+ this.esPutExecutor = NodeUtils.createNamedExecutor("SES-ES-PUT", 5, LOG);
+ this.aaiEntityStats.intializeEntityCounters(
+ searchableEntityLookup.getSearchableEntityDescriptors().keySet());
+ this.esEntityStats.intializeEntityCounters(
+ searchableEntityLookup.getSearchableEntityDescriptors().keySet());
+ this.syncDurationInMs = -1;
+ }
+
+
+
+ public GizmoAdapter getGizmoAdapter() {
+ return gizmoAdapter;
+}
+
+
+
+public void setGizmoAdapter(GizmoAdapter gizmoAdapter) {
+ this.gizmoAdapter = gizmoAdapter;
+}
+
+
+
+/**
+ * Collect all the work.
+ *
+ * @return the operation state
+ */
+ private OperationState collectAllTheWork() {
+ final Map<String, String> contextMap = MDC.getCopyOfContextMap();
+
+ Collection<String> searchableEntityGroups = entityContainerLookup.getSearchableEntityGroups();
+
+ if (searchableEntityGroups.isEmpty()) {
+ LOG.error(AaiUiMsgs.ERROR_LOADING_OXM_SEARCHABLE_ENTITIES);
+ return OperationState.ERROR;
+ }
+
+
+ try {
+
+ /*
+ * launch a parallel async thread to process the documents for each entity-type (to max the
+ * of the configured executor anyway)
+ */
+
+ /*searchableEntityGroups = new ArrayList<String>();
+ searchableEntityGroups.add("pservers");*/
+
+ aaiWorkOnHand.set(searchableEntityGroups.size());
+
+ for (String searchableEntityGroup : searchableEntityGroups) {
+
+ supplyAsync(new Supplier<Void>() {
+
+ @Override
+ public Void get() {
+ MDC.setContextMap(contextMap);
+ OperationResult typeLinksResult = null;
+ try {
+ typeLinksResult = gizmoAdapter.getSelfLinksByEntityType(searchableEntityGroup);
+ aaiWorkOnHand.decrementAndGet();
+ processEntityTypeSelfLinks(typeLinksResult);
+ } catch (Exception exc) {
+
+ exc.printStackTrace();
+ }
+
+ return null;
+ }
+
+ }, aaiExecutor).whenComplete((result, error) -> {
+
+ if (error != null) {
+ LOG.error(AaiUiMsgs.ERROR_GENERIC,
+ "An error occurred getting data from AAI. Error = " + error.getMessage());
+ }
+ });
+
+ }
+
+ while (aaiWorkOnHand.get() != 0) {
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug(AaiUiMsgs.WAIT_FOR_ALL_SELFLINKS_TO_BE_COLLECTED);
+ }
+
+ Thread.sleep(1000);
+ }
+
+ aaiWorkOnHand.set(selflinks.size());
+ allWorkEnumerated = true;
+ syncEntityTypes();
+
+ while (!isSyncDone()) {
+ performRetrySync();
+ Thread.sleep(1000);
+ }
+
+ /*
+ * Make sure we don't hang on to retries that failed which could cause issues during future
+ * syncs
+ */
+ retryLimitTracker.clear();
+
+ } catch (Exception exc) {
+ // TODO -> LOG, waht should be logged here?
+ }
+
+ return OperationState.OK;
+ }
+
+ /* (non-Javadoc)
+ * @see org.openecomp.sparky.synchronizer.IndexSynchronizer#doSync()
+ */
+ @Override
+ public OperationState doSync() {
+ this.syncDurationInMs = -1;
+ String txnID = NodeUtils.getRandomTxnId();
+ MdcContext.initialize(txnID, "SearchableEntitySynchronizer", "", "Sync", "");
+
+ resetCounters();
+ this.allWorkEnumerated = false;
+ syncStartedTimeStampInMs = System.currentTimeMillis();
+ collectAllTheWork();
+
+ return OperationState.OK;
+ }
+
+ /**
+ * Process entity type self links.
+ *
+ * @param operationResult the operation result
+ */
+ private void processEntityTypeSelfLinks(OperationResult operationResult) {
+
+ JsonNode rootNode = null;
+
+ final String jsonResult = operationResult.getResult();
+
+ if (jsonResult != null && jsonResult.length() > 0 && operationResult.wasSuccessful()) {
+
+ try {
+ rootNode = mapper.readTree(jsonResult);
+ } catch (IOException exc) {
+ String message = "Could not deserialize JSON (representing operation result) as node tree. "
+ + "Operation result = " + jsonResult + ". " + exc.getLocalizedMessage();
+ LOG.error(AaiUiMsgs.JSON_PROCESSING_ERROR, message);
+ }
+
+ ArrayNode resultDataArrayNode = null;
+
+ if (rootNode.isArray()) {
+ resultDataArrayNode = (ArrayNode) rootNode;
+
+ Iterator<JsonNode> elementIterator = resultDataArrayNode.elements();
+ JsonNode element = null;
+
+ while (elementIterator.hasNext()) {
+ element = elementIterator.next();
+
+ final String id = NodeUtils.getNodeFieldAsText(element, "id");
+ final String type = NodeUtils.getNodeFieldAsText(element, "type");
+ final String url = NodeUtils.getNodeFieldAsText(element, "url");
+
+ String resourceLink;
+ try {
+ resourceLink = gizmoAdapter.getFullInventoryUrl(type + "/" + id);
+ selflinks.add(new SelfLinkDescriptor(NodeUtils.extractRawGizmoPathWithoutVersion(resourceLink), null, type));
+ } catch (Exception e) {
+ LOG.error(AaiUiMsgs.ERROR_GENERIC, "ERROR: Failed to determine resource link caused by " + e.getMessage());
+ }
+
+ }
+ }
+ }
+
+ }
+
+ /**
+ * Sync entity types.
+ */
+ private void syncEntityTypes() {
+
+ while (selflinks.peek() != null) {
+
+ SelfLinkDescriptor linkDescriptor = selflinks.poll();
+ aaiWorkOnHand.decrementAndGet();
+
+ OxmEntityDescriptor descriptor = null;
+
+ if (linkDescriptor.getSelfLink() != null && linkDescriptor.getEntityType() != null) {
+
+ descriptor = oxmEntityLookup.getEntityDescriptors().get(linkDescriptor.getEntityType());
+
+ if (descriptor == null) {
+ LOG.error(AaiUiMsgs.MISSING_ENTITY_DESCRIPTOR, linkDescriptor.getEntityType());
+ continue;
+ }
+
+ NetworkTransaction txn = new NetworkTransaction();
+ txn.setDescriptor(descriptor);
+ txn.setLink(linkDescriptor.getSelfLink());
+ txn.setOperationType(HttpMethod.GET);
+ txn.setEntityType(linkDescriptor.getEntityType());
+
+ aaiWorkOnHand.incrementAndGet();
+
+ supplyAsync(new PerformGizmoRetrieval(txn, gizmoAdapter), aaiExecutor)
+ .whenComplete((result, error) -> {
+
+ aaiWorkOnHand.decrementAndGet();
+
+ if (error != null) {
+ LOG.error(AaiUiMsgs.AAI_RETRIEVAL_FAILED_GENERIC, error.getLocalizedMessage());
+ } else {
+ if (result == null) {
+ LOG.error(AaiUiMsgs.AAI_RETRIEVAL_FAILED_FOR_SELF_LINK,
+ linkDescriptor.getSelfLink());
+ } else {
+ updateActiveInventoryCounters(result);
+ fetchDocumentForUpsert(result);
+ }
+ }
+ });
+ }
+
+ }
+
+ }
+
+ /**
+ * Perform document upsert.
+ *
+ * @param esGetTxn the es get txn
+ * @param se the se
+ */
+ protected void performDocumentUpsert(NetworkTransaction esGetTxn, SearchableEntity se) {
+ /**
+ * <p>
+ * <ul>
+ * As part of the response processing we need to do the following:
+ * <li>1. Extract the version (if present), it will be the ETAG when we use the
+ * Search-Abstraction-Service
+ * <li>2. Spawn next task which is to do the PUT operation into elastic with or with the version
+ * tag
+ * <li>a) if version is null or RC=404, then standard put, no _update with version tag
+ * <li>b) if version != null, do PUT with _update?version= versionNumber in the URI to elastic
+ * </ul>
+ * </p>
+ */
+ String link = null;
+ try {
+ link = elasticSearchAdapter.buildElasticSearchGetDocUrl(getIndexName(), se.getId());
+ } catch (Exception exc) {
+ LOG.error(AaiUiMsgs.ES_LINK_UPSERT, exc.getLocalizedMessage());
+ return;
+ }
+
+ String versionNumber = null;
+ boolean wasEntryDiscovered = false;
+ if (esGetTxn.getOperationResult().getResultCode() == 404) {
+ LOG.info(AaiUiMsgs.ES_SIMPLE_PUT, se.getEntityPrimaryKeyValue());
+ } else if (esGetTxn.getOperationResult().getResultCode() == 200) {
+ wasEntryDiscovered = true;
+ try {
+ versionNumber = NodeUtils.extractFieldValueFromObject(
+ NodeUtils.convertJsonStrToJsonNode(esGetTxn.getOperationResult().getResult()),
+ "_version");
+ } catch (IOException exc) {
+ String message =
+ "Error extracting version number from response, aborting searchable entity sync of "
+ + se.getEntityPrimaryKeyValue() + ". Error - " + exc.getLocalizedMessage();
+ LOG.error(AaiUiMsgs.ERROR_EXTRACTING_FROM_RESPONSE, message);
+ return;
+ }
+ } else {
+ /*
+ * Not being a 200 does not mean a failure. eg 201 is returned for created. TODO -> Should we
+ * return.
+ */
+ LOG.error(AaiUiMsgs.ES_OPERATION_RETURN_CODE,
+ String.valueOf(esGetTxn.getOperationResult().getResultCode()));
+ return;
+ }
+
+ try {
+ String jsonPayload = null;
+ if (wasEntryDiscovered) {
+ try {
+ ArrayList<JsonNode> sourceObject = new ArrayList<JsonNode>();
+ NodeUtils.extractObjectsByKey(
+ NodeUtils.convertJsonStrToJsonNode(esGetTxn.getOperationResult().getResult()),
+ "_source", sourceObject);
+
+ if (!sourceObject.isEmpty()) {
+ String responseSource = NodeUtils.convertObjectToJson(sourceObject.get(0), false);
+ MergableEntity me = mapper.readValue(responseSource, MergableEntity.class);
+ ObjectReader updater = mapper.readerForUpdating(me);
+ MergableEntity merged = updater.readValue(NodeUtils.convertObjectToJson(se,false));
+ jsonPayload = mapper.writeValueAsString(merged);
+ }
+ } catch (IOException exc) {
+ String message =
+ "Error extracting source value from response, aborting searchable entity sync of "
+ + se.getEntityPrimaryKeyValue() + ". Error - " + exc.getLocalizedMessage();
+ LOG.error(AaiUiMsgs.ERROR_EXTRACTING_FROM_RESPONSE, message);
+ return;
+ }
+ } else {
+ jsonPayload = se.getAsJson();
+ }
+
+ if (wasEntryDiscovered) {
+ if (versionNumber != null && jsonPayload != null) {
+
+ String requestPayload = elasticSearchAdapter.buildBulkImportOperationRequest(getIndexName(),
+ "default", se.getId(), versionNumber, jsonPayload);
+
+ NetworkTransaction transactionTracker = new NetworkTransaction();
+ transactionTracker.setEntityType(esGetTxn.getEntityType());
+ transactionTracker.setDescriptor(esGetTxn.getDescriptor());
+ transactionTracker.setOperationType(HttpMethod.PUT);
+
+ esWorkOnHand.incrementAndGet();
+ supplyAsync(new PerformElasticSearchUpdate(elasticSearchAdapter.getBulkUrl(),
+ requestPayload, elasticSearchAdapter, transactionTracker), esPutExecutor)
+ .whenComplete((result, error) -> {
+
+ esWorkOnHand.decrementAndGet();
+
+ if (error != null) {
+ String message = "Searchable entity sync UPDATE PUT error - "
+ + error.getLocalizedMessage();
+ LOG.error(AaiUiMsgs.ES_SEARCHABLE_ENTITY_SYNC_ERROR, message);
+ } else {
+ updateElasticSearchCounters(result);
+ processStoreDocumentResult(result, esGetTxn, se);
+ }
+ });
+ }
+
+ } else {
+
+ if (link != null && jsonPayload != null) {
+
+ NetworkTransaction updateElasticTxn = new NetworkTransaction();
+ updateElasticTxn.setLink(link);
+ updateElasticTxn.setEntityType(esGetTxn.getEntityType());
+ updateElasticTxn.setDescriptor(esGetTxn.getDescriptor());
+ updateElasticTxn.setOperationType(HttpMethod.PUT);
+
+ esWorkOnHand.incrementAndGet();
+ supplyAsync(new PerformElasticSearchPut(jsonPayload, updateElasticTxn, elasticSearchAdapter),
+ esPutExecutor).whenComplete((result, error) -> {
+
+ esWorkOnHand.decrementAndGet();
+
+ if (error != null) {
+ String message =
+ "Searchable entity sync UPDATE PUT error - " + error.getLocalizedMessage();
+ LOG.error(AaiUiMsgs.ES_SEARCHABLE_ENTITY_SYNC_ERROR, message);
+ } else {
+ updateElasticSearchCounters(result);
+ processStoreDocumentResult(result, esGetTxn, se);
+ }
+ });
+ }
+ }
+ } catch (Exception exc) {
+ String message = "Exception caught during searchable entity sync PUT operation. Message - "
+ + exc.getLocalizedMessage();
+ LOG.error(AaiUiMsgs.ES_SEARCHABLE_ENTITY_SYNC_ERROR, message);
+ }
+ }
+
+ /**
+ * Populate searchable entity document.
+ *
+ * @param doc the doc
+ * @param result the result
+ * @param resultDescriptor the result descriptor
+ * @throws JsonProcessingException the json processing exception
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ protected void populateSearchableEntityDocument(SearchableEntity doc, String result,
+ OxmEntityDescriptor resultDescriptor) throws JsonProcessingException, IOException {
+
+ doc.setEntityType(resultDescriptor.getEntityName());
+
+ JsonNode entityNode = mapper.readTree(result);
+
+ String id = NodeUtils.getNodeFieldAsText(entityNode, "id");
+ String type = NodeUtils.getNodeFieldAsText(entityNode, "type");
+ String url = NodeUtils.getNodeFieldAsText(entityNode, "url");
+
+ JsonNode properties = entityNode.get("properties");
+
+ Iterator<String> fieldNames = properties.fieldNames();
+
+
+
+ List<String> primaryKeyValues = new ArrayList<String>();
+ String pkeyValue = null;
+
+ SearchableOxmEntityDescriptor searchableDescriptor = searchableEntityLookup.getSearchableEntityDescriptors().get(resultDescriptor.getEntityName());
+
+ for (String keyName : searchableDescriptor.getPrimaryKeyAttributeNames()) {
+ pkeyValue = NodeUtils.getNodeFieldAsText(properties, keyName);
+ if (pkeyValue != null) {
+ primaryKeyValues.add(pkeyValue);
+ } else {
+ String message = "populateSearchableEntityDocument(), pKeyValue is null for entityType = "
+ + resultDescriptor.getEntityName();
+ LOG.warn(AaiUiMsgs.WARN_GENERIC, message);
+ }
+ }
+
+ final String primaryCompositeKeyValue = NodeUtils.concatArray(primaryKeyValues, "/");
+ doc.setEntityPrimaryKeyValue(primaryCompositeKeyValue);
+
+ final List<String> searchTagFields = searchableDescriptor.getSearchableAttributes();
+
+ /*
+ * Based on configuration, use the configured field names for this entity-Type to build a
+ * multi-value collection of search tags for elastic search entity search criteria.
+ */
+ for (String searchTagField : searchTagFields) {
+ String searchTagValue = NodeUtils.getNodeFieldAsText(properties, searchTagField);
+ if (searchTagValue != null && !searchTagValue.isEmpty()) {
+ doc.addSearchTagWithKey(searchTagValue, searchTagField);
+ }
+ }
+ }
+
+ /**
+ * Fetch document for upsert.
+ *
+ * @param txn the txn
+ */
+ private void fetchDocumentForUpsert(NetworkTransaction txn) {
+ if (!txn.getOperationResult().wasSuccessful()) {
+ String message = "Self link failure. Result - " + txn.getOperationResult().getResult();
+ LOG.error(AaiUiMsgs.ERROR_GENERIC, message);
+ return;
+ }
+
+ SearchableOxmEntityDescriptor searchableDescriptor = searchableEntityLookup
+ .getSearchableEntityDescriptors().get(txn.getDescriptor().getEntityName());
+
+ try {
+ if (searchableDescriptor.hasSearchableAttributes()) {
+
+ final String jsonResult = txn.getOperationResult().getResult();
+ if (jsonResult != null && jsonResult.length() > 0) {
+
+ SearchableEntity se = new SearchableEntity();
+ se.setLink( txn.getLink() );
+ populateSearchableEntityDocument(se, jsonResult, searchableDescriptor);
+ se.deriveFields();
+
+
+ String link = null;
+ try {
+ link = elasticSearchAdapter.buildElasticSearchGetDocUrl(getIndexName(), se.getId());
+ } catch (Exception exc) {
+ LOG.error(AaiUiMsgs.ES_FAILED_TO_CONSTRUCT_QUERY, exc.getLocalizedMessage());
+ }
+
+ if (link != null) {
+ NetworkTransaction n2 = new NetworkTransaction();
+ n2.setLink(link);
+ n2.setEntityType(txn.getEntityType());
+ n2.setDescriptor(txn.getDescriptor());
+ n2.setOperationType(HttpMethod.GET);
+
+ esWorkOnHand.incrementAndGet();
+
+ supplyAsync(new PerformElasticSearchRetrieval(n2, elasticSearchAdapter), esExecutor)
+ .whenComplete((result, error) -> {
+
+ esWorkOnHand.decrementAndGet();
+
+ if (error != null) {
+ LOG.error(AaiUiMsgs.ES_RETRIEVAL_FAILED, error.getLocalizedMessage());
+ } else {
+ updateElasticSearchCounters(result);
+ performDocumentUpsert(result, se);
+ }
+ });
+ }
+ }
+
+ }
+ } catch (JsonProcessingException exc) {
+ LOG.error(AaiUiMsgs.ERROR_GENERIC, "Processing error while fetching document for elasticsearch update. Error: " + exc.getMessage() );
+ } catch (IOException exc) {
+ LOG.error(AaiUiMsgs.ERROR_GENERIC, "Processing error while fetching document for elasticsearch update. Error: " + exc.getMessage() );
+ }
+ }
+
+ /**
+ * Process store document result.
+ *
+ * @param esPutResult the es put result
+ * @param esGetResult the es get result
+ * @param se the se
+ */
+ private void processStoreDocumentResult(NetworkTransaction esPutResult,
+ NetworkTransaction esGetResult, SearchableEntity se) {
+
+ OperationResult or = esPutResult.getOperationResult();
+
+ if (!or.wasSuccessful()) {
+ if (or.getResultCode() == VERSION_CONFLICT_EXCEPTION_CODE) {
+
+ if (shouldAllowRetry(se.getId())) {
+ esWorkOnHand.incrementAndGet();
+
+ RetrySearchableEntitySyncContainer rsc =
+ new RetrySearchableEntitySyncContainer(esGetResult, se);
+ retryQueue.push(rsc);
+
+ String message = "Store document failed during searchable entity synchronization"
+ + " due to version conflict. Entity will be re-synced.";
+ LOG.warn(AaiUiMsgs.ES_SEARCHABLE_ENTITY_SYNC_ERROR, message);
+ }
+ } else {
+ String message =
+ "Store document failed during searchable entity synchronization with result code "
+ + or.getResultCode() + " and result message " + or.getResult();
+ LOG.error(AaiUiMsgs.ES_SEARCHABLE_ENTITY_SYNC_ERROR, message);
+ }
+ }
+ }
+
+ /**
+ * Perform retry sync.
+ */
+ private void performRetrySync() {
+ while (retryQueue.peek() != null) {
+
+ RetrySearchableEntitySyncContainer rsc = retryQueue.poll();
+ if (rsc != null) {
+
+ SearchableEntity se = rsc.getSearchableEntity();
+ NetworkTransaction txn = rsc.getNetworkTransaction();
+
+ String link = null;
+ try {
+ /*
+ * In this retry flow the se object has already derived its fields
+ */
+ link = elasticSearchAdapter.buildElasticSearchGetDocUrl(getIndexName(), se.getId());
+ } catch (Exception exc) {
+ LOG.error(AaiUiMsgs.ES_FAILED_TO_CONSTRUCT_URI, exc.getLocalizedMessage());
+ }
+
+ if (link != null) {
+ NetworkTransaction retryTransaction = new NetworkTransaction();
+ retryTransaction.setLink(link);
+ retryTransaction.setEntityType(txn.getEntityType());
+ retryTransaction.setDescriptor(txn.getDescriptor());
+ retryTransaction.setOperationType(HttpMethod.GET);
+
+ /*
+ * IMPORTANT - DO NOT incrementAndGet the esWorkOnHand as this is a retry flow! We already
+ * called incrementAndGet when queuing the failed PUT!
+ */
+
+ supplyAsync(new PerformElasticSearchRetrieval(retryTransaction, elasticSearchAdapter),
+ esExecutor).whenComplete((result, error) -> {
+
+ esWorkOnHand.decrementAndGet();
+
+ if (error != null) {
+ LOG.error(AaiUiMsgs.ES_RETRIEVAL_FAILED_RESYNC, error.getLocalizedMessage());
+ } else {
+ updateElasticSearchCounters(result);
+ performDocumentUpsert(result, se);
+ }
+ });
+ }
+
+ }
+ }
+ }
+
+ /**
+ * Should allow retry.
+ *
+ * @param id the id
+ * @return true, if successful
+ */
+ private boolean shouldAllowRetry(String id) {
+ boolean isRetryAllowed = true;
+ if (retryLimitTracker.get(id) != null) {
+ Integer currentCount = retryLimitTracker.get(id);
+ if (currentCount.intValue() >= RETRY_COUNT_PER_ENTITY_LIMIT.intValue()) {
+ isRetryAllowed = false;
+ String message = "Searchable entity re-sync limit reached for " + id
+ + ", re-sync will no longer be attempted for this entity";
+ LOG.error(AaiUiMsgs.ES_SEARCHABLE_ENTITY_SYNC_ERROR, message);
+ } else {
+ Integer newCount = new Integer(currentCount.intValue() + 1);
+ retryLimitTracker.put(id, newCount);
+ }
+ } else {
+ Integer firstRetryCount = new Integer(1);
+ retryLimitTracker.put(id, firstRetryCount);
+ }
+
+ return isRetryAllowed;
+ }
+
+ @Override
+ public SynchronizerState getState() {
+ if (!isSyncDone()) {
+ return SynchronizerState.PERFORMING_SYNCHRONIZATION;
+ }
+
+ return SynchronizerState.IDLE;
+
+ }
+
+ /* (non-Javadoc)
+ * @see org.openecomp.sparky.synchronizer.IndexSynchronizer#getStatReport(boolean)
+ */
+ @Override
+ public String getStatReport(boolean showFinalReport) {
+ syncDurationInMs = System.currentTimeMillis() - syncStartedTimeStampInMs;
+ return this.getStatReport(syncDurationInMs, showFinalReport);
+ }
+
+ /* (non-Javadoc)
+ * @see org.openecomp.sparky.synchronizer.IndexSynchronizer#shutdown()
+ */
+ @Override
+ public void shutdown() {
+ this.shutdownExecutors();
+ }
+
+ @Override
+ protected boolean isSyncDone() {
+ int totalWorkOnHand = aaiWorkOnHand.get() + esWorkOnHand.get();
+
+ if (totalWorkOnHand > 0 || !allWorkEnumerated) {
+ return false;
+ }
+
+ return true;
+ }
+
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/sync/ViewInspectGizmoSyncController.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/sync/ViewInspectGizmoSyncController.java
new file mode 100644
index 0000000..c2a1150
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/sync/ViewInspectGizmoSyncController.java
@@ -0,0 +1,107 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017 Amdocs
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.sparky.viewandinspect.sync;
+
+import org.onap.aai.sparky.config.oxm.OxmEntityContainerLookup;
+import org.onap.aai.sparky.config.oxm.OxmEntityLookup;
+import org.onap.aai.sparky.config.oxm.SearchableEntityLookup;
+import org.onap.aai.sparky.dal.ElasticSearchAdapter;
+import org.onap.aai.sparky.dal.GizmoAdapter;
+import org.onap.aai.sparky.sync.ElasticSearchIndexCleaner;
+import org.onap.aai.sparky.sync.ElasticSearchSchemaFactory;
+import org.onap.aai.sparky.sync.IndexCleaner;
+import org.onap.aai.sparky.sync.IndexIntegrityValidator;
+import org.onap.aai.sparky.sync.SyncControllerImpl;
+import org.onap.aai.sparky.sync.SyncControllerRegistrar;
+import org.onap.aai.sparky.sync.SyncControllerRegistry;
+import org.onap.aai.sparky.sync.config.ElasticSearchEndpointConfig;
+import org.onap.aai.sparky.sync.config.ElasticSearchSchemaConfig;
+import org.onap.aai.sparky.sync.config.NetworkStatisticsConfig;
+import org.onap.aai.sparky.sync.config.SyncControllerConfig;
+
+public class ViewInspectGizmoSyncController extends SyncControllerImpl
+ implements SyncControllerRegistrar {
+
+ private SyncControllerRegistry syncControllerRegistry;
+ //private GizmoAdapter gizmoAdapter;
+ //private ElasticSearchAdapter esAdapter;
+ //private ElasticSearchSchemaConfig schemaConfig;
+ //private ElasticSearchEndpointConfig endpointConfig;
+
+ public ViewInspectGizmoSyncController(SyncControllerConfig syncControllerConfig,
+ GizmoAdapter gizmoAdapter, ElasticSearchAdapter esAdapter,
+ ElasticSearchSchemaConfig schemaConfig, ElasticSearchEndpointConfig endpointConfig,
+ NetworkStatisticsConfig gizmoStatConfig, NetworkStatisticsConfig esStatConfig,
+ OxmEntityLookup oxmEntityLookup,
+ SearchableEntityLookup searchableEntityLookup, OxmEntityContainerLookup oxmEntityContainerLookup,
+ ElasticSearchSchemaFactory elasticSearchSchemaFactory) throws Exception {
+ super(syncControllerConfig);
+
+ // final String controllerName = "View and Inspect Entity Synchronizer";
+
+ //this.gizmoAdapter = gizmoAdapter;
+ //this.esAdapter = esAdapter;
+ //this.schemaConfig = schemaConfig;
+ //this.endpointConfig = endpointConfig;
+
+ IndexIntegrityValidator indexValidator = new IndexIntegrityValidator(esAdapter, schemaConfig,
+ endpointConfig, elasticSearchSchemaFactory.getIndexSchema(schemaConfig));
+
+ registerIndexValidator(indexValidator);
+
+ ViewInspectGizmoEntitySynchronizer ses = new ViewInspectGizmoEntitySynchronizer(schemaConfig,
+ syncControllerConfig.getNumInternalSyncWorkers(),
+ syncControllerConfig.getNumSyncActiveInventoryWorkers(),
+ syncControllerConfig.getNumSyncElasticWorkers(), gizmoStatConfig, esStatConfig,
+ oxmEntityLookup, searchableEntityLookup, oxmEntityContainerLookup);
+
+ ses.setGizmoAdapter(gizmoAdapter);
+ ses.setElasticSearchAdapter(esAdapter);
+
+ registerEntitySynchronizer(ses);
+
+ IndexCleaner indexCleaner =
+ new ElasticSearchIndexCleaner(esAdapter, endpointConfig, schemaConfig);
+
+ registerIndexCleaner(indexCleaner);
+
+ }
+
+ public SyncControllerRegistry getSyncControllerRegistry() {
+ return syncControllerRegistry;
+ }
+
+ public void setSyncControllerRegistry(SyncControllerRegistry syncControllerRegistry) {
+ this.syncControllerRegistry = syncControllerRegistry;
+ }
+
+ @Override
+ public void registerController() {
+ if ( syncControllerRegistry != null ) {
+ if ( syncControllerConfig.isEnabled()) {
+ syncControllerRegistry.registerSyncController(this);
+ }
+ }
+
+ }
+}
diff --git a/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/util/SchemaVisualizationTestDataBuilder.java b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/util/SchemaVisualizationTestDataBuilder.java
new file mode 100644
index 0000000..335e18a
--- /dev/null
+++ b/sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/util/SchemaVisualizationTestDataBuilder.java
@@ -0,0 +1,134 @@
+package org.onap.aai.sparky.viewandinspect.util;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.json.Json;
+import javax.json.JsonObjectBuilder;
+
+import org.onap.aai.restclient.client.OperationResult;
+import org.onap.aai.sparky.config.oxm.OxmEntityLookup;
+import org.onap.aai.sparky.util.OxmModelAndProcessorHelper;
+import org.onap.aai.sparky.viewandinspect.config.VisualizationConfigs;
+import org.onap.aai.sparky.viewandinspect.entity.ActiveInventoryNode;
+import org.restlet.data.Status;
+
+
+public class SchemaVisualizationTestDataBuilder {
+
+ // All of these hash IDs were generated based off the self links of the aaiNodes populated below
+ public static final String ROOT_NODE_HASH_ID = "f2f7ca5b565b43d7ff7cffea26d3315caaaff709e03abac127604008fc323b23";
+ public static final String DEPTH_ONE_NODE_HASH_ID = "f845ab53e23cad7b9a3fc31aeef7b32bd21a72ba0fcdf568b1cfb116f2cff06f";
+ public static final String DEPTH_TWO_NODE_HASH_ID = "372a132a0cd9bacfe408b09e6518cf824dcfbf23297678ddc0a8bf4f55da5c66";
+ public static final String DEPTH_ONE_NODE_TWO_HASH_ID = "56a248219414380145b40eaa41b0482da388baa7492020d37687a998951ecdf9";
+
+ Map<String, ActiveInventoryNode> aaiNodes;
+
+ SchemaVisualizationTestDataBuilder() {
+ aaiNodes = new HashMap<String, ActiveInventoryNode>();
+ }
+
+ public static String getQueryRequest() {
+ JsonObjectBuilder rootNodeBuilder = Json.createObjectBuilder();
+ rootNodeBuilder.add("hashId", "f2f7ca5b565b43d7ff7cffea26d3315caaaff709e03abac127604008fc323b23");
+ return rootNodeBuilder.build().toString();
+ }
+
+ public static String getRawRootNode() {
+
+ JsonObjectBuilder rootNodeBuilder = Json.createObjectBuilder();
+ rootNodeBuilder.add("_index", "magical-test-index");
+ rootNodeBuilder.add("_type", "default");
+ rootNodeBuilder.add("_id", "f2f7ca5b565b43d7ff7cffea26d3315caaaff709e03abac127604008fc323b23"); // Yes, hashed the link below
+ rootNodeBuilder.add("_version", 1);
+ rootNodeBuilder.add("found", true);
+
+ JsonObjectBuilder sourceObjBuilder = Json.createObjectBuilder();
+ sourceObjBuilder.add("entityType", "vf-module");
+ sourceObjBuilder.add("entityPrimaryKeyValue", "root-node-pimary-key-value");
+ sourceObjBuilder.add("link", "/aai/v12/network/generic-vnfs/generic-vnf/root-nodes-generic-vnf/vf-modules/vf-module/root-node-pimary-key-value");
+ sourceObjBuilder.add("searchTags", "root-node-pimary-key-value;root-node-name");
+ sourceObjBuilder.add("searchTagIDs", "vf-module-id;vf-module-name");
+ sourceObjBuilder.add("lastmodTimestamp", "2018-02-01T15:48:03.580+0000");
+
+ rootNodeBuilder.add("_source", sourceObjBuilder.build());
+
+ return rootNodeBuilder.build().toString();
+ }
+
+ public static OperationResult getSchemaVisResult() {
+ OperationResult result = new OperationResult();
+
+ result.setResult(Status.SUCCESS_OK.getCode(), "{}");
+
+ return result;
+ }
+
+ public static void buildAaiGraph(VisualizationConfigs visualizationConfigs) throws IOException {
+ OxmEntityLookup lookerOfTheOxmEntities = OxmModelAndProcessorHelper.getInstance().getOxmEntityLookup();
+
+ ActiveInventoryNode rootNode = new ActiveInventoryNode(visualizationConfigs, lookerOfTheOxmEntities);
+ rootNode.setEntityType("vf-module");
+ rootNode.setPrimaryKeyName("vf-module-id");
+ rootNode.setPrimaryKeyValue("root-node-pimary-key-value");
+ rootNode.setSelfLink("/aai/v12/network/generic-vnfs/generic-vnf/root-nodes-generic-vnf/vf-modules/vf-module/root-node-pimary-key-value");
+ rootNode.addProperty("entityType", "vf-module");
+ rootNode.addProperty("vf-module-id", "root-node-pimary-key-value");
+ rootNode.addProperty("selfLink", "/aai/v12/network/generic-vnfs/generic-vnf/root-nodes-generic-vnf/vf-modules/vf-module/root-node-pimary-key-value");
+ rootNode.addProperty("vf-module-name", "this-is-my-name-eh");
+ rootNode.addProperty("is-base-vf-module", "false");
+ rootNode.addProperty("uri", "network/generic-vnfs/generic-vnf/root-nodes-generic-vnf/vf-modules/vf-module/root-node-pimary-key-value");
+ rootNode.addProperty("orchestration-status", "Created");
+ rootNode.addProperty("resource-version", "432156789");
+ rootNode.setNodeId(ROOT_NODE_HASH_ID);
+
+ ActiveInventoryNode depthOneNode = new ActiveInventoryNode(visualizationConfigs, lookerOfTheOxmEntities);
+ depthOneNode.setEntityType("vserver");
+ depthOneNode.setPrimaryKeyName("vserver-id");
+ depthOneNode.setPrimaryKeyValue("depth-one-from-root-node-vserver-id");
+ depthOneNode.setSelfLink("/aai/v12/cloud-infrastructure/cloud-regions/cloud-region/cloud-region-id/ice-cream/tenants/tenant/tenant-id/vservers/vserver/depth-one-from-root-node-vserver-id");
+ depthOneNode.addProperty("entityType", "vserver");
+ depthOneNode.addProperty("vserver-id", "depth-one-from-root-node-vserver-id");
+ depthOneNode.addProperty("selfLink", "/aai/v12/cloud-infrastructure/cloud-regions/cloud-region/cloud-region-id/ice-cream/tenants/tenant/tenant-id/vservers/vserver/depth-one-from-root-node-vserver-id");
+ depthOneNode.addProperty("vserver-name", "depth-one-vserver");
+ depthOneNode.addProperty("in-maint", "false");
+ depthOneNode.addProperty("vserver-name2", "depth-one-vserver-name2");
+ depthOneNode.addProperty("vserver-selflink", "https://magicaltest.com:6666/v2/tenant-id/servers/depth-one-from-root-node-vserver-id");
+ depthOneNode.addProperty("uri", "cloud-infrastructure/cloud-regions/cloud-region/cloud-region-id/ice-cream/tenants/tenant/tenant-id/vservers/vserver/depth-one-from-root-node-vserver-id");
+ depthOneNode.addProperty("is-closed-loop-disabled", "false");
+ depthOneNode.addProperty("resource-version", "123456789");
+ depthOneNode.setNodeId(DEPTH_ONE_NODE_HASH_ID);
+
+ ActiveInventoryNode depthTwoNode = new ActiveInventoryNode(visualizationConfigs, lookerOfTheOxmEntities);
+ depthTwoNode.setEntityType("pserver");
+ depthTwoNode.setPrimaryKeyName("hostname");
+ depthTwoNode.setPrimaryKeyValue("I-am-a-host");
+ depthTwoNode.setSelfLink("/aai/v12/cloud-infrastructure/pservers/pserver/depth-two-from-root-node-pserver-id");
+ depthTwoNode.addProperty("entityType", "pserver");
+ depthTwoNode.addProperty("hostname", "I-am-a-host");
+ depthTwoNode.addProperty("selfLink", "/aai/v12/cloud-infrastructure/pservers/pserver/depth-two-from-root-node-pserver-id");
+ depthTwoNode.addProperty("in-maint", "false");
+ depthTwoNode.addProperty("resource-version", "987654321");
+ depthTwoNode.addProperty("pserver-id", "depth-two-from-root-node-pserver-id");
+ depthTwoNode.addProperty("uri", "cloud-infrastructure/pservers/pserver/depth-two-from-root-node-pserver-id");
+ depthTwoNode.setNodeId(DEPTH_TWO_NODE_HASH_ID);
+
+ ActiveInventoryNode depthOneNodeTwo = new ActiveInventoryNode(visualizationConfigs, lookerOfTheOxmEntities);
+ depthOneNodeTwo.setEntityType("vserver");
+ depthOneNodeTwo.setPrimaryKeyName("vserver-id");
+ depthOneNodeTwo.setPrimaryKeyValue("depth-one-from-root-node-vserver-id-2");
+ depthOneNodeTwo.setSelfLink("/aai/v12/cloud-infrastructure/cloud-regions/cloud-region/cloud-region-id/ice-cream/tenants/tenant/tenant-id/vservers/vserver/depth-one-from-root-node-vserver-id-2");
+ depthOneNodeTwo.addProperty("entityType", "vserver");
+ depthOneNodeTwo.addProperty("vserver-id", "depth-one-from-root-node-vserver-id-2");
+ depthOneNodeTwo.addProperty("selfLink", "/aai/v12/cloud-infrastructure/cloud-regions/cloud-region/cloud-region-id/ice-cream/tenants/tenant/tenant-id/vservers/vserver/depth-one-from-root-node-vserver-id-2");
+ depthOneNodeTwo.addProperty("in-maint", "false");
+ depthOneNodeTwo.addProperty("resource-version", "678954321");
+ depthOneNodeTwo.addProperty("vserver-name", "depth-one-vserver-2");
+ depthOneNodeTwo.addProperty("vserver-name2", "depth-one-vserver-2-name2");
+ depthOneNodeTwo.addProperty("vserver-selflink", "https://magicaltest.com:6666/v2/tenant-id/servers/depth-one-from-root-node-vserver-id-2");
+ depthOneNodeTwo.addProperty("uri", "cloud-infrastructure/cloud-regions/cloud-region/cloud-region-id/ice-cream/tenants/tenant/tenant-id/vservers/vserver/depth-one-from-root-node-vserver-id-2");
+ depthOneNodeTwo.addProperty("is-closed-loop-disabled", "false");
+ depthOneNodeTwo.setNodeId(DEPTH_ONE_NODE_TWO_HASH_ID);
+ }
+}
diff --git a/sparkybe-onap-service/src/test/resources/bundleconfig/etc/appprops/source-of-truth.properties b/sparkybe-onap-service/src/test/resources/bundleconfig/etc/appprops/source-of-truth.properties
new file mode 100644
index 0000000..f08722f
--- /dev/null
+++ b/sparkybe-onap-service/src/test/resources/bundleconfig/etc/appprops/source-of-truth.properties
@@ -0,0 +1,47 @@
+# Source of Truth mappings. This file maps an enitity path to a source of truth identifier
+# AAI v7
+/v7/network/ipsec-configurations/ipsec-configuration/requested-vig-address-type=service-manager
+/v7/network/ipsec-configurations/ipsec-configuration/requested-encryption-strength=service-manager
+/v7/network/ipsec-configurations/ipsec-configuration/requested-dmz-type=service-manager
+/v7/network/ipsec-configurations/ipsec-configuration/shared-dmz-network-address=service-manager
+/v7/network/ipsec-configurations/ipsec-configuration/requested-customer-name=service-manager
+/v7/network/ipsec-configurations/ipsec-configuration/ike-version=service-manager
+/v7/network/ipsec-configurations/ipsec-configuration/ikev1-authentication=service-manager
+/v7/network/ipsec-configurations/ipsec-configuration/ikev1-encryption=service-manager
+/v7/network/ipsec-configurations/ipsec-configuration/ikev1-dh-group=service-manager
+/v7/network/ipsec-configurations/ipsec-configuration/ikev1-am-group-id=service-manager
+/v7/network/ipsec-configurations/ipsec-configuration/ikev1-am-password=service-manager
+/v7/network/ipsec-configurations/ipsec-configuration/ikev1-sa-lifetime=service-manager
+/v7/network/ipsec-configurations/ipsec-configuration/ipsec-authentication=service-manager
+/v7/network/ipsec-configurations/ipsec-configuration/ipsec-encryption=service-manager
+/v7/network/ipsec-configurations/ipsec-configuration/ipsec-sa-lifetime=service-manager
+/v7/network/ipsec-configurations/ipsec-configuration/ipsec-pfs=service-manager
+/v7/network/ipsec-configurations/ipsec-configuration/xauth-userid=service-manager
+/v7/network/ipsec-configurations/ipsec-configuration/xauth-user-password=service-manager
+/v7/network/ipsec-configurations/ipsec-configuration/dpd-interval=service-manager
+/v7/network/ipsec-configurations/ipsec-configuration/dpd-frequency=service-manager
+/v7/network/ipsec-configurations/ipsec-configuration/vig-servers=service-manager
+
+# AAI v8
+/v8/network/ipsec-configurations/ipsec-configuration/requested-vig-address-type=service-manager
+/v8/network/ipsec-configurations/ipsec-configuration/requested-encryption-strength=service-manager
+/v8/network/ipsec-configurations/ipsec-configuration/requested-dmz-type=service-manager
+/v8/network/ipsec-configurations/ipsec-configuration/shared-dmz-network-address=service-manager
+/v8/network/ipsec-configurations/ipsec-configuration/requested-customer-name=service-manager
+/v8/network/ipsec-configurations/ipsec-configuration/ike-version=service-manager
+/v8/network/ipsec-configurations/ipsec-configuration/ikev1-authentication=service-manager
+/v8/network/ipsec-configurations/ipsec-configuration/ikev1-encryption=service-manager
+/v8/network/ipsec-configurations/ipsec-configuration/ikev1-dh-group=service-manager
+/v8/network/ipsec-configurations/ipsec-configuration/ikev1-am-group-id=service-manager
+/v8/network/ipsec-configurations/ipsec-configuration/ikev1-am-password=service-manager
+/v8/network/ipsec-configurations/ipsec-configuration/ikev1-sa-lifetime=service-manager
+/v8/network/ipsec-configurations/ipsec-configuration/ipsec-authentication=service-manager
+/v8/network/ipsec-configurations/ipsec-configuration/ipsec-encryption=service-manager
+/v8/network/ipsec-configurations/ipsec-configuration/ipsec-sa-lifetime=service-manager
+/v8/network/ipsec-configurations/ipsec-configuration/ipsec-pfs=service-manager
+/v8/network/ipsec-configurations/ipsec-configuration/xauth-userid=service-manager
+/v8/network/ipsec-configurations/ipsec-configuration/xauth-user-password=service-manager
+/v8/network/ipsec-configurations/ipsec-configuration/dpd-interval=service-manager
+/v8/network/ipsec-configurations/ipsec-configuration/dpd-frequency=service-manager
+/v8/network/ipsec-configurations/ipsec-configuration/vig-servers=service-manager
+
diff --git a/sparkybe-onap-service/src/test/resources/es_test_scripts/commands.txt b/sparkybe-onap-service/src/test/resources/es_test_scripts/commands.txt
new file mode 100644
index 0000000..5d25157
--- /dev/null
+++ b/sparkybe-onap-service/src/test/resources/es_test_scripts/commands.txt
@@ -0,0 +1,3 @@
+commands histoty
+curl -XPUT localhost:9200/topographyhistorysearchindex?pretty --data-binary @topoHistoryConfigSettings.json
+curl -XPUT localhost:9200/_bulk?pretty --data-binary @topoHistoryBulkLoad.json
diff --git a/sparkybe-onap-service/src/test/resources/es_test_scripts/geoEntities.json b/sparkybe-onap-service/src/test/resources/es_test_scripts/geoEntities.json
new file mode 100644
index 0000000..9af3978
--- /dev/null
+++ b/sparkybe-onap-service/src/test/resources/es_test_scripts/geoEntities.json
@@ -0,0 +1,6 @@
+{"index":{"_index":"topographicalsearchindex-localhost","_type":"default"}
+{"pkey": "complex.TEST1", "entityType": "complex", "longitude": "-82.089844", "latitude": "33.642063", "selfLink": "http://localhost:8443/complex/TEST1"}
+{"index":{"_index":"topographicalsearchindex-localhost","_type":"default"}
+{"pkey": "complex.TEST2", "entityType": "complex", "longitude": "-114.785156", "latitude": "37.640335", "selfLink": "http://localhost:8443/complex/TEST2"}
+{"index":{"_index":"topographicalsearchindex-localhost","_type":"default"}
+{"pkey": "complex.TEST3", "entityType": "complex", "longitude": "-97.910156", "latitude": "27.595935", "selfLink": "http://localhost:8443/complex/TEST3"}
diff --git a/sparkybe-onap-service/src/test/resources/es_test_scripts/prepareGeoEntityBulkImport.pl b/sparkybe-onap-service/src/test/resources/es_test_scripts/prepareGeoEntityBulkImport.pl
new file mode 100644
index 0000000..67ed571
--- /dev/null
+++ b/sparkybe-onap-service/src/test/resources/es_test_scripts/prepareGeoEntityBulkImport.pl
@@ -0,0 +1,41 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+my $filename = $ARGV[0];
+my $outputfile= $ARGV[1];
+
+open my $fh_input, '<', $filename or die "Cannot open $filename: $!";
+open my $fh_output, '>', $outputfile or die "Cannot open $outputfile: $!";
+
+while ( my $line = <$fh_input> ) {
+ chomp ($line);
+
+ if ( $line =~ /(.*)(\".*\")(.*)/ ) {
+
+ # we have seen examples of the status field containing quoted comma-delimited
+ # strings which is messing up parsing of the record data which is supposed to be
+ # comma-separated at the field level. This little block converts sections of
+ # this type of data into a single-quoted-string with a semi-colon delimiter instead.
+
+ my $beforeBadStr = $1;
+ my $badStr = $2;
+ my $afterBadStr = $3;
+
+ $badStr =~ s/,/;/g;
+ $badStr =~ s/"/'/g;
+
+ $line = $beforeBadStr . $badStr . $afterBadStr ;
+
+ }
+
+ my @row = split(",", $line);
+ print $fh_output "{\"index\":{\"_index\":\"topographicalsearchindex-localhost\",\"_type\":\"default\"}\n";
+ print $fh_output "{\"pkey\": \"$row[0]\", \"entityType\": \"$row[1]\", \"location\" : {\"lat\": \"$row[3]\", \"lon\": \"$row[2]\"}, \"selfLink\": \"$row[4]\"}\n";
+
+}
+
+close($fh_input);
+close($fh_output);
+
diff --git a/sparkybe-onap-service/src/test/resources/es_test_scripts/sampleGeoEntities.csv b/sparkybe-onap-service/src/test/resources/es_test_scripts/sampleGeoEntities.csv
new file mode 100644
index 0000000..d149e39
--- /dev/null
+++ b/sparkybe-onap-service/src/test/resources/es_test_scripts/sampleGeoEntities.csv
@@ -0,0 +1,4 @@
+complex.TEST1,complex,-82.089844,33.642063,http://localhost:8443/complex/TEST1,
+complex.TEST2,complex,-114.785156,37.640335,http://localhost:8443/complex/TEST2,
+complex.TEST3,complex,-97.910156,27.595935,http://localhost:8443/complex/TEST3,
+pserver.TEST1,pserver,-97.910156,27.595935,http://localhost:8443/pserver/TEST1 \ No newline at end of file
diff --git a/sparkybe-onap-service/src/test/resources/es_test_scripts/topoHistoryBulkLoad.json b/sparkybe-onap-service/src/test/resources/es_test_scripts/topoHistoryBulkLoad.json
new file mode 100644
index 0000000..77d57f7
--- /dev/null
+++ b/sparkybe-onap-service/src/test/resources/es_test_scripts/topoHistoryBulkLoad.json
@@ -0,0 +1,24 @@
+{"index":{"_index":"topographyhistorysearchindex-localhost","_type":"default"}
+{"count":4,"entityType":"vServer","timestamp":"31-01-2017 03:00:00"}
+{"index":{"_index":"topographyhistorysearchindex-localhost","_type":"default"}
+{"count":2,"entityType":"pServer","timestamp":"31-01-2017 03:00:00"}
+{"index":{"_index":"topographyhistorysearchindex-localhost","_type":"default"}
+{"count":3,"entityType":"pServer","timestamp":"31-01-2017 02:00:00"}
+{"index":{"_index":"topographyhistorysearchindex-localhost","_type":"default"}
+{"count":4,"entityType":"pServer","timestamp":"31-01-2017 03:00:00"}
+{"index":{"_index":"topographyhistorysearchindex-localhost","_type":"default"}
+{"count":2,"entityType":"vServer","timestamp":"31-01-2017 01:00:00"}
+{"index":{"_index":"topographyhistorysearchindex-localhost","_type":"default"}
+{"count":4,"entityType":"pServer","timestamp":"30-01-2017 03:00:00"}
+{"index":{"_index":"topographyhistorysearchindex-localhost","_type":"default"}
+{"count":4,"entityType":"generic-vnf","timestamp":"30-01-2017 03:00:00"}
+{"index":{"_index":"topographyhistorysearchindex-localhost","_type":"default"}
+{"count":4,"entityType":"vpe","timestamp":"31-01-2017 03:00:00"}
+{"index":{"_index":"topographyhistorysearchindex-localhost","_type":"default"}
+{"count":4,"entityType":"newvce","timestamp":"31-01-2017 03:00:00"}
+{"index":{"_index":"topographyhistorysearchindex-localhost","_type":"default"}
+{"count":4,"entityType":"vce","timestamp":"31-01-2017 03:00:00"}
+{"index":{"_index":"topographyhistorysearchindex-localhost","_type":"default"}
+{"count":4,"entityType":"vce","timestamp":"30-01-2017 03:00:00"}
+{"index":{"_index":"topographyhistorysearchindex-localhost","_type":"default"}
+{"count":4,"entityType":"vce","timestamp":"01-02-2017 03:00:00"}
diff --git a/sparkybe-onap-service/src/test/resources/es_test_scripts/topoHistoryConfigSettings.json b/sparkybe-onap-service/src/test/resources/es_test_scripts/topoHistoryConfigSettings.json
new file mode 100644
index 0000000..875813e
--- /dev/null
+++ b/sparkybe-onap-service/src/test/resources/es_test_scripts/topoHistoryConfigSettings.json
@@ -0,0 +1,20 @@
+{
+ "topographyhistorysearchindex-localhost" : {
+ "mappings" : {
+ "default" : {
+ "properties" : {
+ "count" : {
+ "type" : "keyword"
+ },
+ "entityType" : {
+ "type" : "keyword"
+ },
+ "timestamp" : {
+ "type" : "date",
+ "format" : "MMM d y HH:m:s||dd-MM-yyyy HH:mm:ss||yyyy-MM-dd'T'HH:mm:ss.SSSZZ||MM/dd/yyyy||yyyyMMdd'T'HHmmssZ"
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/sparkybe-onap-service/src/test/resources/es_test_scripts/topographicalConfigSettings.json b/sparkybe-onap-service/src/test/resources/es_test_scripts/topographicalConfigSettings.json
new file mode 100644
index 0000000..c9f5d5d
--- /dev/null
+++ b/sparkybe-onap-service/src/test/resources/es_test_scripts/topographicalConfigSettings.json
@@ -0,0 +1,24 @@
+{
+ "mappings": {
+ "default": {
+ "properties": {
+ "pkey": {
+ "type": "string"
+ },
+ "entityType": {
+ "type": "string"
+ },
+ "longitude": {
+ "type": "string"
+ },
+ "latitude": {
+ "type": "string"
+ },
+ "selfLink": {
+ "type": "string"
+ }
+ }
+ }
+
+ }
+}
diff --git a/sparkybe-onap-service/src/test/resources/es_test_scripts/topographysearch_schema.json b/sparkybe-onap-service/src/test/resources/es_test_scripts/topographysearch_schema.json
new file mode 100644
index 0000000..5de6904
--- /dev/null
+++ b/sparkybe-onap-service/src/test/resources/es_test_scripts/topographysearch_schema.json
@@ -0,0 +1,9 @@
+{
+ "fields": [
+ {"name": "pkey", "data-type": "string", "searchable": "false"},
+ {"name": "entityType", "data-type": "string", "searchable": "false"},
+ {"name": "latitude", "data-type": "string", "searchable": "false"},
+ {"name": "longitude", "data-type": "string", "searchable": "false"},
+ {"name": "selfLink", "data-type": "string", "searchable": "false"}
+ ]
+} \ No newline at end of file
diff --git a/sparkybe-onap-service/src/test/resources/filters/AggregationSuggestionEntity_getIndexDocumentJson_expected.json b/sparkybe-onap-service/src/test/resources/filters/AggregationSuggestionEntity_getIndexDocumentJson_expected.json
new file mode 100644
index 0000000..53e9ec9
--- /dev/null
+++ b/sparkybe-onap-service/src/test/resources/filters/AggregationSuggestionEntity_getIndexDocumentJson_expected.json
@@ -0,0 +1 @@
+"filterList":[{"filterId":"1"},{"filterId":"2"},{"filterId":"7"},{"filterId":"8"}] \ No newline at end of file
diff --git a/sparkybe-onap-service/src/test/resources/filters/aaiui_filters.json b/sparkybe-onap-service/src/test/resources/filters/aaiui_filters.json
new file mode 100644
index 0000000..31716ed
--- /dev/null
+++ b/sparkybe-onap-service/src/test/resources/filters/aaiui_filters.json
@@ -0,0 +1,88 @@
+{
+ "filters": [
+ {
+ "filterId": "1",
+ "filterName": "Orchestration-Status",
+ "displayName": "Orchestration Status",
+ "dataType": "list",
+ "dataSource": {
+ "indexName": "aggregate_generic-vnf_index",
+ "docType": "default",
+ "fieldName": "orchestration-status"
+ }
+ },
+ {
+ "filterId": "2",
+ "filterName": "Prov-Status",
+ "displayName": "Provisioning Status",
+ "dataType": "list",
+ "dataSource": {
+ "indexName": "aggregate_generic-vnf_index",
+ "docType": "default",
+ "fieldName": "prov-status"
+ }
+ },
+ {
+ "filterId": "3",
+ "filterName": "Severity",
+ "displayName": "Severity",
+ "dataType": "list",
+ "dataSource": {
+ "indexName": "di-violations",
+ "docType": "default",
+ "fieldName": "severity"
+ }
+ },
+ {
+ "filterId": "4",
+ "filterName": "Category",
+ "displayName": "Category",
+ "dataType": "list",
+ "dataSource": {
+ "indexName": "di-violations",
+ "docType": "default",
+ "fieldName": "category"
+ }
+ },
+ {
+ "filterId": "5",
+ "filterName": "Date",
+ "displayName": "Date",
+ "dataType": "date"
+ },
+ {
+ "filterId": "6",
+ "filterName": "EntityType",
+ "displayName": "Object Type",
+ "dataType": "list",
+ "dataSource": {
+ "indexName": "di-violations",
+ "docType": "default",
+ "fieldName": "entityType"
+ }
+ },
+ {
+ "filterId": "7",
+ "filterName": "NF-Type",
+ "displayName": "Network Function Type",
+ "dataType": "list",
+ "dataSource": {
+ "indexName": "aggregate_generic-vnf_index",
+ "docType": "default",
+ "fieldName": "nf-type"
+ }
+ },
+ {
+ "filterId": "8",
+ "filterName": "NF-Role",
+ "displayName": "Network Function Role",
+ "dataType": "list",
+ "dataSource": {
+ "indexName": "aggregate_generic-vnf_index",
+ "docType": "default",
+ "fieldName": "nf-role"
+ }
+ }
+
+ ]
+} \ No newline at end of file
diff --git a/sparkybe-onap-service/src/test/resources/filters/aaiui_filters_testConfig.json b/sparkybe-onap-service/src/test/resources/filters/aaiui_filters_testConfig.json
new file mode 100644
index 0000000..62b6811
--- /dev/null
+++ b/sparkybe-onap-service/src/test/resources/filters/aaiui_filters_testConfig.json
@@ -0,0 +1,79 @@
+{
+ "filters": [
+ {
+ "filterId": "1",
+ "filterName": "Orchestration-Status",
+ "displayName": "Orchestration Status",
+ "dataType": "dropDown",
+ "multiSelect": "false",
+ "watermark": "Any Orchestration Status",
+ "optionsType": "options",
+ "dataSource": {
+ "indexName": "aggregate_generic-vnf_index",
+ "docType": "default",
+ "fieldName": "orchestration-status"
+ }
+ },
+ {
+ "filterId": "2",
+ "filterName": "Prov-Status",
+ "displayName": "Provisioning Status",
+ "dataType": "dropDown",
+ "multiSelect": "false",
+ "watermark": "Any Provisioning Status",
+ "optionsType": "options",
+ "dataSource": {
+ "indexName": "aggregate_generic-vnf_index",
+ "docType": "default",
+ "fieldName": "prov-status"
+ }
+ },
+ {
+ "filterId": "5",
+ "filterName": "Date",
+ "displayName": "Date",
+ "dataType": "date",
+ "multiSelect": "false",
+ "watermark": "Choose Date Range",
+ "defaultValue" : {"decode": "Today", "code": "last_0_hours"},
+ "optionsType": "dynamicOptions",
+ "optionsValues": [
+ {"decode": "Today", "code": "last_0_hours"},
+ {"decode": "Since Yesterday", "code": "last_1_days"},
+ {"decode": "Since Last Week", "code": "last_1_weeks"},
+ {"decode": "Since Last Month", "code": "last_1_months"},
+ {"decode": "Since Last Year", "code": "last_1_years"},
+ {"decode": "Custom Range", "code": "custom_range"}
+ ]
+ },
+ {
+ "filterId": "7",
+ "filterName": "NF-Type",
+ "displayName": "Network Function Type",
+ "dataType": "dropDown",
+ "multiSelect": "false",
+ "watermark": "Any Network Function Type",
+ "optionsType": "options",
+ "dataSource": {
+ "indexName": "aggregate_generic-vnf_index",
+ "docType": "default",
+ "fieldName": "nf-type"
+ }
+ },
+ {
+ "filterId": "8",
+ "filterName": "NF-Role",
+ "displayName": "Network Function Role",
+ "dataType": "dropDown",
+ "multiSelect": "false",
+ "watermark": "Any Network Function Role",
+ "optionsType": "options",
+ "dataSource": {
+ "indexName": "aggregate_generic-vnf_index",
+ "docType": "default",
+ "fieldName": "nf-role"
+ }
+ }
+
+ ]
+} \ No newline at end of file
diff --git a/sparkybe-onap-service/src/test/resources/filters/aaiui_views.json b/sparkybe-onap-service/src/test/resources/filters/aaiui_views.json
new file mode 100644
index 0000000..e6ece9f
--- /dev/null
+++ b/sparkybe-onap-service/src/test/resources/filters/aaiui_views.json
@@ -0,0 +1,38 @@
+{
+ "views": [
+ {
+ "viewName" : "vnfSearch",
+ "filters" : [
+ {
+ "filterId": "1"
+ },
+ {
+ "filterId": "2"
+ },
+ {
+ "filterId": "7"
+ },
+ {
+ "filterId": "8"
+ }
+ ]
+ },
+ {
+ "viewName" : "dataIntegrity",
+ "filters" : [
+ {
+ "filterId": "3"
+ },
+ {
+ "filterId": "4"
+ },
+ {
+ "filterId": "5"
+ },
+ {
+ "filterId": "6"
+ }
+ ]
+ }
+ ]
+} \ No newline at end of file
diff --git a/sparkybe-onap-service/src/test/resources/filters/aaiui_views_testConfig.json b/sparkybe-onap-service/src/test/resources/filters/aaiui_views_testConfig.json
new file mode 100644
index 0000000..9ca0119
--- /dev/null
+++ b/sparkybe-onap-service/src/test/resources/filters/aaiui_views_testConfig.json
@@ -0,0 +1,21 @@
+{
+ "views": [
+ {
+ "viewName" : "vnfSearch",
+ "filters" : [
+ {
+ "filterId": "1"
+ },
+ {
+ "filterId": "2"
+ },
+ {
+ "filterId": "7"
+ },
+ {
+ "filterId": "8"
+ }
+ ]
+ }
+ ]
+} \ No newline at end of file
diff --git a/sparkybe-onap-service/src/test/resources/filters/filterAggregationEndpoint_emptyRequestBody_expectedResponse.json b/sparkybe-onap-service/src/test/resources/filters/filterAggregationEndpoint_emptyRequestBody_expectedResponse.json
new file mode 100644
index 0000000..95a2b16
--- /dev/null
+++ b/sparkybe-onap-service/src/test/resources/filters/filterAggregationEndpoint_emptyRequestBody_expectedResponse.json
@@ -0,0 +1 @@
+{"count":0} \ No newline at end of file
diff --git a/sparkybe-onap-service/src/test/resources/filters/filterAggregationEndpoint_emptyRequestFilterArray_expectedResponse.json b/sparkybe-onap-service/src/test/resources/filters/filterAggregationEndpoint_emptyRequestFilterArray_expectedResponse.json
new file mode 100644
index 0000000..36ae0a5
--- /dev/null
+++ b/sparkybe-onap-service/src/test/resources/filters/filterAggregationEndpoint_emptyRequestFilterArray_expectedResponse.json
@@ -0,0 +1 @@
+{"groupby_aggregation":[{"totalChartHits":0,"buckets":[]}]} \ No newline at end of file
diff --git a/sparkybe-onap-service/src/test/resources/filters/filterAggregationEndpoint_emptyRequestFilterArray_requestBody.json b/sparkybe-onap-service/src/test/resources/filters/filterAggregationEndpoint_emptyRequestFilterArray_requestBody.json
new file mode 100644
index 0000000..ba7d987
--- /dev/null
+++ b/sparkybe-onap-service/src/test/resources/filters/filterAggregationEndpoint_emptyRequestFilterArray_requestBody.json
@@ -0,0 +1,3 @@
+{
+ "filters": []
+} \ No newline at end of file
diff --git a/sparkybe-onap-service/src/test/resources/filters/filterAggregationEndpoint_successPath_expectedResponse.json b/sparkybe-onap-service/src/test/resources/filters/filterAggregationEndpoint_successPath_expectedResponse.json
new file mode 100644
index 0000000..e2c5766
--- /dev/null
+++ b/sparkybe-onap-service/src/test/resources/filters/filterAggregationEndpoint_successPath_expectedResponse.json
@@ -0,0 +1 @@
+{"total":116,"aggregations":{"prov-status":[{"doc_count":77,"key":""},{"doc_count":2,"key":"PREPROV"}],"orchestration-status":[{"doc_count":116,"key":"Created"}]}}
diff --git a/sparkybe-onap-service/src/test/resources/filters/filterAggregationEndpoint_successPath_operationResult.json b/sparkybe-onap-service/src/test/resources/filters/filterAggregationEndpoint_successPath_operationResult.json
new file mode 100644
index 0000000..753a11f
--- /dev/null
+++ b/sparkybe-onap-service/src/test/resources/filters/filterAggregationEndpoint_successPath_operationResult.json
@@ -0,0 +1 @@
+{"took":39,"timed_out":false,"_shards":{"total":5,"successful":5,"failed":0},"hits":{"total":116,"max_score":0.0,"hits":[]},"aggregations":{"prov-status":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"","doc_count":77},{"key":"PREPROV","doc_count":2}]},"orchestration-status":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"Created","doc_count":116}]}}} \ No newline at end of file
diff --git a/sparkybe-onap-service/src/test/resources/filters/filterAggregationEndpoint_successPath_requestBody.json b/sparkybe-onap-service/src/test/resources/filters/filterAggregationEndpoint_successPath_requestBody.json
new file mode 100644
index 0000000..c321760
--- /dev/null
+++ b/sparkybe-onap-service/src/test/resources/filters/filterAggregationEndpoint_successPath_requestBody.json
@@ -0,0 +1,11 @@
+{
+ "filters": [
+ {
+ "filterId": "1",
+ "filterValue": "Created"
+ },
+ {
+ "filterId": "2"
+ }
+ ]
+} \ No newline at end of file
diff --git a/sparkybe-onap-service/src/test/resources/portal/portal-authentication.properties b/sparkybe-onap-service/src/test/resources/portal/portal-authentication.properties
new file mode 100644
index 0000000..c3c34d6
--- /dev/null
+++ b/sparkybe-onap-service/src/test/resources/portal/portal-authentication.properties
@@ -0,0 +1,2 @@
+username=testuser
+password=OBF:1vv31vn61xtv1zlo1y0s1v1p1v2p1y0y1zlu1xtn1vnw1vu7 \ No newline at end of file
diff --git a/sparkybe-onap-service/src/test/resources/portal/roles.config b/sparkybe-onap-service/src/test/resources/portal/roles.config
new file mode 100644
index 0000000..b8313bd
--- /dev/null
+++ b/sparkybe-onap-service/src/test/resources/portal/roles.config
@@ -0,0 +1,6 @@
+[
+ {
+ "id":1,
+ "name":"View"
+ }
+] \ No newline at end of file
diff --git a/sparkybe-onap-service/src/test/resources/sync/ElasticSearch/AfterSync_ElasticSearch_ScrollApi_Successful.json b/sparkybe-onap-service/src/test/resources/sync/ElasticSearch/AfterSync_ElasticSearch_ScrollApi_Successful.json
new file mode 100644
index 0000000..014e194
--- /dev/null
+++ b/sparkybe-onap-service/src/test/resources/sync/ElasticSearch/AfterSync_ElasticSearch_ScrollApi_Successful.json
@@ -0,0 +1,171 @@
+{
+ "_scroll_id": "cXVlcnlUaGVuRmV0Y2g7NTs1MzA6T2dvOXI5ekVSWkdTM0JBQ0tnR0Jvdzs1Mjg6T2dvOXI5ekVSWkdTM0JBQ0tnR0Jvdzs1Mjc6T2dvOXI5ekVSWkdTM0JBQ0tnR0Jvdzs1MjY6T2dvOXI5ekVSWkdTM0JBQ0tnR0Jvdzs1Mjk6T2dvOXI5ekVSWkdTM0JBQ0tnR0JvdzswOw==",
+ "took": 29,
+ "timed_out": false,
+ "_shards": {
+ "total": 5,
+ "successful": 5,
+ "failed": 0
+ },
+ "hits": {
+ "total": 1345,
+ "max_score": 1,
+ "hits": [
+ {
+ "_index": "entitysearchindex-localhost",
+ "_type": "default",
+ "_id": "7defe67ea13549fcf8163c755db0d8595f32da23022966e3313281474a551742DWH",
+ "_score": 1,
+ "_source": {
+ "entityType": "generic-vnf",
+ "entityPrimaryKeyValue": "genericvnft2i12bd2",
+ "link": "/aai/v11/network/generic-vnfs/generic-vnf/genericvnft2i12bd2",
+ "searchTags": "genericvnft2i12bd2;genericvnft2i12bd2",
+ "searchTagIDs": "vnf-id;vnf-name",
+ "lastmodTimestamp": "2018-01-29T03:35:40.413-0500"
+ }
+ },
+ {
+ "_index": "entitysearchindex-localhost",
+ "_type": "default",
+ "_id": "981d7d3e27d91cbf118b01e6b5415ecbe1622a0c6c2afe4e04f91919f37f8fbeDWH",
+ "_score": 1,
+ "_source": {
+ "entityType": "complex",
+ "entityPrimaryKeyValue": "STUB-609ccabb-7504-3e23-91a4-30d29776e792",
+ "link": "/aai/v11/cloud-infrastructure/complexes/complex/STUB-609ccabb-7504-3e23-91a4-30d29776e792",
+ "searchTags": "STUB-609ccabb-7504-3e23-91a4-30d29776e792;Sydney;BennelongPoint; 2000",
+ "searchTagIDs": "physical-location-id;complex-name;street1;postal-code",
+ "lastmodTimestamp": "2018-01-25T13:15:57.471-0500"
+ }
+ },
+ {
+ "_index": "entitysearchindex-localhost",
+ "_type": "default",
+ "_id": "89788f6bbcddfe40a5248fdb2c46c380aaea66f61e56c66e00d815163ddf98c4DWH",
+ "_score": 1,
+ "_source": {
+ "entityType": "pnf",
+ "entityPrimaryKeyValue": "NSG34-ANZBank",
+ "link": "/aai/v11/network/pnfs/pnf/NSG34-ANZBank",
+ "searchTags": "NSG34-ANZBank",
+ "searchTagIDs": "pnf-name",
+ "lastmodTimestamp": "2018-01-25T13:15:50.890-0500"
+ }
+ },
+ {
+ "_index": "entitysearchindex-localhost",
+ "_type": "default",
+ "_id": "76ec93a5740e6c519dbbe4f20c366bf8114273adc13db228bc3012658ec80e57DWH",
+ "_score": 1,
+ "_source": {
+ "entityType": "service-instance",
+ "entityPrimaryKeyValue": "84635d51-0183-4078-850b-8eeb1ac88a5a",
+ "link": "/aai/v11/business/customers/customer/ANZBank/service-subscriptions/service-subscription/SDWAN-CPE/service-instances/service-instance/84635d51-0183-4078-850b-8eeb1ac88a5a",
+ "searchTags": "84635d51-0183-4078-850b-8eeb1ac88a5a;CPE-PERTH-NSG32",
+ "searchTagIDs": "service-instance-id;service-instance-name",
+ "lastmodTimestamp": "2018-01-25T13:15:55.672-0500"
+ }
+ },
+ {
+ "_index": "entitysearchindex-localhost",
+ "_type": "default",
+ "_id": "1ad1fbf279a6f822db790bc1d1143b6c09be33dbcae870b332bcb622b42bb208DWH",
+ "_score": 1,
+ "_source": {
+ "entityType": "service-instance",
+ "entityPrimaryKeyValue": "69d0ab4c-1ab1-4488-997d-d6f8ae82bfeb",
+ "link": "/aai/v11/business/customers/customer/AEESDNC/service-subscriptions/service-subscription/SDWAN-DOMAIN/service-instances/service-instance/69d0ab4c-1ab1-4488-997d-d6f8ae82bfeb",
+ "searchTags": "69d0ab4c-1ab1-4488-997d-d6f8ae82bfeb;Domain-AEESDNC",
+ "searchTagIDs": "service-instance-id;service-instance-name",
+ "lastmodTimestamp": "2018-01-25T13:15:54.341-0500"
+ }
+ },
+ {
+ "_index": "entitysearchindex-localhost",
+ "_type": "default",
+ "_id": "11b0c483640efdac72d39859387aa623b2059d8ac35bf5310b3ef0d77c0eaebcDWH",
+ "_score": 1,
+ "_source": {
+ "entityType": "generic-vnf",
+ "entityPrimaryKeyValue": "genericvnft1i1bd2",
+ "link": "/aai/v11/network/generic-vnfs/generic-vnf/genericvnft1i1bd2",
+ "searchTags": "genericvnft1i1bd2;genericvnft1i1bd2",
+ "searchTagIDs": "vnf-id;vnf-name",
+ "lastmodTimestamp": "2018-01-29T03:35:28.908-0500"
+ }
+ },
+ {
+ "_index": "entitysearchindex-localhost",
+ "_type": "default",
+ "_id": "44182de194b1b4b6ad8002bf79277cf7be2b3143d2cc4e84c2ce80c46574a550DWH",
+ "_score": 1,
+ "_source": {
+ "entityType": "generic-vnf",
+ "entityPrimaryKeyValue": "genericvnft3i1be2",
+ "link": "/aai/v11/network/generic-vnfs/generic-vnf/genericvnft3i1be2",
+ "searchTags": "genericvnft3i1be2;genericvnft3i1be2",
+ "searchTagIDs": "vnf-id;vnf-name",
+ "lastmodTimestamp": "2018-01-29T03:35:47.064-0500"
+ }
+ },
+ {
+ "_index": "entitysearchindex-localhost",
+ "_type": "default",
+ "_id": "ee9e7975cb6db6deb2222802b7cac2dd1ec122341742ce4efb1e34c792712679DWH",
+ "_score": 1,
+ "_source": {
+ "entityType": "customer",
+ "entityPrimaryKeyValue": "Barclays",
+ "link": "/aai/v11/business/customers/customer/Barclays",
+ "searchTags": "Barclays;Barclays",
+ "searchTagIDs": "global-customer-id;subscriber-name",
+ "lastmodTimestamp": "2018-01-25T13:16:00.301-0500"
+ }
+ },
+ {
+ "_index": "entitysearchindex-localhost",
+ "_type": "default",
+ "_id": "f05c00191ad4746d4a2e7457e5f378df328cf7edfd4f99cc5ad8688be0185fd2DWH",
+ "_score": 1,
+ "_source": {
+ "entityType": "customer",
+ "entityPrimaryKeyValue": "AEESDNC",
+ "link": "/aai/v11/business/customers/customer/AEESDNC",
+ "searchTags": "AEESDNC;AEESDNC",
+ "searchTagIDs": "global-customer-id;subscriber-name",
+ "lastmodTimestamp": "2018-01-25T13:16:00.390-0500"
+ }
+ },
+ {
+ "_index": "entitysearchindex-localhost",
+ "_type": "default",
+ "_id": "96be943f01d1db1fe8a3c6ffd03f79385d99dc8d351a6292980fc1af93da987bDWH",
+ "_score": 1,
+ "_source": {
+ "entityType": "generic-vnf",
+ "entityPrimaryKeyValue": "aeetest_vnf1_under_fw-si1",
+ "link": "/aai/v11/network/generic-vnfs/generic-vnf/aeetest_vnf1_under_fw-si1",
+ "searchTags": "aeetest_vnf1_under_fw-si1;aeetest_vnf1_under_fw-si1",
+ "searchTagIDs": "vnf-id;vnf-name",
+ "lastmodTimestamp": "2018-01-29T03:35:51.548-0500"
+ }
+ },
+ {
+ "_index": "entitysearchindex-localhost",
+ "_type": "default",
+ "_id": "96be943f01d1db1fe8a3c6ffd03f79385d99dc8d351a6292980fc1af93da987bDWH2",
+ "_score": 1,
+ "_source": {
+ "entityType": "generic-vnf",
+ "entityPrimaryKeyValue": "aeetest_vnf1_under_fw-si12",
+ "link": "/aai/v11/network/generic-vnfs/generic-vnf/aeetest_vnf1_under_fw-si12",
+ "searchTags": "aeetest_vnf1_under_fw-si1;aeetest_vnf1_under_fw-si12",
+ "searchTagIDs": "vnf-id;vnf-name",
+ "lastmodTimestamp": "2018-01-29T03:35:51.548-0502"
+ }
+ }
+
+ ]
+ }
+} \ No newline at end of file
diff --git a/sparkybe-onap-service/src/test/resources/sync/ElasticSearch/BeforeSync_ElasticSearch_ScrollApi_Successful.json b/sparkybe-onap-service/src/test/resources/sync/ElasticSearch/BeforeSync_ElasticSearch_ScrollApi_Successful.json
new file mode 100644
index 0000000..38fc297
--- /dev/null
+++ b/sparkybe-onap-service/src/test/resources/sync/ElasticSearch/BeforeSync_ElasticSearch_ScrollApi_Successful.json
@@ -0,0 +1,156 @@
+{
+ "_scroll_id": "cXVlcnlUaGVuRmV0Y2g7NTs1MzA6T2dvOXI5ekVSWkdTM0JBQ0tnR0Jvdzs1Mjg6T2dvOXI5ekVSWkdTM0JBQ0tnR0Jvdzs1Mjc6T2dvOXI5ekVSWkdTM0JBQ0tnR0Jvdzs1MjY6T2dvOXI5ekVSWkdTM0JBQ0tnR0Jvdzs1Mjk6T2dvOXI5ekVSWkdTM0JBQ0tnR0JvdzswOw==",
+ "took": 29,
+ "timed_out": false,
+ "_shards": {
+ "total": 5,
+ "successful": 5,
+ "failed": 0
+ },
+ "hits": {
+ "total": 1345,
+ "max_score": 1,
+ "hits": [
+ {
+ "_index": "entitysearchindex-localhost",
+ "_type": "default",
+ "_id": "7defe67ea13549fcf8163c755db0d8595f32da23022966e3313281474a551742",
+ "_score": 1,
+ "_source": {
+ "entityType": "generic-vnf",
+ "entityPrimaryKeyValue": "genericvnft2i12bd2",
+ "link": "/aai/v11/network/generic-vnfs/generic-vnf/genericvnft2i12bd2",
+ "searchTags": "genericvnft2i12bd2;genericvnft2i12bd2",
+ "searchTagIDs": "vnf-id;vnf-name",
+ "lastmodTimestamp": "2018-01-29T03:35:40.413-0500"
+ }
+ },
+ {
+ "_index": "entitysearchindex-localhost",
+ "_type": "default",
+ "_id": "981d7d3e27d91cbf118b01e6b5415ecbe1622a0c6c2afe4e04f91919f37f8fbe",
+ "_score": 1,
+ "_source": {
+ "entityType": "complex",
+ "entityPrimaryKeyValue": "STUB-609ccabb-7504-3e23-91a4-30d29776e792",
+ "link": "/aai/v11/cloud-infrastructure/complexes/complex/STUB-609ccabb-7504-3e23-91a4-30d29776e792",
+ "searchTags": "STUB-609ccabb-7504-3e23-91a4-30d29776e792;Sydney;BennelongPoint; 2000",
+ "searchTagIDs": "physical-location-id;complex-name;street1;postal-code",
+ "lastmodTimestamp": "2018-01-25T13:15:57.471-0500"
+ }
+ },
+ {
+ "_index": "entitysearchindex-localhost",
+ "_type": "default",
+ "_id": "89788f6bbcddfe40a5248fdb2c46c380aaea66f61e56c66e00d815163ddf98c4",
+ "_score": 1,
+ "_source": {
+ "entityType": "pnf",
+ "entityPrimaryKeyValue": "NSG34-ANZBank",
+ "link": "/aai/v11/network/pnfs/pnf/NSG34-ANZBank",
+ "searchTags": "NSG34-ANZBank",
+ "searchTagIDs": "pnf-name",
+ "lastmodTimestamp": "2018-01-25T13:15:50.890-0500"
+ }
+ },
+ {
+ "_index": "entitysearchindex-localhost",
+ "_type": "default",
+ "_id": "76ec93a5740e6c519dbbe4f20c366bf8114273adc13db228bc3012658ec80e57",
+ "_score": 1,
+ "_source": {
+ "entityType": "service-instance",
+ "entityPrimaryKeyValue": "84635d51-0183-4078-850b-8eeb1ac88a5a",
+ "link": "/aai/v11/business/customers/customer/ANZBank/service-subscriptions/service-subscription/SDWAN-CPE/service-instances/service-instance/84635d51-0183-4078-850b-8eeb1ac88a5a",
+ "searchTags": "84635d51-0183-4078-850b-8eeb1ac88a5a;CPE-PERTH-NSG32",
+ "searchTagIDs": "service-instance-id;service-instance-name",
+ "lastmodTimestamp": "2018-01-25T13:15:55.672-0500"
+ }
+ },
+ {
+ "_index": "entitysearchindex-localhost",
+ "_type": "default",
+ "_id": "1ad1fbf279a6f822db790bc1d1143b6c09be33dbcae870b332bcb622b42bb208",
+ "_score": 1,
+ "_source": {
+ "entityType": "service-instance",
+ "entityPrimaryKeyValue": "69d0ab4c-1ab1-4488-997d-d6f8ae82bfeb",
+ "link": "/aai/v11/business/customers/customer/AEESDNC/service-subscriptions/service-subscription/SDWAN-DOMAIN/service-instances/service-instance/69d0ab4c-1ab1-4488-997d-d6f8ae82bfeb",
+ "searchTags": "69d0ab4c-1ab1-4488-997d-d6f8ae82bfeb;Domain-AEESDNC",
+ "searchTagIDs": "service-instance-id;service-instance-name",
+ "lastmodTimestamp": "2018-01-25T13:15:54.341-0500"
+ }
+ },
+ {
+ "_index": "entitysearchindex-localhost",
+ "_type": "default",
+ "_id": "11b0c483640efdac72d39859387aa623b2059d8ac35bf5310b3ef0d77c0eaebc",
+ "_score": 1,
+ "_source": {
+ "entityType": "generic-vnf",
+ "entityPrimaryKeyValue": "genericvnft1i1bd2",
+ "link": "/aai/v11/network/generic-vnfs/generic-vnf/genericvnft1i1bd2",
+ "searchTags": "genericvnft1i1bd2;genericvnft1i1bd2",
+ "searchTagIDs": "vnf-id;vnf-name",
+ "lastmodTimestamp": "2018-01-29T03:35:28.908-0500"
+ }
+ },
+ {
+ "_index": "entitysearchindex-localhost",
+ "_type": "default",
+ "_id": "44182de194b1b4b6ad8002bf79277cf7be2b3143d2cc4e84c2ce80c46574a550",
+ "_score": 1,
+ "_source": {
+ "entityType": "generic-vnf",
+ "entityPrimaryKeyValue": "genericvnft3i1be2",
+ "link": "/aai/v11/network/generic-vnfs/generic-vnf/genericvnft3i1be2",
+ "searchTags": "genericvnft3i1be2;genericvnft3i1be2",
+ "searchTagIDs": "vnf-id;vnf-name",
+ "lastmodTimestamp": "2018-01-29T03:35:47.064-0500"
+ }
+ },
+ {
+ "_index": "entitysearchindex-localhost",
+ "_type": "default",
+ "_id": "ee9e7975cb6db6deb2222802b7cac2dd1ec122341742ce4efb1e34c792712679",
+ "_score": 1,
+ "_source": {
+ "entityType": "customer",
+ "entityPrimaryKeyValue": "Barclays",
+ "link": "/aai/v11/business/customers/customer/Barclays",
+ "searchTags": "Barclays;Barclays",
+ "searchTagIDs": "global-customer-id;subscriber-name",
+ "lastmodTimestamp": "2018-01-25T13:16:00.301-0500"
+ }
+ },
+ {
+ "_index": "entitysearchindex-localhost",
+ "_type": "default",
+ "_id": "f05c00191ad4746d4a2e7457e5f378df328cf7edfd4f99cc5ad8688be0185fd2",
+ "_score": 1,
+ "_source": {
+ "entityType": "customer",
+ "entityPrimaryKeyValue": "AEESDNC",
+ "link": "/aai/v11/business/customers/customer/AEESDNC",
+ "searchTags": "AEESDNC;AEESDNC",
+ "searchTagIDs": "global-customer-id;subscriber-name",
+ "lastmodTimestamp": "2018-01-25T13:16:00.390-0500"
+ }
+ },
+ {
+ "_index": "entitysearchindex-localhost",
+ "_type": "default",
+ "_id": "96be943f01d1db1fe8a3c6ffd03f79385d99dc8d351a6292980fc1af93da987b",
+ "_score": 1,
+ "_source": {
+ "entityType": "generic-vnf",
+ "entityPrimaryKeyValue": "aeetest_vnf1_under_fw-si1",
+ "link": "/aai/v11/network/generic-vnfs/generic-vnf/aeetest_vnf1_under_fw-si1",
+ "searchTags": "aeetest_vnf1_under_fw-si1;aeetest_vnf1_under_fw-si1",
+ "searchTagIDs": "vnf-id;vnf-name",
+ "lastmodTimestamp": "2018-01-29T03:35:51.548-0500"
+ }
+ }
+ ]
+ }
+} \ No newline at end of file
diff --git a/sparkybe-onap-service/src/test/resources/sync/ElasticSearch/docEntityFromElasticSearch1.json b/sparkybe-onap-service/src/test/resources/sync/ElasticSearch/docEntityFromElasticSearch1.json
new file mode 100644
index 0000000..904c729
--- /dev/null
+++ b/sparkybe-onap-service/src/test/resources/sync/ElasticSearch/docEntityFromElasticSearch1.json
@@ -0,0 +1,17 @@
+{
+ "_index" : "aggregate_generic-vnf_index",
+ "_type" : "default",
+ "_id" : "a5583fff3d57e0412363a9edfc265fd95374e6e0ef7b7061c7286622da904848",
+ "_version" : 1,
+ "found" : true,
+ "_source" : {
+ "link" : "/aai/v11/network/generic-vnfs/generic-vnf/genericvnft2i11bd2",
+ "lastmodTimestamp" : "2018-01-29T03:35:46.859-0500",
+ "vnf-id" : "genericvnft2i11bd2",
+ "in-maint" : "false",
+ "resource-version" : "1508939769479",
+ "vnf-name" : "genericvnft2i11bd2",
+ "vnf-type" : "VirtualNetworkFunctionType",
+ "is-closed-loop-disabled" : "true"
+ }
+ } \ No newline at end of file
diff --git a/sparkybe-onap-service/src/test/resources/sync/ElasticSearch/docEntityFromElasticSearch2.json b/sparkybe-onap-service/src/test/resources/sync/ElasticSearch/docEntityFromElasticSearch2.json
new file mode 100644
index 0000000..7eb2317
--- /dev/null
+++ b/sparkybe-onap-service/src/test/resources/sync/ElasticSearch/docEntityFromElasticSearch2.json
@@ -0,0 +1,17 @@
+{
+ "_index" : "aggregate_generic-vnf_index",
+ "_type" : "default",
+ "_id" : "a5583fff3d57e0412363a9edfc265fd95374e6e0ef7b7061c7286622da9048482",
+ "_version" : 1,
+ "found" : true,
+ "_source" : {
+ "link" : "/aai/v11/network/generic-vnfs/generic-vnf/genericvnft2i11bd22",
+ "lastmodTimestamp" : "2018-01-29T03:35:46.859-0500",
+ "vnf-id" : "genericvnft2i11bd22",
+ "in-maint" : "false",
+ "resource-version" : "1508939769479",
+ "vnf-name" : "genericvnft2i11bd22",
+ "vnf-type" : "VirtualNetworkFunctionType",
+ "is-closed-loop-disabled" : "true"
+ }
+ } \ No newline at end of file
diff --git a/sparkybe-onap-service/src/test/resources/sync/ElasticSearch/docEntityFromElasticSearch3.json b/sparkybe-onap-service/src/test/resources/sync/ElasticSearch/docEntityFromElasticSearch3.json
new file mode 100644
index 0000000..6332610
--- /dev/null
+++ b/sparkybe-onap-service/src/test/resources/sync/ElasticSearch/docEntityFromElasticSearch3.json
@@ -0,0 +1,17 @@
+{
+ "_index" : "aggregate_generic-vnf_index",
+ "_type" : "default",
+ "_id" : "a5583fff3d57e0412363a9edfc265fd95374e6e0ef7b7061c7286622da9048483",
+ "_version" : 1,
+ "found" : true,
+ "_source" : {
+ "link" : "/aai/v11/network/generic-vnfs/generic-vnf/genericvnft2i11bd3",
+ "lastmodTimestamp" : "2018-01-29T03:35:46.859-0500",
+ "vnf-id" : "genericvnft2i11bd3",
+ "in-maint" : "false",
+ "resource-version" : "1508939769479",
+ "vnf-name" : "genericvnft2i11bd3",
+ "vnf-type" : "VirtualNetworkFunctionType",
+ "is-closed-loop-disabled" : "true"
+ }
+ } \ No newline at end of file
diff --git a/sparkybe-onap-service/src/test/resources/sync/ElasticSearch/docEntityFromElasticSearch4.json b/sparkybe-onap-service/src/test/resources/sync/ElasticSearch/docEntityFromElasticSearch4.json
new file mode 100644
index 0000000..71298e9
--- /dev/null
+++ b/sparkybe-onap-service/src/test/resources/sync/ElasticSearch/docEntityFromElasticSearch4.json
@@ -0,0 +1,17 @@
+{
+ "_index" : "aggregate_generic-vnf_index",
+ "_type" : "default",
+ "_id" : "a5583fff3d57e0412363a9edfc265fd95374e6e0ef7b7061c7286622da9048484",
+ "_version" : 1,
+ "found" : true,
+ "_source" : {
+ "link" : "/aai/v11/network/generic-vnfs/generic-vnf/genericvnft2i11bd4",
+ "lastmodTimestamp" : "2018-01-29T03:35:46.859-0500",
+ "vnf-id" : "genericvnft2i11bd4",
+ "in-maint" : "false",
+ "resource-version" : "1508939769479",
+ "vnf-name" : "genericvnft2i11bd4",
+ "vnf-type" : "VirtualNetworkFunctionType",
+ "is-closed-loop-disabled" : "true"
+ }
+} \ No newline at end of file
diff --git a/sparkybe-onap-service/src/test/resources/sync/ElasticSearch/docEntityFromElasticSearch5.json b/sparkybe-onap-service/src/test/resources/sync/ElasticSearch/docEntityFromElasticSearch5.json
new file mode 100644
index 0000000..08d8cdd
--- /dev/null
+++ b/sparkybe-onap-service/src/test/resources/sync/ElasticSearch/docEntityFromElasticSearch5.json
@@ -0,0 +1,17 @@
+{
+ "_index" : "aggregate_generic-vnf_index",
+ "_type" : "default",
+ "_id" : "a5583fff3d57e0412363a9edfc265fd95374e6e0ef7b7061c7286622da904848",
+ "_version" : 1,
+ "found" : true,
+ "_source" : {
+ "link" : "/aai/v11/network/generic-vnfs/generic-vnf/genericvnft2i11bd5",
+ "lastmodTimestamp" : "2018-01-29T03:35:46.859-0500",
+ "vnf-id" : "genericvnft2i11bd5",
+ "in-maint" : "false",
+ "resource-version" : "1508939769479",
+ "vnf-name" : "genericvnft2i11bd5",
+ "vnf-type" : "VirtualNetworkFunctionType",
+ "is-closed-loop-disabled" : "true"
+ }
+ } \ No newline at end of file
diff --git a/sparkybe-onap-service/src/test/resources/sync/aai/aai-resources/customer/customer-4.json b/sparkybe-onap-service/src/test/resources/sync/aai/aai-resources/customer/customer-4.json
new file mode 100644
index 0000000..df805ba
--- /dev/null
+++ b/sparkybe-onap-service/src/test/resources/sync/aai/aai-resources/customer/customer-4.json
@@ -0,0 +1,60 @@
+{
+ "global-customer-id": "customer-4",
+ "subscriber-name": "Gold",
+ "subscriber-type": "GoldType",
+ "resource-version": "1494001938080",
+ "service-subscriptions": {
+ "service-subscription": [
+ {
+ "service-type": "service-subscription-2",
+ "resource-version": "1494001891362",
+ "service-instances": {
+ "service-instance": [
+ {
+ "service-instance-id": "service-instance-54",
+ "service-instance-name": "si_failtest",
+ "model-invariant-id": "732263bd-0655-428d-a347-d65676d1a949",
+ "resource-version": "1494001997513"
+ },
+ {
+ "service-instance-id": "service-instance-55",
+ "service-instance-name": "test-343432",
+ "model-invariant-id": "709d1be4-9a3f-4a29-8c4d-a20465e808a3",
+ "model-version-id": "240376de-870e-48df-915a-31f140eedd2c",
+ "resource-version": "1500370094198",
+ "orchestration-status": "Active"
+ }
+ ]
+ },
+ "relationship-list": {
+ "relationship": [
+ {
+ "related-to": "tenant",
+ "related-link": "/aai/v11/cloud-infrastructure/cloud-regions/cloud-region/att-aic/mtn6/tenants/tenant/tenant-1",
+ "relationship-data": [
+ {
+ "relationship-key": "cloud-region.cloud-owner",
+ "relationship-value": "cotton-candy"
+ },
+ {
+ "relationship-key": "cloud-region.cloud-region-id",
+ "relationship-value": "fluffy-clouds"
+ },
+ {
+ "relationship-key": "tenant.tenant-id",
+ "relationship-value": "tenant-1"
+ }
+ ],
+ "related-to-property": [
+ {
+ "property-key": "tenant.tenant-name",
+ "property-value": "CandyMan"
+ }
+ ]
+ }
+ ]
+ }
+ }
+ ]
+ }
+} \ No newline at end of file
diff --git a/sparkybe-onap-service/src/test/resources/sync/aai/aai-resources/service-instance/service-instance-50.json b/sparkybe-onap-service/src/test/resources/sync/aai/aai-resources/service-instance/service-instance-50.json
new file mode 100644
index 0000000..17a48fc
--- /dev/null
+++ b/sparkybe-onap-service/src/test/resources/sync/aai/aai-resources/service-instance/service-instance-50.json
@@ -0,0 +1,26 @@
+{
+ "service-instance-id": "service-instance-50",
+ "service-instance-name": "s01",
+ "service-type": "",
+ "service-role": "",
+ "environment-context": "Universe",
+ "workload-context": "QuantumContext",
+ "model-invariant-id": "5b9c0f33-eec1-484a-bf77-736a6644d7a8",
+ "model-version-id": "b75e0d22-05ff-4448-9266-5f0d4e1dbbd6",
+ "resource-version": "1510659038818",
+ "orchestration-status": "Active",
+ "relationship-list": {
+ "relationship": [
+ {
+ "related-to": "project",
+ "related-link": "/aai/v11/business/projects/project/project1",
+ "relationship-data": [
+ {
+ "relationship-key": "project.project-name",
+ "relationship-value": "project1"
+ }
+ ]
+ }
+ ]
+ }
+}
diff --git a/sparkybe-onap-service/src/test/resources/sync/aai/aai-resources/service-instance/service-instance-51.json b/sparkybe-onap-service/src/test/resources/sync/aai/aai-resources/service-instance/service-instance-51.json
new file mode 100644
index 0000000..bfc5241
--- /dev/null
+++ b/sparkybe-onap-service/src/test/resources/sync/aai/aai-resources/service-instance/service-instance-51.json
@@ -0,0 +1,28 @@
+{
+ "service-instance-id": "service-instance-51",
+ "service-instance-name": "test765445g",
+ "model-invariant-id": "709d1be4-9a3f-4a29-8c4d-a20465e808a3",
+ "model-version-id": "240376de-870e-48df-915a-31f140eedd2c",
+ "resource-version": "1499868690949",
+ "orchestration-status": "Active",
+ "relationship-list": {
+ "relationship": [
+ {
+ "related-to": "generic-vnf",
+ "related-link": "/aai/v11/network/generic-vnfs/generic-vnf/fbb52a16-2c57-4212-802f-32dbba2204f2",
+ "relationship-data": [
+ {
+ "relationship-key": "generic-vnf.vnf-id",
+ "relationship-value": "fbb52a16-2c57-4212-802f-32dbba2204f2"
+ }
+ ],
+ "related-to-property": [
+ {
+ "property-key": "generic-vnf.vnf-name",
+ "property-value": "fdfdfdf"
+ }
+ ]
+ }
+ ]
+ }
+} \ No newline at end of file
diff --git a/sparkybe-onap-service/src/test/resources/sync/aai/aai-resources/service-instance/service-instance-52.json b/sparkybe-onap-service/src/test/resources/sync/aai/aai-resources/service-instance/service-instance-52.json
new file mode 100644
index 0000000..6083a8f
--- /dev/null
+++ b/sparkybe-onap-service/src/test/resources/sync/aai/aai-resources/service-instance/service-instance-52.json
@@ -0,0 +1,12 @@
+{
+ "service-instance-id": "service-instance-52",
+ "service-instance-name": "si52",
+ "service-type": "",
+ "service-role": "",
+ "environment-context": "null",
+ "workload-context": "null",
+ "model-invariant-id": "d7b48529-6ae2-49f0-8633-b29e7cd4d4ce",
+ "model-version-id": "44671b15-83dd-4db7-a36e-dfada3eaa2f9",
+ "resource-version": "1508144995828",
+ "orchestration-status": "Active"
+}
diff --git a/sparkybe-onap-service/src/test/resources/sync/aai/aai-resources/service-instance/service-instance-53.json b/sparkybe-onap-service/src/test/resources/sync/aai/aai-resources/service-instance/service-instance-53.json
new file mode 100644
index 0000000..5765c43
--- /dev/null
+++ b/sparkybe-onap-service/src/test/resources/sync/aai/aai-resources/service-instance/service-instance-53.json
@@ -0,0 +1,12 @@
+{
+ "service-instance-id": "service-instance-53",
+ "service-instance-name": "a1",
+ "service-type": "si53-type",
+ "service-role": "si53-role",
+ "environment-context": "Universe",
+ "workload-context": "Nano",
+ "model-invariant-id": "340f3957-ff0a-4503-866d-a34fd1b97450",
+ "model-version-id": "ee2d8783-8495-4fb1-9553-6cdbd2dd3a50",
+ "resource-version": "1509355912484",
+ "orchestration-status": "Active",
+} \ No newline at end of file
diff --git a/sparkybe-onap-service/src/test/resources/sync/aai/aai-resources/service-instance/service-instance-54.json b/sparkybe-onap-service/src/test/resources/sync/aai/aai-resources/service-instance/service-instance-54.json
new file mode 100644
index 0000000..249c38b
--- /dev/null
+++ b/sparkybe-onap-service/src/test/resources/sync/aai/aai-resources/service-instance/service-instance-54.json
@@ -0,0 +1,6 @@
+{
+ "service-instance-id": "service-instance-54",
+ "service-instance-name": "si_failtest",
+ "model-invariant-id": "732263bd-0655-428d-a347-d65676d1a949",
+ "resource-version": "1494001997513"
+}
diff --git a/sparkybe-onap-service/src/test/resources/sync/aai/aai-resources/service-instance/service-instance-55.json b/sparkybe-onap-service/src/test/resources/sync/aai/aai-resources/service-instance/service-instance-55.json
new file mode 100644
index 0000000..8db5b2e
--- /dev/null
+++ b/sparkybe-onap-service/src/test/resources/sync/aai/aai-resources/service-instance/service-instance-55.json
@@ -0,0 +1,8 @@
+{
+ "service-instance-id": "service-instance-55",
+ "service-instance-name": "test-343432",
+ "model-invariant-id": "709d1be4-9a3f-4a29-8c4d-a20465e808a3",
+ "model-version-id": "240376de-870e-48df-915a-31f140eedd2c",
+ "resource-version": "1500370094198",
+ "orchestration-status": "Active"
+}
diff --git a/sparkybe-onap-service/src/test/resources/sync/aai/aai-resources/service-instance/service-instance-56.json b/sparkybe-onap-service/src/test/resources/sync/aai/aai-resources/service-instance/service-instance-56.json
new file mode 100644
index 0000000..a87de6f
--- /dev/null
+++ b/sparkybe-onap-service/src/test/resources/sync/aai/aai-resources/service-instance/service-instance-56.json
@@ -0,0 +1,4 @@
+{
+ "service-instance-id": "service-instance-56",
+ "resource-version": "1495736709053"
+} \ No newline at end of file
diff --git a/sparkybe-onap-service/src/test/resources/sync/aai/aai-resources/service-instance/service-instance-57.json b/sparkybe-onap-service/src/test/resources/sync/aai/aai-resources/service-instance/service-instance-57.json
new file mode 100644
index 0000000..ce26fda
--- /dev/null
+++ b/sparkybe-onap-service/src/test/resources/sync/aai/aai-resources/service-instance/service-instance-57.json
@@ -0,0 +1,11 @@
+{
+ "service-instance-id": "service-instance-57",
+ "service-instance-name": "first_macro_shani",
+ "service-type": "",
+ "service-role": "",
+ "workload-context": "Universe",
+ "model-invariant-id": "5b9c0f33-eec1-484a-bf77-736a6644d7a8",
+ "model-version-id": "b75e0d22-05ff-4448-9266-5f0d4e1dbbd6",
+ "resource-version": "1508071197869",
+ "orchestration-status": "Active"
+} \ No newline at end of file
diff --git a/sparkybe-onap-service/src/test/resources/sync/aai/aai-resources/service-instance/service-instance-58.json b/sparkybe-onap-service/src/test/resources/sync/aai/aai-resources/service-instance/service-instance-58.json
new file mode 100644
index 0000000..7e6f5e9
--- /dev/null
+++ b/sparkybe-onap-service/src/test/resources/sync/aai/aai-resources/service-instance/service-instance-58.json
@@ -0,0 +1,32 @@
+{
+ "service-instance-id": "service-instance-58",
+ "service-instance-name": "a3",
+ "service-type": "",
+ "service-role": "",
+ "environment-context": "FluffyClouds",
+ "workload-context": "TasteGood",
+ "model-invariant-id": "d5937aa1-37fb-4ed0-8c30-5144b89a64ae",
+ "model-version-id": "06ac9663-54cf-4c77-b926-6e8757cf6380",
+ "resource-version": "1509356358573",
+ "orchestration-status": "Active",
+ "relationship-list": {
+ "relationship": [
+ {
+ "related-to": "generic-vnf",
+ "related-link": "/aai/v11/network/generic-vnfs/generic-vnf/9c925d7e-1a94-4784-a45b-408c8cc96fa8",
+ "relationship-data": [
+ {
+ "relationship-key": "generic-vnf.vnf-id",
+ "relationship-value": "9c925d7e-1a94-4784-a45b-408c8cc96fa8"
+ }
+ ],
+ "related-to-property": [
+ {
+ "property-key": "generic-vnf.vnf-name",
+ "property-value": "dfdsfds"
+ }
+ ]
+ }
+ ]
+ }
+} \ No newline at end of file
diff --git a/sparkybe-onap-service/src/test/resources/sync/aai/aai-resources/service-instance/service-instance-59.json b/sparkybe-onap-service/src/test/resources/sync/aai/aai-resources/service-instance/service-instance-59.json
new file mode 100644
index 0000000..37e7d35
--- /dev/null
+++ b/sparkybe-onap-service/src/test/resources/sync/aai/aai-resources/service-instance/service-instance-59.json
@@ -0,0 +1,4 @@
+{
+ "service-instance-id": "service-instance-59",
+ "resource-version": "1506087955081"
+}
diff --git a/sparkybe-onap-service/src/test/resources/sync/aai/aai-resources/service-subscription/service-subscription-2.json b/sparkybe-onap-service/src/test/resources/sync/aai/aai-resources/service-subscription/service-subscription-2.json
new file mode 100644
index 0000000..2d02ccc
--- /dev/null
+++ b/sparkybe-onap-service/src/test/resources/sync/aai/aai-resources/service-subscription/service-subscription-2.json
@@ -0,0 +1,50 @@
+{
+ "service-type": "service-subscription-2",
+ "resource-version": "1494001891362",
+ "service-instances": {
+ "service-instance": [
+ {
+ "service-instance-id": "service-instance-54",
+ "service-instance-name": "si_failtest",
+ "model-invariant-id": "732263bd-0655-428d-a347-d65676d1a949",
+ "resource-version": "1494001997513"
+ },
+ {
+ "service-instance-id": "service-instance-55",
+ "service-instance-name": "test-343432",
+ "model-invariant-id": "709d1be4-9a3f-4a29-8c4d-a20465e808a3",
+ "model-version-id": "240376de-870e-48df-915a-31f140eedd2c",
+ "resource-version": "1500370094198",
+ "orchestration-status": "Active"
+ }
+ ]
+ },
+ "relationship-list": {
+ "relationship": [
+ {
+ "related-to": "tenant",
+ "related-link": "/aai/v11/cloud-infrastructure/cloud-regions/cloud-region/myCloud/isBig/tenants/tenant/tenant-1",
+ "relationship-data": [
+ {
+ "relationship-key": "cloud-region.cloud-owner",
+ "relationship-value": "myCloud"
+ },
+ {
+ "relationship-key": "cloud-region.cloud-region-id",
+ "relationship-value": "isBig"
+ },
+ {
+ "relationship-key": "tenant.tenant-id",
+ "relationship-value": "tenant-1"
+ }
+ ],
+ "related-to-property": [
+ {
+ "property-key": "tenant.tenant-name",
+ "property-value": "SuperDude"
+ }
+ ]
+ }
+ ]
+ }
+} \ No newline at end of file
diff --git a/sparkybe-onap-service/src/test/resources/sync/aai/aai-resources/tenant/tenant-1.json b/sparkybe-onap-service/src/test/resources/sync/aai/aai-resources/tenant/tenant-1.json
new file mode 100644
index 0000000..3dad086
--- /dev/null
+++ b/sparkybe-onap-service/src/test/resources/sync/aai/aai-resources/tenant/tenant-1.json
@@ -0,0 +1,23 @@
+{
+ "tenant-id": "tenant-1",
+ "tenant-name": "SuperDude",
+ "resource-version": "1494001855362",
+ "relationship-list": {
+ "relationship": [
+ {
+ "related-to": "service-subscription",
+ "related-link": "/aai/v11/business/customers/customer/customer-2/service-subscriptions/service-subscription/service-subscription-2",
+ "relationship-data": [
+ {
+ "relationship-key": "customer.global-customer-id",
+ "relationship-value": "customer-4"
+ },
+ {
+ "relationship-key": "service-subscription.service-type",
+ "relationship-value": "service-subscription-2"
+ }
+ ]
+ }
+ ]
+ }
+} \ No newline at end of file
diff --git a/sparkybe-onap-service/src/test/resources/sync/aai/aai-traversal/generic-query/service-instance-50.json b/sparkybe-onap-service/src/test/resources/sync/aai/aai-traversal/generic-query/service-instance-50.json
new file mode 100644
index 0000000..d4e9d8d
--- /dev/null
+++ b/sparkybe-onap-service/src/test/resources/sync/aai/aai-traversal/generic-query/service-instance-50.json
@@ -0,0 +1,8 @@
+{
+ "result-data": [
+ {
+ "resource-type": "service-instance",
+ "resource-link": "/aai/v11/business/customers/customer/customer-2/service-subscriptions/service-subscription/service-subscription-2/service-instances/service-instance/service-instance-50"
+ }
+ ]
+} \ No newline at end of file
diff --git a/sparkybe-onap-service/src/test/resources/sync/aai/aai-traversal/generic-query/service-instance-51.json b/sparkybe-onap-service/src/test/resources/sync/aai/aai-traversal/generic-query/service-instance-51.json
new file mode 100644
index 0000000..7c29652
--- /dev/null
+++ b/sparkybe-onap-service/src/test/resources/sync/aai/aai-traversal/generic-query/service-instance-51.json
@@ -0,0 +1,8 @@
+{
+ "result-data": [
+ {
+ "resource-type": "service-instance",
+ "resource-link": "/aai/v11/business/customers/customer/customer-2/service-subscriptions/service-subscription/service-subscription-2/service-instances/service-instance/service-instance-51"
+ }
+ ]
+} \ No newline at end of file
diff --git a/sparkybe-onap-service/src/test/resources/sync/aai/aai-traversal/generic-query/service-instance-52.json b/sparkybe-onap-service/src/test/resources/sync/aai/aai-traversal/generic-query/service-instance-52.json
new file mode 100644
index 0000000..5d88946
--- /dev/null
+++ b/sparkybe-onap-service/src/test/resources/sync/aai/aai-traversal/generic-query/service-instance-52.json
@@ -0,0 +1,8 @@
+{
+ "result-data": [
+ {
+ "resource-type": "service-instance",
+ "resource-link": "/aai/v11/business/customers/customer/customer-2/service-subscriptions/service-subscription/service-subscription-2/service-instances/service-instance/service-instance-52"
+ }
+ ]
+} \ No newline at end of file
diff --git a/sparkybe-onap-service/src/test/resources/sync/aai/aai-traversal/generic-query/service-instance-53.json b/sparkybe-onap-service/src/test/resources/sync/aai/aai-traversal/generic-query/service-instance-53.json
new file mode 100644
index 0000000..8422ab0
--- /dev/null
+++ b/sparkybe-onap-service/src/test/resources/sync/aai/aai-traversal/generic-query/service-instance-53.json
@@ -0,0 +1,8 @@
+{
+ "result-data": [
+ {
+ "resource-type": "service-instance",
+ "resource-link": "/aai/v11/business/customers/customer/customer-2/service-subscriptions/service-subscription/service-subscription-2/service-instances/service-instance/service-instance-53"
+ }
+ ]
+} \ No newline at end of file
diff --git a/sparkybe-onap-service/src/test/resources/sync/aai/aai-traversal/generic-query/service-instance-54.json b/sparkybe-onap-service/src/test/resources/sync/aai/aai-traversal/generic-query/service-instance-54.json
new file mode 100644
index 0000000..d61ee8e
--- /dev/null
+++ b/sparkybe-onap-service/src/test/resources/sync/aai/aai-traversal/generic-query/service-instance-54.json
@@ -0,0 +1,8 @@
+{
+ "result-data": [
+ {
+ "resource-type": "service-instance",
+ "resource-link": "/aai/v11/business/customers/customer/customer-2/service-subscriptions/service-subscription/service-subscription-2/service-instances/service-instance/service-instance-54"
+ }
+ ]
+} \ No newline at end of file
diff --git a/sparkybe-onap-service/src/test/resources/sync/aai/aai-traversal/generic-query/service-instance-55.json b/sparkybe-onap-service/src/test/resources/sync/aai/aai-traversal/generic-query/service-instance-55.json
new file mode 100644
index 0000000..7594913
--- /dev/null
+++ b/sparkybe-onap-service/src/test/resources/sync/aai/aai-traversal/generic-query/service-instance-55.json
@@ -0,0 +1,8 @@
+{
+ "result-data": [
+ {
+ "resource-type": "service-instance",
+ "resource-link": "/aai/v11/business/customers/customer/customer-2/service-subscriptions/service-subscription/service-subscription-2/service-instances/service-instance/service-instance-55"
+ }
+ ]
+} \ No newline at end of file
diff --git a/sparkybe-onap-service/src/test/resources/sync/aai/aai-traversal/generic-query/service-instance-56.json b/sparkybe-onap-service/src/test/resources/sync/aai/aai-traversal/generic-query/service-instance-56.json
new file mode 100644
index 0000000..dc66079
--- /dev/null
+++ b/sparkybe-onap-service/src/test/resources/sync/aai/aai-traversal/generic-query/service-instance-56.json
@@ -0,0 +1,8 @@
+{
+ "result-data": [
+ {
+ "resource-type": "service-instance",
+ "resource-link": "/aai/v11/business/customers/customer/DHV_20170525142406/service-subscriptions/service-subscription/uCPE/service-instances/service-instance/service-instance-56"
+ }
+ ]
+} \ No newline at end of file
diff --git a/sparkybe-onap-service/src/test/resources/sync/aai/aai-traversal/generic-query/service-instance-57.json b/sparkybe-onap-service/src/test/resources/sync/aai/aai-traversal/generic-query/service-instance-57.json
new file mode 100644
index 0000000..427fbdf
--- /dev/null
+++ b/sparkybe-onap-service/src/test/resources/sync/aai/aai-traversal/generic-query/service-instance-57.json
@@ -0,0 +1,8 @@
+{
+ "result-data": [
+ {
+ "resource-type": "service-instance",
+ "resource-link": "/aai/v11/business/customers/customer/customer-2/service-subscriptions/service-subscription/service-subscription-2/service-instances/service-instance/service-instance-57"
+ }
+ ]
+} \ No newline at end of file
diff --git a/sparkybe-onap-service/src/test/resources/sync/aai/aai-traversal/generic-query/service-instance-58.json b/sparkybe-onap-service/src/test/resources/sync/aai/aai-traversal/generic-query/service-instance-58.json
new file mode 100644
index 0000000..f459422
--- /dev/null
+++ b/sparkybe-onap-service/src/test/resources/sync/aai/aai-traversal/generic-query/service-instance-58.json
@@ -0,0 +1,8 @@
+{
+ "result-data": [
+ {
+ "resource-type": "service-instance",
+ "resource-link": "/aai/v11/business/customers/customer/customer-2/service-subscriptions/service-subscription/service-subscription-2/service-instances/service-instance/service-instance-58"
+ }
+ ]
+} \ No newline at end of file
diff --git a/sparkybe-onap-service/src/test/resources/sync/aai/aai-traversal/generic-query/service-instance-59.json b/sparkybe-onap-service/src/test/resources/sync/aai/aai-traversal/generic-query/service-instance-59.json
new file mode 100644
index 0000000..380f932
--- /dev/null
+++ b/sparkybe-onap-service/src/test/resources/sync/aai/aai-traversal/generic-query/service-instance-59.json
@@ -0,0 +1,8 @@
+{
+ "result-data": [
+ {
+ "resource-type": "service-instance",
+ "resource-link": "/aai/v11/business/customers/customer/customer-1/service-subscriptions/service-subscription/service-subscription-1/service-instances/service-instance/service-instance-59"
+ }
+ ]
+} \ No newline at end of file
diff --git a/sparkybe-onap-service/src/test/resources/sync/aai/aai-traversal/generic-query/service-instance/service-instance-54.json b/sparkybe-onap-service/src/test/resources/sync/aai/aai-traversal/generic-query/service-instance/service-instance-54.json
new file mode 100644
index 0000000..d61ee8e
--- /dev/null
+++ b/sparkybe-onap-service/src/test/resources/sync/aai/aai-traversal/generic-query/service-instance/service-instance-54.json
@@ -0,0 +1,8 @@
+{
+ "result-data": [
+ {
+ "resource-type": "service-instance",
+ "resource-link": "/aai/v11/business/customers/customer/customer-2/service-subscriptions/service-subscription/service-subscription-2/service-instances/service-instance/service-instance-54"
+ }
+ ]
+} \ No newline at end of file
diff --git a/sparkybe-onap-service/src/test/resources/sync/aai/aai-traversal/generic-query/service-instance/service-instance-55.json b/sparkybe-onap-service/src/test/resources/sync/aai/aai-traversal/generic-query/service-instance/service-instance-55.json
new file mode 100644
index 0000000..7594913
--- /dev/null
+++ b/sparkybe-onap-service/src/test/resources/sync/aai/aai-traversal/generic-query/service-instance/service-instance-55.json
@@ -0,0 +1,8 @@
+{
+ "result-data": [
+ {
+ "resource-type": "service-instance",
+ "resource-link": "/aai/v11/business/customers/customer/customer-2/service-subscriptions/service-subscription/service-subscription-2/service-instances/service-instance/service-instance-55"
+ }
+ ]
+} \ No newline at end of file
diff --git a/sparkybe-onap-service/src/test/resources/sync/aai/aai-traversal/generic-query/service-subscription/service-subscription-2.json b/sparkybe-onap-service/src/test/resources/sync/aai/aai-traversal/generic-query/service-subscription/service-subscription-2.json
new file mode 100644
index 0000000..d377d5d
--- /dev/null
+++ b/sparkybe-onap-service/src/test/resources/sync/aai/aai-traversal/generic-query/service-subscription/service-subscription-2.json
@@ -0,0 +1,8 @@
+{
+ "result-data": [
+ {
+ "resource-type": "service-subscription",
+ "resource-link": "/aai/v11/business/customers/customer/customer-2/service-subscriptions/service-subscription/service-subscription-2"
+ }
+ ]
+} \ No newline at end of file
diff --git a/sparkybe-onap-service/src/test/resources/sync/aai/activeInventory_complex_nodesQuery_response.json b/sparkybe-onap-service/src/test/resources/sync/aai/activeInventory_complex_nodesQuery_response.json
new file mode 100644
index 0000000..508d711
--- /dev/null
+++ b/sparkybe-onap-service/src/test/resources/sync/aai/activeInventory_complex_nodesQuery_response.json
@@ -0,0 +1,24 @@
+{
+ "result-data" : [
+ {
+ "resource-type" : "complex",
+ "resource-link" : "https://a.server.some.where:8443/aai/v7/complexes/complex/complex1"
+ },
+ {
+ "resource-type" : "complex",
+ "resource-link" : "https://a.server.some.where:8443/aai/v7/complexes/complex/complex2"
+ },
+ {
+ "resource-type" : "complex",
+ "resource-link" : "https://a.server.some.where:8443/aai/v7/complexes/complex/complex3"
+ },
+ {
+ "resource-type" : "complex",
+ "resource-link" : "https://a.server.some.where:8443/aai/v7/complexes/complex/complex4"
+ },
+ {
+ "resource-type" : "complex",
+ "resource-link" : "https://a.server.some.where:8443/aai/v7/complexes/complex/complex5"
+ }
+ ]
+} \ No newline at end of file
diff --git a/sparkybe-onap-service/src/test/resources/sync/aai/activeInventory_generic-vnf_nodesQuery_response.json b/sparkybe-onap-service/src/test/resources/sync/aai/activeInventory_generic-vnf_nodesQuery_response.json
new file mode 100644
index 0000000..f1cb3d4
--- /dev/null
+++ b/sparkybe-onap-service/src/test/resources/sync/aai/activeInventory_generic-vnf_nodesQuery_response.json
@@ -0,0 +1,16 @@
+{
+ "result-data": [
+ {
+ "resource-type": "generic-vnf",
+ "resource-link": "/aai/v11/network/generic-vnfs/generic-vnf/generic-vnf-1"
+ },
+ {
+ "resource-type": "generic-vnf",
+ "resource-link": "/aai/v11/network/generic-vnfs/generic-vnf/generic-vnf-2"
+ },
+ {
+ "resource-type": "generic-vnf",
+ "resource-link": "/aai/v11/network/generic-vnfs/generic-vnf/generic-vnf-3"
+ }
+ ]
+} \ No newline at end of file
diff --git a/sparkybe-onap-service/src/test/resources/sync/aai/activeInventory_service-subscription_nodesQuery_response.json b/sparkybe-onap-service/src/test/resources/sync/aai/activeInventory_service-subscription_nodesQuery_response.json
new file mode 100644
index 0000000..414724f
--- /dev/null
+++ b/sparkybe-onap-service/src/test/resources/sync/aai/activeInventory_service-subscription_nodesQuery_response.json
@@ -0,0 +1,16 @@
+{
+ "result-data": [
+ {
+ "resource-type": "service-subscription",
+ "resource-link": "/aai/v11/business/customers/customer/customer-1/service-subscriptions/service-subscription/service-subscription1"
+ },
+ {
+ "resource-type": "service-subscription",
+ "resource-link": "/aai/v11/business/customers/customer/customer-2/service-subscriptions/service-subscription/service-subscription-2"
+ },
+ {
+ "resource-type": "service-subscription",
+ "resource-link": "/aai/v11/business/customers/customer/customer-3/service-subscriptions/service-subscription/service-subscription-3"
+ }
+ ]
+} \ No newline at end of file
diff --git a/sparkybe-onap-service/src/test/resources/sync/aai/complex1_fullDepth_aaiEntityRetrieval.json b/sparkybe-onap-service/src/test/resources/sync/aai/complex1_fullDepth_aaiEntityRetrieval.json
new file mode 100644
index 0000000..3831848
--- /dev/null
+++ b/sparkybe-onap-service/src/test/resources/sync/aai/complex1_fullDepth_aaiEntityRetrieval.json
@@ -0,0 +1,30 @@
+{
+ "physical-location-id": "HMBGGEANN02-1",
+ "resource-version": "1494001844620",
+ "physical-location-type": "EQUIPMENT LOCATION-1",
+ "street1": "WENDENSTRASSE 379-1",
+ "city": "HAMBURG-1",
+ "state": "GE",
+ "postal-code": "20097-1",
+ "country": "USA",
+ "region": "US",
+ "relationship-list": {
+ "relationship": [
+ {
+ "related-to": "pserver",
+ "related-link": "/aai/v11/cloud-infrastructure/pservers/pserver/GER-45-IIGA-TRANSPORT_ONLY_DEL-1",
+ "relationship-data": [
+ {
+ "relationship-key": "pserver.hostname",
+ "relationship-value": "GER-45-IIGA-TRANSPORT_ONLY_DEL-1"
+ }
+ ],
+ "related-to-property": [
+ {
+ "property-key": "pserver.pserver-name2-1"
+ }
+ ]
+ }
+ ]
+ }
+} \ No newline at end of file
diff --git a/sparkybe-onap-service/src/test/resources/sync/aai/complex2_fullDepth_aaiEntityRetrieval.json b/sparkybe-onap-service/src/test/resources/sync/aai/complex2_fullDepth_aaiEntityRetrieval.json
new file mode 100644
index 0000000..7a4d680
--- /dev/null
+++ b/sparkybe-onap-service/src/test/resources/sync/aai/complex2_fullDepth_aaiEntityRetrieval.json
@@ -0,0 +1,30 @@
+{
+ "physical-location-id": "HMBGGEANN02-2",
+ "resource-version": "1494001844620",
+ "physical-location-type": "EQUIPMENT LOCATION-2",
+ "street1": "WENDENSTRASSE 379-2",
+ "city": "HAMBURG-2",
+ "state": "GE",
+ "postal-code": "20097-2",
+ "country": "USA",
+ "region": "US",
+ "relationship-list": {
+ "relationship": [
+ {
+ "related-to": "pserver",
+ "related-link": "/aai/v11/cloud-infrastructure/pservers/pserver/GER-45-IIGA-TRANSPORT_ONLY_DEL-2",
+ "relationship-data": [
+ {
+ "relationship-key": "pserver.hostname",
+ "relationship-value": "GER-45-IIGA-TRANSPORT_ONLY_DEL-2"
+ }
+ ],
+ "related-to-property": [
+ {
+ "property-key": "pserver.pserver-name2-2"
+ }
+ ]
+ }
+ ]
+ }
+} \ No newline at end of file
diff --git a/sparkybe-onap-service/src/test/resources/sync/aai/complex3_fullDepth_aaiEntityRetrieval.json b/sparkybe-onap-service/src/test/resources/sync/aai/complex3_fullDepth_aaiEntityRetrieval.json
new file mode 100644
index 0000000..e4a3789
--- /dev/null
+++ b/sparkybe-onap-service/src/test/resources/sync/aai/complex3_fullDepth_aaiEntityRetrieval.json
@@ -0,0 +1,30 @@
+{
+ "physical-location-id": "HMBGGEANN02-3",
+ "resource-version": "1494001844620",
+ "physical-location-type": "EQUIPMENT LOCATION-3",
+ "street1": "WENDENSTRASSE 379-3",
+ "city": "HAMBURG-3",
+ "state": "GE",
+ "postal-code": "20097-3",
+ "country": "USA",
+ "region": "US",
+ "relationship-list": {
+ "relationship": [
+ {
+ "related-to": "pserver",
+ "related-link": "/aai/v11/cloud-infrastructure/pservers/pserver/GER-45-IIGA-TRANSPORT_ONLY_DEL-3",
+ "relationship-data": [
+ {
+ "relationship-key": "pserver.hostname",
+ "relationship-value": "GER-45-IIGA-TRANSPORT_ONLY_DEL-3"
+ }
+ ],
+ "related-to-property": [
+ {
+ "property-key": "pserver.pserver-name2-3"
+ }
+ ]
+ }
+ ]
+ }
+} \ No newline at end of file
diff --git a/sparkybe-onap-service/src/test/resources/sync/aai/complex4_fullDepth_aaiEntityRetrieval.json b/sparkybe-onap-service/src/test/resources/sync/aai/complex4_fullDepth_aaiEntityRetrieval.json
new file mode 100644
index 0000000..1963b3b
--- /dev/null
+++ b/sparkybe-onap-service/src/test/resources/sync/aai/complex4_fullDepth_aaiEntityRetrieval.json
@@ -0,0 +1,30 @@
+{
+ "physical-location-id": "HMBGGEANN02-4",
+ "resource-version": "1494001844620",
+ "physical-location-type": "EQUIPMENT LOCATION-4",
+ "street1": "WENDENSTRASSE 379-4",
+ "city": "HAMBURG-4",
+ "state": "GE",
+ "postal-code": "20097-4",
+ "country": "USA",
+ "region": "US",
+ "relationship-list": {
+ "relationship": [
+ {
+ "related-to": "pserver",
+ "related-link": "/aai/v11/cloud-infrastructure/pservers/pserver/GER-45-IIGA-TRANSPORT_ONLY_DEL-4",
+ "relationship-data": [
+ {
+ "relationship-key": "pserver.hostname",
+ "relationship-value": "GER-45-IIGA-TRANSPORT_ONLY_DEL-4"
+ }
+ ],
+ "related-to-property": [
+ {
+ "property-key": "pserver.pserver-name2-4"
+ }
+ ]
+ }
+ ]
+ }
+} \ No newline at end of file
diff --git a/sparkybe-onap-service/src/test/resources/sync/aai/complex5_fullDepth_aaiEntityRetrieval.json b/sparkybe-onap-service/src/test/resources/sync/aai/complex5_fullDepth_aaiEntityRetrieval.json
new file mode 100644
index 0000000..70fcba8
--- /dev/null
+++ b/sparkybe-onap-service/src/test/resources/sync/aai/complex5_fullDepth_aaiEntityRetrieval.json
@@ -0,0 +1,30 @@
+{
+ "physical-location-id": "HMBGGEANN02-5",
+ "resource-version": "1494001844620",
+ "physical-location-type": "EQUIPMENT LOCATION-5",
+ "street1": "WENDENSTRASSE 379-5",
+ "city": "HAMBURG-5",
+ "state": "GE",
+ "postal-code": "20097-5",
+ "country": "USA",
+ "region": "US",
+ "relationship-list": {
+ "relationship": [
+ {
+ "related-to": "pserver",
+ "related-link": "/aai/v11/cloud-infrastructure/pservers/pserver/GER-45-IIGA-TRANSPORT_ONLY_DEL-5",
+ "relationship-data": [
+ {
+ "relationship-key": "pserver.hostname",
+ "relationship-value": "GER-45-IIGA-TRANSPORT_ONLY_DEL-5"
+ }
+ ],
+ "related-to-property": [
+ {
+ "property-key": "pserver.pserver-name2-5"
+ }
+ ]
+ }
+ ]
+ }
+} \ No newline at end of file
diff --git a/sparkybe-onap-service/src/test/resources/sync/aai/generic-vnf-generic-vnf-1_full_depth.json b/sparkybe-onap-service/src/test/resources/sync/aai/generic-vnf-generic-vnf-1_full_depth.json
new file mode 100644
index 0000000..14abe18
--- /dev/null
+++ b/sparkybe-onap-service/src/test/resources/sync/aai/generic-vnf-generic-vnf-1_full_depth.json
@@ -0,0 +1,136 @@
+{
+ "vnf-id": "generic-vnf-1",
+ "vnf-name": "vProbe_Fe_VEPMS_sk316t_sd_01",
+ "vnf-type": "vProbe Fe VEPMS_sk316t/vProbe Fe VEPMS_sk316t 0",
+ "service-id": "a9a77d5a-123e-4ca2-9eb9-0b015d2ee0fb",
+ "prov-status": "PREPROV",
+ "orchestration-status": "Created",
+ "in-maint": false,
+ "is-closed-loop-disabled": false,
+ "resource-version": "1511102454640",
+ "model-invariant-id": "b8dba4bd-04ee-42bc-8c41-db06addb6866",
+ "model-version-id": "c9e7826d-c4b8-40c7-83e4-d9f96e7d5827",
+ "model-customization-id": "d2ca6d16-6529-4362-b53e-7bf4141372b1",
+ "nf-type": "PROBES",
+ "nf-function": "vProbes (Frontend )",
+ "nf-role": "vLB",
+ "nf-naming-code": "null",
+ "relationship-list": {
+ "relationship": [
+ {
+ "related-to": "service-instance",
+ "related-link": "/aai/v11/business/customers/customer/a9a77d5a-123e-4ca2-9eb9-0b015d2ee0fb/service-subscriptions/service-subscription/Mobility/service-instances/service-instance/22663785-ebb9-49c7-b95b-209537e6627f",
+ "relationship-data": [
+ {
+ "relationship-key": "customer.global-customer-id",
+ "relationship-value": "a9a77d5a-123e-4ca2-9eb9-0b015d2ee0fb"
+ },
+ {
+ "relationship-key": "service-subscription.service-type",
+ "relationship-value": "Mobility"
+ },
+ {
+ "relationship-key": "service-instance.service-instance-id",
+ "relationship-value": "22663785-ebb9-49c7-b95b-209537e6627f"
+ }
+ ],
+ "related-to-property": [
+ {
+ "property-key": "service-instance.service-instance-name",
+ "property-value": "vProbe_Fe_VEPMS_sk316t_sd"
+ }
+ ]
+ },
+ {
+ "related-to": "line-of-business",
+ "related-link": "/aai/v11/business/lines-of-business/line-of-business/lob1",
+ "relationship-data": [
+ {
+ "relationship-key": "line-of-business.line-of-business-name",
+ "relationship-value": "lob1"
+ }
+ ]
+ },
+ {
+ "related-to": "platform",
+ "related-link": "/aai/v11/business/platforms/platform/platform1",
+ "relationship-data": [
+ {
+ "relationship-key": "platform.platform-name",
+ "relationship-value": "platform1"
+ }
+ ]
+ },
+ {
+ "related-to": "volume-group",
+ "related-link": "/aai/v11/cloud-infrastructure/cloud-regions/cloud-region/att-aic/mtn6/volume-groups/volume-group/ecf748d5-be43-45ae-a8b1-c8520d144bdf",
+ "relationship-data": [
+ {
+ "relationship-key": "cloud-region.cloud-owner",
+ "relationship-value": "att-aic"
+ },
+ {
+ "relationship-key": "cloud-region.cloud-region-id",
+ "relationship-value": "mtn6"
+ },
+ {
+ "relationship-key": "volume-group.volume-group-id",
+ "relationship-value": "ecf748d5-be43-45ae-a8b1-c8520d144bdf"
+ }
+ ]
+ },
+ {
+ "related-to": "volume-group",
+ "related-link": "/aai/v11/cloud-infrastructure/cloud-regions/cloud-region/att-aic/mtn6/volume-groups/volume-group/1e26c1a7-8a91-4459-ba02-8cc2d70dd065",
+ "relationship-data": [
+ {
+ "relationship-key": "cloud-region.cloud-owner",
+ "relationship-value": "att-aic"
+ },
+ {
+ "relationship-key": "cloud-region.cloud-region-id",
+ "relationship-value": "mtn6"
+ },
+ {
+ "relationship-key": "volume-group.volume-group-id",
+ "relationship-value": "1e26c1a7-8a91-4459-ba02-8cc2d70dd065"
+ }
+ ]
+ },
+ {
+ "related-to": "volume-group",
+ "related-link": "/aai/v11/cloud-infrastructure/cloud-regions/cloud-region/att-aic/mtn6/volume-groups/volume-group/5223cfdc-50bf-4607-9651-2270384d6414",
+ "relationship-data": [
+ {
+ "relationship-key": "cloud-region.cloud-owner",
+ "relationship-value": "att-aic"
+ },
+ {
+ "relationship-key": "cloud-region.cloud-region-id",
+ "relationship-value": "mtn6"
+ },
+ {
+ "relationship-key": "volume-group.volume-group-id",
+ "relationship-value": "5223cfdc-50bf-4607-9651-2270384d6414"
+ }
+ ]
+ }
+ ]
+ },
+ "vf-modules": {
+ "vf-module": [
+ {
+ "vf-module-id": "eba81b96-851e-4374-9b9e-d186527f3c46",
+ "vf-module-name": "zmtn6afprb01_base1_sd_02",
+ "heat-stack-id": "zmtn6afprb01_base1_sd_02/cfd1203d-ff2f-49a3-a40b-72ac67cd8432",
+ "orchestration-status": "active",
+ "is-base-vf-module": true,
+ "resource-version": "1511301104226",
+ "model-invariant-id": "c01b5b9f-0760-4bcc-93b5-e1b24dd9bcfa",
+ "model-version-id": "30e71b66-93c6-4e0f-b7ff-de26b45c83e9",
+ "model-customization-id": "caaf8b40-03e9-4c58-9d18-613f564e2ea8",
+ "module-index": 0
+ }
+ ]
+ }
+}
diff --git a/sparkybe-onap-service/src/test/resources/sync/aai/generic-vnf-generic-vnf-2_full_depth.json b/sparkybe-onap-service/src/test/resources/sync/aai/generic-vnf-generic-vnf-2_full_depth.json
new file mode 100644
index 0000000..a03e4c8
--- /dev/null
+++ b/sparkybe-onap-service/src/test/resources/sync/aai/generic-vnf-generic-vnf-2_full_depth.json
@@ -0,0 +1,118 @@
+{
+ "vnf-id": "generic-vnf-2",
+ "vnf-name": "zmtn6apndns_v6_01",
+ "vnf-type": "APNDNS_mm779p_II/APNDNS_mm779p_II 0",
+ "service-id": "a9a77d5a-123e-4ca2-9eb9-0b015d2ee0fb",
+ "prov-status": "PREPROV",
+ "orchestration-status": "Created",
+ "in-maint": false,
+ "is-closed-loop-disabled": false,
+ "resource-version": "1511184323962",
+ "model-invariant-id": "f3f6ed00-cd41-4e96-b669-0daa10da5491",
+ "model-version-id": "f76e6281-d80f-4403-9603-4245b0c8d8cd",
+ "model-customization-id": "f499ebb9-4383-42c1-8ace-2b682f312504",
+ "nf-type": "DNS",
+ "nf-function": "APN-DNS",
+ "nf-role": "VDNS",
+ "nf-naming-code": "null",
+ "relationship-list": {
+ "relationship": [
+ {
+ "related-to": "service-instance",
+ "related-link": "/aai/v11/business/customers/customer/a9a77d5a-123e-4ca2-9eb9-0b015d2ee0fb/service-subscriptions/service-subscription/Nimbus/service-instances/service-instance/3a743f07-86cc-47db-bee5-03fa91c77748",
+ "relationship-data": [
+ {
+ "relationship-key": "customer.global-customer-id",
+ "relationship-value": "a9a77d5a-123e-4ca2-9eb9-0b015d2ee0fb"
+ },
+ {
+ "relationship-key": "service-subscription.service-type",
+ "relationship-value": "Nimbus"
+ },
+ {
+ "relationship-key": "service-instance.service-instance-id",
+ "relationship-value": "3a743f07-86cc-47db-bee5-03fa91c77748"
+ }
+ ],
+ "related-to-property": [
+ {
+ "property-key": "service-instance.service-instance-name",
+ "property-value": "APNDNS_mm779p_II_V6"
+ }
+ ]
+ },
+ {
+ "related-to": "line-of-business",
+ "related-link": "/aai/v11/business/lines-of-business/line-of-business/lob1",
+ "relationship-data": [
+ {
+ "relationship-key": "line-of-business.line-of-business-name",
+ "relationship-value": "lob1"
+ }
+ ]
+ },
+ {
+ "related-to": "platform",
+ "related-link": "/aai/v11/business/platforms/platform/platform1",
+ "relationship-data": [
+ {
+ "relationship-key": "platform.platform-name",
+ "relationship-value": "platform1"
+ }
+ ]
+ },
+ {
+ "related-to": "volume-group",
+ "related-link": "/aai/v11/cloud-infrastructure/cloud-regions/cloud-region/att-aic/mtn6/volume-groups/volume-group/03ec51a4-2ea9-4947-b66a-b01c7b9e9ea5",
+ "relationship-data": [
+ {
+ "relationship-key": "cloud-region.cloud-owner",
+ "relationship-value": "att-aic"
+ },
+ {
+ "relationship-key": "cloud-region.cloud-region-id",
+ "relationship-value": "mtn6"
+ },
+ {
+ "relationship-key": "volume-group.volume-group-id",
+ "relationship-value": "03ec51a4-2ea9-4947-b66a-b01c7b9e9ea5"
+ }
+ ]
+ },
+ {
+ "related-to": "volume-group",
+ "related-link": "/aai/v11/cloud-infrastructure/cloud-regions/cloud-region/att-aic/mtn6/volume-groups/volume-group/1b3bf4c2-a4cc-4c37-afcc-ec49f5c1c653",
+ "relationship-data": [
+ {
+ "relationship-key": "cloud-region.cloud-owner",
+ "relationship-value": "att-aic"
+ },
+ {
+ "relationship-key": "cloud-region.cloud-region-id",
+ "relationship-value": "mtn6"
+ },
+ {
+ "relationship-key": "volume-group.volume-group-id",
+ "relationship-value": "1b3bf4c2-a4cc-4c37-afcc-ec49f5c1c653"
+ }
+ ]
+ }
+ ]
+ },
+ "vf-modules": {
+ "vf-module": [
+ {
+ "vf-module-id": "1b5602c0-b0c7-42fd-9bbd-8d503e464c5a",
+ "vf-module-name": "APNDNS_V6_base",
+ "heat-stack-id": "APNDNS_V6_base/bd3aa649-179f-4017-a848-f9a90cfa8908",
+ "orchestration-status": "active",
+ "is-base-vf-module": true,
+ "resource-version": "1511271087769",
+ "model-invariant-id": "874a259a-c4a3-4928-bbaa-0cd391ea3ec8",
+ "model-version-id": "417a7a36-87f8-4366-8d7b-95e47f1009b9",
+ "model-customization-id": "76a64957-74c7-4598-84c9-aa0e94bd2a69",
+ "module-index": 0
+ }
+ ]
+ }
+} \ No newline at end of file
diff --git a/sparkybe-onap-service/src/test/resources/sync/aai/generic-vnf-generic-vnf-3_full_depth.json b/sparkybe-onap-service/src/test/resources/sync/aai/generic-vnf-generic-vnf-3_full_depth.json
new file mode 100644
index 0000000..de2481b
--- /dev/null
+++ b/sparkybe-onap-service/src/test/resources/sync/aai/generic-vnf-generic-vnf-3_full_depth.json
@@ -0,0 +1,30 @@
+{
+ "vnf-id": "generic-vnf-3",
+ "vnf-name": "generic-vnf-test01-name19",
+ "vnf-name2": "generic-vnf-test01-name19",
+ "vnf-type": "generic-vnf-rx2202-type",
+ "service-id": "d0217510-514b-429d-9b84-e4ed74e4c552",
+ "regional-resource-zone": "example-regional-resource-zone-val-8204",
+ "prov-status": "ACTIVE",
+ "license-key": "lk",
+ "equipment-role": "role",
+ "orchestration-status": "PendingDelete",
+ "heat-stack-id": "generic-vnf-rx2202-heat-stack-id",
+ "mso-catalog-key": "generic-vnf-rx2202-mso-catalog-key",
+ "management-option": "generic-vnf-rx2202-management-option",
+ "ipv4-oam-address": "1.2.3.4",
+ "ipv4-loopback0-address": "4.5.6.7",
+ "nm-lan-v6-address": "33::34",
+ "management-v6-address": "34::35",
+ "vcpu": 7957,
+ "vcpu-units": "example-vcpu-units-val-8204",
+ "vmemory": 168,
+ "vmemory-units": "example-vmemory-units-val-8204",
+ "vdisk": 3227,
+ "vdisk-units": "example-vdisk-units-val-8204",
+ "in-maint": false,
+ "is-closed-loop-disabled": true,
+ "resource-version": "1500476417001",
+ "nf-type": "vCE/vFW",
+ "nf-role": "vSeGW"
+} \ No newline at end of file
diff --git a/sparkybe-onap-service/src/test/resources/sync/aai/service-subscription-service-subscription-1.json b/sparkybe-onap-service/src/test/resources/sync/aai/service-subscription-service-subscription-1.json
new file mode 100644
index 0000000..3d2d38c
--- /dev/null
+++ b/sparkybe-onap-service/src/test/resources/sync/aai/service-subscription-service-subscription-1.json
@@ -0,0 +1,12 @@
+{
+ "service-type": "service-subscription-1",
+ "resource-version": "1506087955078",
+ "service-instances": {
+ "service-instance": [
+ {
+ "service-instance-id": "service-subscription-1",
+ "resource-version": "1506087955081"
+ }
+ ]
+ }
+} \ No newline at end of file
diff --git a/sparkybe-onap-service/src/test/resources/sync/aai/service-subscription-service-subscription-2.json b/sparkybe-onap-service/src/test/resources/sync/aai/service-subscription-service-subscription-2.json
new file mode 100644
index 0000000..d4c2414
--- /dev/null
+++ b/sparkybe-onap-service/src/test/resources/sync/aai/service-subscription-service-subscription-2.json
@@ -0,0 +1,350 @@
+{
+ "service-type": "service-subscription-2",
+ "resource-version": "1494001891362",
+ "service-instances": {
+ "service-instance": [
+ {
+ "service-instance-id": "service-instance-54",
+ "service-instance-name": "si_failtest",
+ "model-invariant-id": "732263bd-0655-428d-a347-d65676d1a949",
+ "resource-version": "1494001997513"
+ },
+ {
+ "service-instance-id": "service-instance-55",
+ "service-instance-name": "test-343432",
+ "model-invariant-id": "709d1be4-9a3f-4a29-8c4d-a20465e808a3",
+ "model-version-id": "240376de-870e-48df-915a-31f140eedd2c",
+ "resource-version": "1500370094198",
+ "orchestration-status": "Active"
+ },
+ {
+ "service-instance-id": "service-instance-50",
+ "service-instance-name": "s01",
+ "service-type": "",
+ "service-role": "",
+ "environment-context": "General_Revenue-Bearing",
+ "workload-context": "Production",
+ "model-invariant-id": "5b9c0f33-eec1-484a-bf77-736a6644d7a8",
+ "model-version-id": "b75e0d22-05ff-4448-9266-5f0d4e1dbbd6",
+ "resource-version": "1510659038818",
+ "orchestration-status": "Active",
+ "relationship-list": {
+ "relationship": [
+ {
+ "related-to": "project",
+ "related-link": "/aai/v11/business/projects/project/project1",
+ "relationship-data": [
+ {
+ "relationship-key": "project.project-name",
+ "relationship-value": "project1"
+ }
+ ]
+ },
+ {
+ "related-to": "owning-entity",
+ "related-link": "/aai/v11/business/owning-entities/owning-entity/589fe0db-26c4-45e5-9f4e-a246c74fce76",
+ "relationship-data": [
+ {
+ "relationship-key": "owning-entity.owning-entity-id",
+ "relationship-value": "589fe0db-26c4-45e5-9f4e-a246c74fce76"
+ }
+ ]
+ }
+ ]
+ }
+ },
+ {
+ "service-instance-id": "service-instance-52",
+ "service-instance-name": "shanitest",
+ "service-type": "",
+ "service-role": "",
+ "environment-context": "null",
+ "workload-context": "null",
+ "model-invariant-id": "d7b48529-6ae2-49f0-8633-b29e7cd4d4ce",
+ "model-version-id": "44671b15-83dd-4db7-a36e-dfada3eaa2f9",
+ "resource-version": "1508144995828",
+ "orchestration-status": "Active"
+ },
+ {
+ "service-instance-id": "service-instance-57",
+ "service-instance-name": "first_macro_shani",
+ "service-type": "",
+ "service-role": "",
+ "environment-context": "General_Revenue-Bearing",
+ "workload-context": "Production",
+ "model-invariant-id": "5b9c0f33-eec1-484a-bf77-736a6644d7a8",
+ "model-version-id": "b75e0d22-05ff-4448-9266-5f0d4e1dbbd6",
+ "resource-version": "1508071197869",
+ "orchestration-status": "Active"
+ },
+ {
+ "service-instance-id": "service-instance-53",
+ "service-instance-name": "a1",
+ "service-type": "service_type_shani",
+ "service-role": "service_role_shani",
+ "environment-context": "General_Revenue-Bearing",
+ "workload-context": "Production",
+ "model-invariant-id": "340f3957-ff0a-4503-866d-a34fd1b97450",
+ "model-version-id": "ee2d8783-8495-4fb1-9553-6cdbd2dd3a50",
+ "resource-version": "1509355912484",
+ "orchestration-status": "Active",
+ "relationship-list": {
+ "relationship": [
+ {
+ "related-to": "owning-entity",
+ "related-link": "/aai/v11/business/owning-entities/owning-entity/2356a43d-ed56-43b6-aefc-8391b82588c9",
+ "relationship-data": [
+ {
+ "relationship-key": "owning-entity.owning-entity-id",
+ "relationship-value": "2356a43d-ed56-43b6-aefc-8391b82588c9"
+ }
+ ]
+ }
+ ]
+ }
+ },
+ {
+ "service-instance-id": "service-instance-58",
+ "service-instance-name": "a3",
+ "service-type": "",
+ "service-role": "",
+ "environment-context": "General_Revenue-Bearing",
+ "workload-context": "Production",
+ "model-invariant-id": "d5937aa1-37fb-4ed0-8c30-5144b89a64ae",
+ "model-version-id": "06ac9663-54cf-4c77-b926-6e8757cf6380",
+ "resource-version": "1509356358573",
+ "orchestration-status": "Active",
+ "relationship-list": {
+ "relationship": [
+ {
+ "related-to": "generic-vnf",
+ "related-link": "/aai/v11/network/generic-vnfs/generic-vnf/9c925d7e-1a94-4784-a45b-408c8cc96fa8",
+ "relationship-data": [
+ {
+ "relationship-key": "generic-vnf.vnf-id",
+ "relationship-value": "9c925d7e-1a94-4784-a45b-408c8cc96fa8"
+ }
+ ],
+ "related-to-property": [
+ {
+ "property-key": "generic-vnf.vnf-name",
+ "property-value": "dfdsfds"
+ }
+ ]
+ },
+ {
+ "related-to": "owning-entity",
+ "related-link": "/aai/v11/business/owning-entities/owning-entity/589fe0db-26c4-45e5-9f4e-a246c74fce76",
+ "relationship-data": [
+ {
+ "relationship-key": "owning-entity.owning-entity-id",
+ "relationship-value": "589fe0db-26c4-45e5-9f4e-a246c74fce76"
+ }
+ ]
+ }
+ ]
+ }
+ },
+ {
+ "service-instance-id": "service-instance-51",
+ "service-instance-name": "test765445g",
+ "model-invariant-id": "709d1be4-9a3f-4a29-8c4d-a20465e808a3",
+ "model-version-id": "240376de-870e-48df-915a-31f140eedd2c",
+ "resource-version": "1499868690949",
+ "orchestration-status": "Active",
+ "relationship-list": {
+ "relationship": [
+ {
+ "related-to": "generic-vnf",
+ "related-link": "/aai/v11/network/generic-vnfs/generic-vnf/fbb52a16-2c57-4212-802f-32dbba2204f2",
+ "relationship-data": [
+ {
+ "relationship-key": "generic-vnf.vnf-id",
+ "relationship-value": "fbb52a16-2c57-4212-802f-32dbba2204f2"
+ }
+ ],
+ "related-to-property": [
+ {
+ "property-key": "generic-vnf.vnf-name",
+ "property-value": "fdfdfdf"
+ }
+ ]
+ }
+ ]
+ }
+ }
+ ]
+ },
+ "relationship-list": {
+ "relationship": [
+ {
+ "related-to": "tenant",
+ "related-link": "/aai/v11/cloud-infrastructure/cloud-regions/cloud-region/att-aic/mtn6/tenants/tenant/tenant-1",
+ "relationship-data": [
+ {
+ "relationship-key": "cloud-region.cloud-owner",
+ "relationship-value": "att-aic"
+ },
+ {
+ "relationship-key": "cloud-region.cloud-region-id",
+ "relationship-value": "mtn6"
+ },
+ {
+ "relationship-key": "tenant.tenant-id",
+ "relationship-value": "tenant-1"
+ }
+ ],
+ "related-to-property": [
+ {
+ "property-key": "tenant.tenant-name",
+ "property-value": "AIN Web Tool-15-D-sspstMAIL"
+ }
+ ]
+ },
+ {
+ "related-to": "tenant",
+ "related-link": "/aai/v11/cloud-infrastructure/cloud-regions/cloud-region/att-aic/mtn6/tenants/tenant/23cbbd1872864ea08aa53ade25d34172",
+ "relationship-data": [
+ {
+ "relationship-key": "cloud-region.cloud-owner",
+ "relationship-value": "att-aic"
+ },
+ {
+ "relationship-key": "cloud-region.cloud-region-id",
+ "relationship-value": "mtn6"
+ },
+ {
+ "relationship-key": "tenant.tenant-id",
+ "relationship-value": "23cbbd1872864ea08aa53ade25d34172"
+ }
+ ],
+ "related-to-property": [
+ {
+ "property-key": "tenant.tenant-name",
+ "property-value": "AIN Web Tool-15-D-rtertet"
+ }
+ ]
+ },
+ {
+ "related-to": "tenant",
+ "related-link": "/aai/v11/cloud-infrastructure/cloud-regions/cloud-region/att-aic/mtn6/tenants/tenant/ded2432abb5a4100801331d07787afc2",
+ "relationship-data": [
+ {
+ "relationship-key": "cloud-region.cloud-owner",
+ "relationship-value": "att-aic"
+ },
+ {
+ "relationship-key": "cloud-region.cloud-region-id",
+ "relationship-value": "mtn6"
+ },
+ {
+ "relationship-key": "tenant.tenant-id",
+ "relationship-value": "ded2432abb5a4100801331d07787afc2"
+ }
+ ],
+ "related-to-property": [
+ {
+ "property-key": "tenant.tenant-name",
+ "property-value": "AIN/SMS-16-D-SSPecompFlvr2"
+ }
+ ]
+ },
+ {
+ "related-to": "tenant",
+ "related-link": "/aai/v11/cloud-infrastructure/cloud-regions/cloud-region/att-aic/mtn6/tenants/tenant/ad5aab08f5f7435e9983311af543f311",
+ "relationship-data": [
+ {
+ "relationship-key": "cloud-region.cloud-owner",
+ "relationship-value": "att-aic"
+ },
+ {
+ "relationship-key": "cloud-region.cloud-region-id",
+ "relationship-value": "mtn6"
+ },
+ {
+ "relationship-key": "tenant.tenant-id",
+ "relationship-value": "ad5aab08f5f7435e9983311af543f311"
+ }
+ ],
+ "related-to-property": [
+ {
+ "property-key": "tenant.tenant-name",
+ "property-value": "AINWebTool-15-X-PODECOMP"
+ }
+ ]
+ },
+ {
+ "related-to": "tenant",
+ "related-link": "/aai/v11/cloud-infrastructure/cloud-regions/cloud-region/att-aic/mtn6/tenants/tenant/8071dc66981c4294b05483a1cddac801",
+ "relationship-data": [
+ {
+ "relationship-key": "cloud-region.cloud-owner",
+ "relationship-value": "att-aic"
+ },
+ {
+ "relationship-key": "cloud-region.cloud-region-id",
+ "relationship-value": "mtn6"
+ },
+ {
+ "relationship-key": "tenant.tenant-id",
+ "relationship-value": "8071dc66981c4294b05483a1cddac801"
+ }
+ ],
+ "related-to-property": [
+ {
+ "property-key": "tenant.tenant-name",
+ "property-value": "CESAR-100-X-ecompPODprivate"
+ }
+ ]
+ },
+ {
+ "related-to": "tenant",
+ "related-link": "/aai/v11/cloud-infrastructure/cloud-regions/cloud-region/att-aic/mtn6/tenants/tenant/036f769581904ca08ead1415c22b9ec0",
+ "relationship-data": [
+ {
+ "relationship-key": "cloud-region.cloud-owner",
+ "relationship-value": "att-aic"
+ },
+ {
+ "relationship-key": "cloud-region.cloud-region-id",
+ "relationship-value": "mtn6"
+ },
+ {
+ "relationship-key": "tenant.tenant-id",
+ "relationship-value": "036f769581904ca08ead1415c22b9ec0"
+ }
+ ],
+ "related-to-property": [
+ {
+ "property-key": "tenant.tenant-name",
+ "property-value": "AINWebTool-15-X-PODECOMPCLONE"
+ }
+ ]
+ },
+ {
+ "related-to": "tenant",
+ "related-link": "/aai/v11/cloud-infrastructure/cloud-regions/cloud-region/att-aic/mtn6/tenants/tenant/c2475a36c5e04f12a21593849ae83420",
+ "relationship-data": [
+ {
+ "relationship-key": "cloud-region.cloud-owner",
+ "relationship-value": "att-aic"
+ },
+ {
+ "relationship-key": "cloud-region.cloud-region-id",
+ "relationship-value": "mtn6"
+ },
+ {
+ "relationship-key": "tenant.tenant-id",
+ "relationship-value": "c2475a36c5e04f12a21593849ae83420"
+ }
+ ],
+ "related-to-property": [
+ {
+ "property-key": "tenant.tenant-name",
+ "property-value": "AIN/SMS-16-X-hope"
+ }
+ ]
+ }
+ ]
+ }
+} \ No newline at end of file
diff --git a/sparkybe-onap-service/src/test/resources/sync/aai/service-subscription-service-subscription-3.json b/sparkybe-onap-service/src/test/resources/sync/aai/service-subscription-service-subscription-3.json
new file mode 100644
index 0000000..39b46ad
--- /dev/null
+++ b/sparkybe-onap-service/src/test/resources/sync/aai/service-subscription-service-subscription-3.json
@@ -0,0 +1,12 @@
+{
+ "service-type": "service-subscription-3",
+ "resource-version": "1495736709052",
+ "service-instances": {
+ "service-instance": [
+ {
+ "service-instance-id": "service-subscription-3",
+ "resource-version": "1495736709053"
+ }
+ ]
+ }
+} \ No newline at end of file
diff --git a/sparkybe-onap-service/src/test/resources/sync/auth/emptyCert.p12 b/sparkybe-onap-service/src/test/resources/sync/auth/emptyCert.p12
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/sparkybe-onap-service/src/test/resources/sync/auth/emptyCert.p12
diff --git a/sparkybe-onap-service/src/test/resources/sync/etc/autoSuggestMappings.json b/sparkybe-onap-service/src/test/resources/sync/etc/autoSuggestMappings.json
new file mode 100644
index 0000000..9e26dfe
--- /dev/null
+++ b/sparkybe-onap-service/src/test/resources/sync/etc/autoSuggestMappings.json
@@ -0,0 +1 @@
+{} \ No newline at end of file
diff --git a/sparkybe-onap-service/src/test/resources/sync/etc/autoSuggestSettings.json b/sparkybe-onap-service/src/test/resources/sync/etc/autoSuggestSettings.json
new file mode 100644
index 0000000..9e26dfe
--- /dev/null
+++ b/sparkybe-onap-service/src/test/resources/sync/etc/autoSuggestSettings.json
@@ -0,0 +1 @@
+{} \ No newline at end of file
diff --git a/sparkybe-onap-service/src/test/resources/user-auth-reader/authorized-users-empty.config b/sparkybe-onap-service/src/test/resources/user-auth-reader/authorized-users-empty.config
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/sparkybe-onap-service/src/test/resources/user-auth-reader/authorized-users-empty.config
diff --git a/sparkybe-onap-service/src/test/resources/user-auth-reader/authorized-users.config b/sparkybe-onap-service/src/test/resources/user-auth-reader/authorized-users.config
new file mode 100644
index 0000000..b9bb4e2
--- /dev/null
+++ b/sparkybe-onap-service/src/test/resources/user-auth-reader/authorized-users.config
@@ -0,0 +1,3 @@
+user1
+user2 user3
+user4 \ No newline at end of file
diff --git a/sparkybe-onap-service/src/test/resources/user-validator/authorized-users.config b/sparkybe-onap-service/src/test/resources/user-validator/authorized-users.config
new file mode 100644
index 0000000..58698bc
--- /dev/null
+++ b/sparkybe-onap-service/src/test/resources/user-validator/authorized-users.config
@@ -0,0 +1,3 @@
+ user1
+user2 user3
+user4 \ No newline at end of file