From ba31685194c77ef140411531299696ae701385d4 Mon Sep 17 00:00:00 2001
From: da490c
Date: Thu, 22 Mar 2018 00:32:52 -0400
Subject: Convert Sparky to Spring-Boot
Issue-ID: AAI-599
Change-Id: If474dd02794f442fdddcd90f62fb75e0d6b907e7
Signed-off-by: da490c
---
.../search/AggregateSummaryProcessor.java | 210 +++
.../search/AggregateVnfSearchProvider.java | 129 ++
.../aggregatevnf/search/VnfSearchQueryBuilder.java | 176 +++
.../sync/AggregationSyncControllerFactory.java | 241 +++
.../aggregation/sync/AggregationSynchronizer.java | 782 ++++++++++
.../sync/HistoricalEntitySummarizer.java | 384 +++++
.../sync/HistoricalEntitySyncController.java | 94 ++
.../aai/sparky/analytics/AbstractStatistics.java | 178 +++
.../aai/sparky/analytics/AveragingRingBuffer.java | 121 ++
.../aai/sparky/analytics/ComponentStatistics.java | 80 +
.../aai/sparky/analytics/HistogramSampler.java | 286 ++++
.../aai/sparky/analytics/HistoricalCounter.java | 177 +++
.../sync/AutoSuggestionSyncController.java | 105 ++
.../sync/AutosuggestionSynchronizer.java | 776 ++++++++++
.../sync/VnfAliasSuggestionSynchronizer.java | 197 +++
.../sync/VnfAliasSyncController.java | 99 ++
.../common/search/CommonSearchSuggestion.java | 90 ++
.../aai/sparky/config/SparkyResourceLoader.java | 125 ++
.../sparky/config/oxm/CrossEntityReference.java | 78 +
.../config/oxm/CrossEntityReferenceDescriptor.java | 67 +
.../config/oxm/CrossEntityReferenceLookup.java | 136 ++
.../aai/sparky/config/oxm/GeoEntityDescriptor.java | 61 +
.../aai/sparky/config/oxm/GeoEntityLookup.java | 137 ++
.../sparky/config/oxm/GeoOxmEntityDescriptor.java | 71 +
.../aai/sparky/config/oxm/OxmEntityDescriptor.java | 68 +
.../aai/sparky/config/oxm/OxmEntityLookup.java | 132 ++
.../onap/aai/sparky/config/oxm/OxmModelLoader.java | 195 +++
.../aai/sparky/config/oxm/OxmModelProcessor.java | 33 +
.../sparky/config/oxm/SearchableEntityLookup.java | 119 ++
.../config/oxm/SearchableOxmEntityDescriptor.java | 75 +
.../config/oxm/SuggestionEntityDescriptor.java | 54 +
.../sparky/config/oxm/SuggestionEntityLookup.java | 181 +++
.../sync/CrossEntityReferenceSynchronizer.java | 937 +++++++++++
.../aai/sparky/dal/ActiveInventoryAdapter.java | 404 +++++
.../onap/aai/sparky/dal/ElasticSearchAdapter.java | 157 ++
.../java/org/onap/aai/sparky/dal/GizmoAdapter.java | 336 ++++
.../onap/aai/sparky/dal/NetworkTransaction.java | 159 ++
.../dal/aai/ActiveInventoryEntityStatistics.java | 285 ++++
...tiveInventoryProcessingExceptionStatistics.java | 139 ++
.../ElasticSearchEntityStatistics.java | 265 ++++
.../exception/ElasticSearchOperationException.java | 53 +
.../dal/proxy/processor/AaiUiProxyProcessor.java | 207 +++
.../org/onap/aai/sparky/dal/rest/HttpMethod.java | 33 +
.../dal/rest/RestClientConstructionException.java | 38 +
.../aai/sparky/dal/rest/RestClientFactory.java | 97 ++
.../sparky/dal/rest/RestOperationalStatistics.java | 255 +++
.../sparky/dal/rest/config/RestEndpointConfig.java | 179 +++
.../editattributes/AttributeEditProcessor.java | 182 +++
.../sparky/editattributes/AttributeUpdater.java | 362 +++++
.../editattributes/UserAuthorizationReader.java | 79 +
.../aai/sparky/editattributes/UserValidator.java | 67 +
.../sparky/editattributes/entity/EditRequest.java | 69 +
.../exception/AttributeUpdateException.java | 62 +
.../inventory/EntityHistoryQueryBuilder.java | 143 ++
.../inventory/GeoVisualizationProcessor.java | 180 +++
.../sparky/inventory/entity/GeoIndexDocument.java | 289 ++++
.../inventory/entity/TopographicalEntity.java | 219 +++
.../org/onap/aai/sparky/logging/AaiUiMsgs.java | 472 ++++++
.../onap/aai/sparky/logging/util/LoggingUtils.java | 43 +
.../onap/aai/sparky/logging/util/ServletUtils.java | 204 +++
.../sparky/search/EntityCountHistoryProcessor.java | 407 +++++
.../onap/aai/sparky/search/EntityTypeSummary.java | 53 +
.../aai/sparky/search/EntityTypeSummaryBucket.java | 46 +
.../aai/sparky/search/SearchEntityProperties.java | 49 +
.../org/onap/aai/sparky/search/SearchResponse.java | 102 ++
.../aai/sparky/search/SearchServiceAdapter.java | 139 ++
.../aai/sparky/search/UnifiedSearchProcessor.java | 188 +++
.../onap/aai/sparky/search/api/SearchProvider.java | 36 +
.../aai/sparky/search/config/SuggestionConfig.java | 76 +
.../sparky/search/entity/QuerySearchEntity.java | 73 +
.../aai/sparky/search/entity/SearchSuggestion.java | 39 +
.../search/filters/FilterElasticSearchAdapter.java | 119 ++
.../aai/sparky/search/filters/FilterProcessor.java | 144 ++
.../sparky/search/filters/FilterQueryBuilder.java | 218 +++
.../search/filters/FilteredSearchHelper.java | 158 ++
.../search/filters/UiFiltersEntityConverter.java | 180 +++
.../search/filters/config/FiltersConfig.java | 158 ++
.../filters/config/FiltersDetailsConfig.java | 58 +
.../filters/config/FiltersForViewsConfig.java | 57 +
.../search/filters/config/UiFilterConfig.java | 188 +++
.../filters/config/UiFilterDataSourceConfig.java | 99 ++
.../filters/config/UiFilterListItemConfig.java | 70 +
.../config/UiFilterOptionsValuesConfig.java | 68 +
.../filters/config/UiViewListItemConfig.java | 68 +
.../search/filters/entity/AggregationEntity.java | 80 +
.../search/filters/entity/BoolQueryBuilder.java | 123 ++
.../entity/FilteredAggregationQueryBuilder.java | 65 +
.../filters/entity/MatchFilterCriteriaEntity.java | 77 +
.../sparky/search/filters/entity/SearchFilter.java | 88 ++
.../search/filters/entity/UiFilterEntity.java | 180 +++
.../search/filters/entity/UiFilterValueEntity.java | 80 +
.../search/filters/entity/UiFiltersEntity.java | 53 +
.../search/registry/SearchProviderRegistry.java | 76 +
.../aai/sparky/security/BaseCookieDecryptor.java | 51 +
.../onap/aai/sparky/security/CookieDecryptor.java | 31 +
.../org/onap/aai/sparky/security/EcompSso.java | 155 ++
.../sparky/security/SecurityContextFactory.java | 78 +
.../security/SecurityContextFactoryImpl.java | 205 +++
.../sparky/security/filter/CspCookieFilter.java | 267 ++++
.../aai/sparky/security/filter/LoginFilter.java | 236 +++
.../security/portal/PortalRestAPIServiceImpl.java | 213 +++
.../aai/sparky/security/portal/UserManager.java | 170 ++
.../portal/config/PortalAuthenticationConfig.java | 124 ++
.../sparky/security/portal/config/RolesConfig.java | 90 ++
.../subscription/SubscriptionServiceProcessor.java | 74 +
.../subscription/config/SubscriptionConfig.java | 139 ++
.../subscription/payload/entity/Message.java | 60 +
.../payload/entity/ObjectInspectorPayload.java | 128 ++
.../sparky/subscription/payload/entity/Params.java | 60 +
.../subscription/payload/entity/Payload.java | 60 +
.../subscription/services/SubscriptionService.java | 65 +
.../sparky/sync/AbstractEntitySynchronizer.java | 524 +++++++
.../aai/sparky/sync/ElasticSearchIndexCleaner.java | 604 ++++++++
.../sparky/sync/ElasticSearchSchemaFactory.java | 97 ++
.../org/onap/aai/sparky/sync/IndexCleaner.java | 57 +
.../aai/sparky/sync/IndexIntegrityValidator.java | 178 +++
.../onap/aai/sparky/sync/IndexSynchronizer.java | 67 +
.../org/onap/aai/sparky/sync/IndexValidator.java | 58 +
.../org/onap/aai/sparky/sync/SyncController.java | 96 ++
.../onap/aai/sparky/sync/SyncControllerImpl.java | 682 ++++++++
.../aai/sparky/sync/SyncControllerRegistrar.java | 29 +
.../aai/sparky/sync/SyncControllerRegistry.java | 50 +
.../aai/sparky/sync/SyncControllerService.java | 222 +++
.../aai/sparky/sync/SynchronizerConstants.java | 65 +
.../onap/aai/sparky/sync/TaskProcessingStats.java | 135 ++
.../aai/sparky/sync/TransactionRateMonitor.java | 75 +
.../sync/config/ElasticSearchEndpointConfig.java | 72 +
.../sync/config/ElasticSearchSchemaConfig.java | 77 +
.../sync/config/NetworkStatisticsConfig.java | 239 +++
.../sparky/sync/config/SyncControllerConfig.java | 305 ++++
.../aai/sparky/sync/entity/AggregationEntity.java | 99 ++
.../sync/entity/AggregationSuggestionEntity.java | 111 ++
.../onap/aai/sparky/sync/entity/IndexDocument.java | 41 +
.../sync/entity/IndexableCrossEntityReference.java | 97 ++
.../aai/sparky/sync/entity/IndexableEntity.java | 100 ++
.../aai/sparky/sync/entity/MergableEntity.java | 59 +
.../aai/sparky/sync/entity/ObjectIdCollection.java | 78 +
.../aai/sparky/sync/entity/SearchableEntity.java | 142 ++
.../aai/sparky/sync/entity/SelfLinkDescriptor.java | 90 ++
.../sparky/sync/entity/SuggestionSearchEntity.java | 327 ++++
.../sparky/sync/entity/TransactionStorageType.java | 56 +
.../sparky/sync/enumeration/OperationState.java | 32 +
.../sparky/sync/enumeration/SynchronizerState.java | 32 +
.../sync/task/PerformActiveInventoryRetrieval.java | 97 ++
.../sparky/sync/task/PerformElasticSearchPut.java | 90 ++
.../sync/task/PerformElasticSearchRetrieval.java | 72 +
.../sync/task/PerformElasticSearchUpdate.java | 82 +
.../sparky/sync/task/PerformGizmoRetrieval.java | 95 ++
.../aai/sparky/sync/task/StoreDocumentTask.java | 90 ++
.../aai/sparky/sync/task/SyncControllerTask.java | 55 +
.../sparky/topology/sync/GeoSyncController.java | 101 ++
.../aai/sparky/topology/sync/GeoSynchronizer.java | 487 ++++++
.../org/onap/aai/sparky/util/ConfigHelper.java | 193 +++
.../org/onap/aai/sparky/util/EncryptConvertor.java | 149 ++
.../java/org/onap/aai/sparky/util/Encryptor.java | 155 ++
.../java/org/onap/aai/sparky/util/ErrorUtil.java | 61 +
.../org/onap/aai/sparky/util/JsonXmlConverter.java | 79 +
.../java/org/onap/aai/sparky/util/NodeUtils.java | 896 +++++++++++
.../org/onap/aai/sparky/util/RawByteHelper.java | 176 +++
.../org/onap/aai/sparky/util/RestletUtils.java | 119 ++
.../aai/sparky/util/SuggestionsPermutation.java | 100 ++
.../java/org/onap/aai/sparky/util/TreeWalker.java | 136 ++
.../viewandinspect/EntityTypeAggregation.java | 61 +
.../SchemaVisualizationProcessor.java | 99 ++
.../viewandinspect/config/SparkyConstants.java | 102 ++
.../config/TierSupportUiConstants.java | 102 ++
.../config/VisualizationConfigs.java | 174 +++
.../viewandinspect/entity/ActiveInventoryNode.java | 831 ++++++++++
.../entity/D3VisualizationOutput.java | 93 ++
.../sparky/viewandinspect/entity/EntityEntry.java | 81 +
.../sparky/viewandinspect/entity/GizmoEntity.java | 98 ++
.../entity/GizmoRelationshipEntity.java | 103 ++
.../entity/GizmoRelationshipHint.java | 77 +
.../sparky/viewandinspect/entity/GraphMeta.java | 147 ++
.../sparky/viewandinspect/entity/GraphRequest.java | 58 +
.../viewandinspect/entity/InlineMessage.java | 70 +
.../aai/sparky/viewandinspect/entity/JsonNode.java | 207 +++
.../sparky/viewandinspect/entity/JsonNodeLink.java | 77 +
.../sparky/viewandinspect/entity/NodeDebug.java | 59 +
.../aai/sparky/viewandinspect/entity/NodeMeta.java | 207 +++
.../entity/NodeProcessingTransaction.java | 109 ++
.../sparky/viewandinspect/entity/QueryParams.java | 57 +
.../sparky/viewandinspect/entity/QueryRequest.java | 47 +
.../viewandinspect/entity/RelatedToProperty.java | 64 +
.../sparky/viewandinspect/entity/Relationship.java | 96 ++
.../viewandinspect/entity/RelationshipData.java | 63 +
.../entity/RelationshipDirectionality.java | 42 +
.../viewandinspect/entity/RelationshipList.java | 57 +
.../entity/SearchableEntityList.java | 116 ++
.../entity/SelfLinkDeterminationTransaction.java | 80 +
.../viewandinspect/entity/SparkyGraphLink.java | 75 +
.../viewandinspect/entity/SparkyGraphNode.java | 248 +++
.../enumeration/NodeProcessingAction.java | 36 +
.../enumeration/NodeProcessingState.java | 31 +
.../search/ViewInspectSearchProvider.java | 426 +++++
.../services/BaseGizmoVisualizationContext.java | 990 ++++++++++++
.../services/BaseVisualizationContext.java | 1631 ++++++++++++++++++++
.../services/BaseVisualizationService.java | 382 +++++
.../services/VisualizationContext.java | 55 +
.../services/VisualizationService.java | 52 +
.../services/VisualizationTransformer.java | 305 ++++
.../PerformGizmoNodeSelfLinkProcessingTask.java | 128 ++
.../task/PerformNodeSelfLinkProcessingTask.java | 129 ++
.../task/PerformSelfLinkDeterminationTask.java | 95 ++
.../sync/ViewInspectEntitySynchronizer.java | 779 ++++++++++
.../sync/ViewInspectSyncController.java | 122 ++
.../main/resources/logging/AAIUIMsgs.properties | 901 +++++++++++
.../sparky/analytics/AveragingRingBufferTest.java | 134 ++
.../aai/sparky/analytics/HistogramSamplerTest.java | 91 ++
.../sparky/analytics/HistoricalCounterTest.java | 70 +
.../analytics/TransactionRateControllerTest.java | 217 +++
.../sync/AutosuggestionSynchronizerTest.java | 387 +++++
.../common/search/CommonSearchSuggestionTest.java | 55 +
.../oxm/CrossEntityReferenceDescriptorTest.java | 34 +
.../config/oxm/CrossEntityReferenceTest.java | 36 +
.../sparky/config/oxm/GeoEntityDescriptorTest.java | 37 +
.../config/oxm/GeoOxmEntityDescriptorTest.java | 40 +
.../config/oxm/OxmEntityContainerLookup.java | 99 ++
.../sparky/config/oxm/OxmEntityDescriptorTest.java | 41 +
.../sync/CrossEntityReferenceSynchronizerTest.java | 1035 +++++++++++++
.../aai/sparky/dal/ActiveInventoryAdapterTest.java | 63 +
.../aai/sparky/dal/ElasticSearchAdapterTest.java | 50 +
.../aai/sparky/dal/NetworkTransactionTest.java | 59 +
.../entity/AutoSuggestDocumentEntity.java | 44 +
.../entity/AutoSuggestDocumentEntityFields.java | 81 +
.../entity/AutoSuggestElasticHitEntity.java | 87 ++
.../entity/AutoSuggestElasticHitsEntity.java | 50 +
.../entity/AutoSuggestElasticSearchResponse.java | 85 +
.../dal/elasticsearch/entity/BucketEntity.java | 61 +
.../dal/elasticsearch/entity/ElasticHit.java | 29 +
.../elasticsearch/entity/ElasticHitsEntity.java | 74 +
.../entity/ElasticSearchAggegrationResponse.java | 109 ++
.../entity/ElasticSearchAggregation.java | 74 +
.../entity/ElasticSearchCountResponse.java | 60 +
.../dal/elasticsearch/entity/PayloadEntity.java | 32 +
.../proxy/processor/AaiUiProxyProcessorTest.java | 145 ++
.../dal/rest/config/RestEndpointConfigTest.java | 76 +
.../dal/sas/config/SearchServiceConfigTest.java | 21 +
.../aai/sparky/dal/sas/entity/DocumentEntity.java | 68 +
.../sparky/dal/sas/entity/EntityCountResponse.java | 55 +
.../dal/sas/entity/GroupByAggregationEntity.java | 60 +
.../entity/GroupByAggregationResponseEntity.java | 48 +
.../onap/aai/sparky/dal/sas/entity/HitEntity.java | 48 +
.../sas/entity/SearchAbstractionEntityBuilder.java | 294 ++++
.../dal/sas/entity/SearchAbstractionResponse.java | 39 +
.../aai/sparky/dal/sas/entity/SearchResult.java | 49 +
.../editattributes/AttributeUpdaterTest.java | 164 ++
.../sparky/editattributes/EditAttributesTest.java | 171 ++
.../TestUserAuthorizationReader.java | 113 ++
.../sparky/editattributes/TestUserValidator.java | 137 ++
.../editattributes/entity/EditRequestTest.java | 43 +
.../inventory/EntityHistoryQueryBuilderTest.java | 34 +
.../aai/sparky/inventory/GeoIndexDocumentTest.java | 121 ++
.../inventory/entity/TopographicalEntityTest.java | 50 +
.../aai/sparky/logging/util/LoggingUtilsTest.java | 25 +
.../search/EntityCountHistoryProcessorTest.java | 154 ++
.../sparky/search/EntityTypeSummaryBucketTest.java | 31 +
.../aai/sparky/search/EntityTypeSummaryTest.java | 37 +
.../sparky/search/SearchEntityPropertiesTest.java | 34 +
.../sparky/search/SearchServiceAdapterTest.java | 47 +
.../sparky/search/UnifiedSearchProcessorTest.java | 445 ++++++
.../sparky/search/config/SuggestionConfigTest.java | 42 +
.../sparky/search/entity/MockSearchResponse.java | 71 +
.../sparky/search/filters/FilterProcessorTest.java | 374 +++++
.../search/filters/FilteredSearchHelperTest.java | 69 +
.../search/filters/config/FiltersConfigTest.java | 47 +
.../filters/config/FiltersDetailsConfigTest.java | 40 +
.../filters/config/FiltersForViewsConfigTest.java | 40 +
.../search/filters/config/UiFilterConfigTest.java | 57 +
.../config/UiFilterDataSourceConfigTest.java | 44 +
.../filters/config/UiFilterListItemConfigTest.java | 34 +
.../config/UiFilterOptionsValuesConfigTest.java | 31 +
.../filters/config/UiViewListItemConfigTest.java | 38 +
.../filters/entity/DiscoverFiltersRequest.java | 40 +
.../search/filters/entity/ViewConfiguration.java | 68 +
.../sparky/search/filters/entity/ViewFilter.java | 57 +
.../security/SecurityContextFactoryImplTest.java | 143 ++
.../portal/TestPortalRestAPIServiceImpl.java | 283 ++++
.../sparky/security/portal/TestUserManager.java | 265 ++++
.../config/SubscriptionConfigTest.java | 54 +
.../subscription/payload/entity/MessageTest.java | 32 +
.../payload/entity/ObjectInspectorPayloadTest.java | 43 +
.../subscription/payload/entity/ParamsTest.java | 30 +
.../subscription/payload/entity/PayloadTest.java | 32 +
.../sync/AbstractEntitySynchronizerTest.java | 463 ++++++
.../sparky/sync/AggregationSynchronizerTest.java | 345 +++++
.../sparky/sync/ElasticSearchIndexCleanerTest.java | 122 ++
.../aai/sparky/sync/SyncControllerImplTest.java | 81 +
.../config/ElasticSearchEndpointConfigTest.java | 39 +
.../sync/config/ElasticSearchSchemaConfigTest.java | 47 +
.../sync/config/NetworkStatisticsConfigTest.java | 74 +
.../sync/config/SyncControllerConfigTest.java | 64 +
.../synchronizer/AsyncRateControlTester.java | 242 +++
.../sparky/synchronizer/GizmoEntitySummarizer.java | 251 +++
.../aai/sparky/synchronizer/IndexDocumentTest.java | 104 ++
.../IndexableCrossEntityReferenceTest.java | 72 +
.../sparky/synchronizer/SyncControllerBuilder.java | 512 ++++++
.../synchronizer/SyncControllerServiceTest.java | 34 +
.../sparky/synchronizer/TestSyncController.java | 177 +++
.../entity/AggregationSuggestionEntityTest.java | 75 +
.../entity/SuggestionSearchEntityTest.java | 187 +++
.../task/PerformActiveInventoryRetrievalTest.java | 93 ++
.../aai/sparky/util/CaptureLoggerAppender.java | 247 +++
.../org/onap/aai/sparky/util/ExceptionHelper.java | 62 +
.../onap/aai/sparky/util/HttpServletHelper.java | 162 ++
.../org/onap/aai/sparky/util/LogValidator.java | 85 +
.../sparky/util/OxmModelAndProcessorHelper.java | 143 ++
.../onap/aai/sparky/util/SparkyTestConstants.java | 19 +
.../util/StringCollectionContainsMatcher.java | 39 +
.../sparky/util/SuggestionsPermutationTest.java | 130 ++
.../onap/aai/sparky/util/TestResourceLoader.java | 31 +
.../org/onap/aai/sparky/util/TreeWalkerTest.java | 563 +++++++
.../BaseVisualizationContextTest.java | 5 +
.../BaseVisualizationServiceTest.java | 75 +
.../SchemaVisualizationProcessorTest.java | 78 +
.../sparky/viewandinspect/SearchAdapterTest.java | 87 ++
.../sparky/viewandinspect/SearchResponseTest.java | 92 ++
.../sparky/viewandinspect/SearchServletTest.java | 992 ++++++++++++
.../viewandinspect/SearchableGroupsTest.java | 73 +
.../ViewAndInspectSearchRequestTest.java | 81 +
.../VisualizationTransformerTest.java | 77 +
.../config/VisualizationConfigTest.java | 62 +
.../entity/ActiveInventoryNodeTest.java | 128 ++
.../entity/D3VisualizationOutputTest.java | 46 +
.../viewandinspect/entity/EntityEntryTest.java | 94 ++
.../viewandinspect/entity/GraphMetaTest.java | 61 +
.../viewandinspect/entity/GraphRequestTest.java | 61 +
.../viewandinspect/entity/InlineMessageTest.java | 55 +
.../viewandinspect/entity/JsonNodeLinkTest.java | 57 +
.../viewandinspect/entity/NodeDebugTest.java | 57 +
.../sparky/viewandinspect/entity/NodeMetaTest.java | 88 ++
.../entity/NodeProcessingTransactionTest.java | 62 +
.../viewandinspect/entity/QueryParamsTest.java | 56 +
.../viewandinspect/entity/QueryRequestTest.java | 54 +
.../entity/RelatedToPropertyTest.java | 54 +
.../entity/RelationshipDataTest.java | 54 +
.../entity/RelationshipListTest.java | 32 +
.../viewandinspect/entity/RelationshipTest.java | 43 +
.../viewandinspect/entity/SearchResponseTest.java | 52 +
.../entity/SearchableEntityListTest.java | 44 +
.../SelfLinkDeterminationTransactionTest.java | 68 +
.../viewandinspect/entity/SparkyGraphLinkTest.java | 56 +
.../viewandinspect/entity/SparkyGraphNodeTest.java | 81 +
.../services/BaseVisualizationContextTest.java | 273 ++++
.../sync/ViewInspectGizmoEntitySynchronizer.java | 792 ++++++++++
.../sync/ViewInspectGizmoSyncController.java | 107 ++
.../util/SchemaVisualizationTestDataBuilder.java | 134 ++
.../etc/appprops/source-of-truth.properties | 47 +
.../test/resources/es_test_scripts/commands.txt | 3 +
.../resources/es_test_scripts/geoEntities.json | 6 +
.../es_test_scripts/prepareGeoEntityBulkImport.pl | 41 +
.../es_test_scripts/sampleGeoEntities.csv | 4 +
.../es_test_scripts/topoHistoryBulkLoad.json | 24 +
.../es_test_scripts/topoHistoryConfigSettings.json | 20 +
.../topographicalConfigSettings.json | 24 +
.../es_test_scripts/topographysearch_schema.json | 9 +
...estionEntity_getIndexDocumentJson_expected.json | 1 +
.../src/test/resources/filters/aaiui_filters.json | 88 ++
.../filters/aaiui_filters_testConfig.json | 79 +
.../src/test/resources/filters/aaiui_views.json | 38 +
.../resources/filters/aaiui_views_testConfig.json | 21 +
...Endpoint_emptyRequestBody_expectedResponse.json | 1 +
...t_emptyRequestFilterArray_expectedResponse.json | 1 +
...dpoint_emptyRequestFilterArray_requestBody.json | 3 +
...ationEndpoint_successPath_expectedResponse.json | 1 +
...gationEndpoint_successPath_operationResult.json | 1 +
...ggregationEndpoint_successPath_requestBody.json | 11 +
.../portal/portal-authentication.properties | 2 +
.../src/test/resources/portal/roles.config | 6 +
...terSync_ElasticSearch_ScrollApi_Successful.json | 171 ++
...oreSync_ElasticSearch_ScrollApi_Successful.json | 156 ++
.../ElasticSearch/docEntityFromElasticSearch1.json | 17 +
.../ElasticSearch/docEntityFromElasticSearch2.json | 17 +
.../ElasticSearch/docEntityFromElasticSearch3.json | 17 +
.../ElasticSearch/docEntityFromElasticSearch4.json | 17 +
.../ElasticSearch/docEntityFromElasticSearch5.json | 17 +
.../aai/aai-resources/customer/customer-4.json | 60 +
.../service-instance/service-instance-50.json | 26 +
.../service-instance/service-instance-51.json | 28 +
.../service-instance/service-instance-52.json | 12 +
.../service-instance/service-instance-53.json | 12 +
.../service-instance/service-instance-54.json | 6 +
.../service-instance/service-instance-55.json | 8 +
.../service-instance/service-instance-56.json | 4 +
.../service-instance/service-instance-57.json | 11 +
.../service-instance/service-instance-58.json | 32 +
.../service-instance/service-instance-59.json | 4 +
.../service-subscription-2.json | 50 +
.../sync/aai/aai-resources/tenant/tenant-1.json | 23 +
.../generic-query/service-instance-50.json | 8 +
.../generic-query/service-instance-51.json | 8 +
.../generic-query/service-instance-52.json | 8 +
.../generic-query/service-instance-53.json | 8 +
.../generic-query/service-instance-54.json | 8 +
.../generic-query/service-instance-55.json | 8 +
.../generic-query/service-instance-56.json | 8 +
.../generic-query/service-instance-57.json | 8 +
.../generic-query/service-instance-58.json | 8 +
.../generic-query/service-instance-59.json | 8 +
.../service-instance/service-instance-54.json | 8 +
.../service-instance/service-instance-55.json | 8 +
.../service-subscription-2.json | 8 +
...ctiveInventory_complex_nodesQuery_response.json | 24 +
...eInventory_generic-vnf_nodesQuery_response.json | 16 +
...y_service-subscription_nodesQuery_response.json | 16 +
.../aai/complex1_fullDepth_aaiEntityRetrieval.json | 30 +
.../aai/complex2_fullDepth_aaiEntityRetrieval.json | 30 +
.../aai/complex3_fullDepth_aaiEntityRetrieval.json | 30 +
.../aai/complex4_fullDepth_aaiEntityRetrieval.json | 30 +
.../aai/complex5_fullDepth_aaiEntityRetrieval.json | 30 +
.../aai/generic-vnf-generic-vnf-1_full_depth.json | 136 ++
.../aai/generic-vnf-generic-vnf-2_full_depth.json | 118 ++
.../aai/generic-vnf-generic-vnf-3_full_depth.json | 30 +
...ervice-subscription-service-subscription-1.json | 12 +
...ervice-subscription-service-subscription-2.json | 350 +++++
...ervice-subscription-service-subscription-3.json | 12 +
.../src/test/resources/sync/auth/emptyCert.p12 | 0
.../resources/sync/etc/autoSuggestMappings.json | 1 +
.../resources/sync/etc/autoSuggestSettings.json | 1 +
.../user-auth-reader/authorized-users-empty.config | 0
.../user-auth-reader/authorized-users.config | 3 +
.../user-validator/authorized-users.config | 3 +
422 files changed, 53750 insertions(+)
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/aggregatevnf/search/AggregateSummaryProcessor.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/aggregatevnf/search/AggregateVnfSearchProvider.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/aggregatevnf/search/VnfSearchQueryBuilder.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/aggregation/sync/AggregationSyncControllerFactory.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/aggregation/sync/AggregationSynchronizer.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/aggregation/sync/HistoricalEntitySummarizer.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/aggregation/sync/HistoricalEntitySyncController.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/analytics/AbstractStatistics.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/analytics/AveragingRingBuffer.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/analytics/ComponentStatistics.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/analytics/HistogramSampler.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/analytics/HistoricalCounter.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/autosuggestion/sync/AutoSuggestionSyncController.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/autosuggestion/sync/AutosuggestionSynchronizer.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/autosuggestion/sync/VnfAliasSuggestionSynchronizer.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/autosuggestion/sync/VnfAliasSyncController.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/common/search/CommonSearchSuggestion.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/config/SparkyResourceLoader.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/config/oxm/CrossEntityReference.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/config/oxm/CrossEntityReferenceDescriptor.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/config/oxm/CrossEntityReferenceLookup.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/config/oxm/GeoEntityDescriptor.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/config/oxm/GeoEntityLookup.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/config/oxm/GeoOxmEntityDescriptor.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/config/oxm/OxmEntityDescriptor.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/config/oxm/OxmEntityLookup.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/config/oxm/OxmModelLoader.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/config/oxm/OxmModelProcessor.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/config/oxm/SearchableEntityLookup.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/config/oxm/SearchableOxmEntityDescriptor.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/config/oxm/SuggestionEntityDescriptor.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/config/oxm/SuggestionEntityLookup.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/crossentityreference/sync/CrossEntityReferenceSynchronizer.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/dal/ActiveInventoryAdapter.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/dal/ElasticSearchAdapter.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/dal/GizmoAdapter.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/dal/NetworkTransaction.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/dal/aai/ActiveInventoryEntityStatistics.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/dal/aai/ActiveInventoryProcessingExceptionStatistics.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/dal/elasticsearch/ElasticSearchEntityStatistics.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/dal/exception/ElasticSearchOperationException.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/dal/proxy/processor/AaiUiProxyProcessor.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/dal/rest/HttpMethod.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/dal/rest/RestClientConstructionException.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/dal/rest/RestClientFactory.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/dal/rest/RestOperationalStatistics.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/dal/rest/config/RestEndpointConfig.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/editattributes/AttributeEditProcessor.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/editattributes/AttributeUpdater.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/editattributes/UserAuthorizationReader.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/editattributes/UserValidator.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/editattributes/entity/EditRequest.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/editattributes/exception/AttributeUpdateException.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/inventory/EntityHistoryQueryBuilder.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/inventory/GeoVisualizationProcessor.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/inventory/entity/GeoIndexDocument.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/inventory/entity/TopographicalEntity.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/logging/AaiUiMsgs.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/logging/util/LoggingUtils.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/logging/util/ServletUtils.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/EntityCountHistoryProcessor.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/EntityTypeSummary.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/EntityTypeSummaryBucket.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/SearchEntityProperties.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/SearchResponse.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/SearchServiceAdapter.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/UnifiedSearchProcessor.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/api/SearchProvider.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/config/SuggestionConfig.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/entity/QuerySearchEntity.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/entity/SearchSuggestion.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/FilterElasticSearchAdapter.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/FilterProcessor.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/FilterQueryBuilder.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/FilteredSearchHelper.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/UiFiltersEntityConverter.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/config/FiltersConfig.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/config/FiltersDetailsConfig.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/config/FiltersForViewsConfig.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/config/UiFilterConfig.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/config/UiFilterDataSourceConfig.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/config/UiFilterListItemConfig.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/config/UiFilterOptionsValuesConfig.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/config/UiViewListItemConfig.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/entity/AggregationEntity.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/entity/BoolQueryBuilder.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/entity/FilteredAggregationQueryBuilder.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/entity/MatchFilterCriteriaEntity.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/entity/SearchFilter.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/entity/UiFilterEntity.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/entity/UiFilterValueEntity.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/filters/entity/UiFiltersEntity.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/search/registry/SearchProviderRegistry.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/security/BaseCookieDecryptor.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/security/CookieDecryptor.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/security/EcompSso.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/security/SecurityContextFactory.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/security/SecurityContextFactoryImpl.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/security/filter/CspCookieFilter.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/security/filter/LoginFilter.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/security/portal/PortalRestAPIServiceImpl.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/security/portal/UserManager.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/security/portal/config/PortalAuthenticationConfig.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/security/portal/config/RolesConfig.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/subscription/SubscriptionServiceProcessor.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/subscription/config/SubscriptionConfig.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/subscription/payload/entity/Message.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/subscription/payload/entity/ObjectInspectorPayload.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/subscription/payload/entity/Params.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/subscription/payload/entity/Payload.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/subscription/services/SubscriptionService.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/AbstractEntitySynchronizer.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/ElasticSearchIndexCleaner.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/ElasticSearchSchemaFactory.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/IndexCleaner.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/IndexIntegrityValidator.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/IndexSynchronizer.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/IndexValidator.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/SyncController.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/SyncControllerImpl.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/SyncControllerRegistrar.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/SyncControllerRegistry.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/SyncControllerService.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/SynchronizerConstants.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/TaskProcessingStats.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/TransactionRateMonitor.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/config/ElasticSearchEndpointConfig.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/config/ElasticSearchSchemaConfig.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/config/NetworkStatisticsConfig.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/config/SyncControllerConfig.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/entity/AggregationEntity.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/entity/AggregationSuggestionEntity.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/entity/IndexDocument.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/entity/IndexableCrossEntityReference.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/entity/IndexableEntity.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/entity/MergableEntity.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/entity/ObjectIdCollection.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/entity/SearchableEntity.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/entity/SelfLinkDescriptor.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/entity/SuggestionSearchEntity.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/entity/TransactionStorageType.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/enumeration/OperationState.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/enumeration/SynchronizerState.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/task/PerformActiveInventoryRetrieval.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/task/PerformElasticSearchPut.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/task/PerformElasticSearchRetrieval.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/task/PerformElasticSearchUpdate.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/task/PerformGizmoRetrieval.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/task/StoreDocumentTask.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/sync/task/SyncControllerTask.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/topology/sync/GeoSyncController.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/topology/sync/GeoSynchronizer.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/util/ConfigHelper.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/util/EncryptConvertor.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/util/Encryptor.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/util/ErrorUtil.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/util/JsonXmlConverter.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/util/NodeUtils.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/util/RawByteHelper.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/util/RestletUtils.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/util/SuggestionsPermutation.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/util/TreeWalker.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/EntityTypeAggregation.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/SchemaVisualizationProcessor.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/config/SparkyConstants.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/config/TierSupportUiConstants.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/config/VisualizationConfigs.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/ActiveInventoryNode.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/D3VisualizationOutput.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/EntityEntry.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/GizmoEntity.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/GizmoRelationshipEntity.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/GizmoRelationshipHint.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/GraphMeta.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/GraphRequest.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/InlineMessage.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/JsonNode.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/JsonNodeLink.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/NodeDebug.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/NodeMeta.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/NodeProcessingTransaction.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/QueryParams.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/QueryRequest.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/RelatedToProperty.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/Relationship.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/RelationshipData.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/RelationshipDirectionality.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/RelationshipList.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/SearchableEntityList.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/SelfLinkDeterminationTransaction.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/SparkyGraphLink.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/entity/SparkyGraphNode.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/enumeration/NodeProcessingAction.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/enumeration/NodeProcessingState.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/search/ViewInspectSearchProvider.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/services/BaseGizmoVisualizationContext.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/services/BaseVisualizationContext.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/services/BaseVisualizationService.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/services/VisualizationContext.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/services/VisualizationService.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/services/VisualizationTransformer.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/task/PerformGizmoNodeSelfLinkProcessingTask.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/task/PerformNodeSelfLinkProcessingTask.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewandinspect/task/PerformSelfLinkDeterminationTask.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewinspect/sync/ViewInspectEntitySynchronizer.java
create mode 100644 sparkybe-onap-service/src/main/java/org/onap/aai/sparky/viewinspect/sync/ViewInspectSyncController.java
create mode 100644 sparkybe-onap-service/src/main/resources/logging/AAIUIMsgs.properties
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/analytics/AveragingRingBufferTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/analytics/HistogramSamplerTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/analytics/HistoricalCounterTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/analytics/TransactionRateControllerTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/autosuggestion/sync/AutosuggestionSynchronizerTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/common/search/CommonSearchSuggestionTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/config/oxm/CrossEntityReferenceDescriptorTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/config/oxm/CrossEntityReferenceTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/config/oxm/GeoEntityDescriptorTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/config/oxm/GeoOxmEntityDescriptorTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/config/oxm/OxmEntityContainerLookup.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/config/oxm/OxmEntityDescriptorTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/crossentityreference/sync/CrossEntityReferenceSynchronizerTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/ActiveInventoryAdapterTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/ElasticSearchAdapterTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/NetworkTransactionTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/elasticsearch/entity/AutoSuggestDocumentEntity.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/elasticsearch/entity/AutoSuggestDocumentEntityFields.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/elasticsearch/entity/AutoSuggestElasticHitEntity.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/elasticsearch/entity/AutoSuggestElasticHitsEntity.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/elasticsearch/entity/AutoSuggestElasticSearchResponse.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/elasticsearch/entity/BucketEntity.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/elasticsearch/entity/ElasticHit.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/elasticsearch/entity/ElasticHitsEntity.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/elasticsearch/entity/ElasticSearchAggegrationResponse.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/elasticsearch/entity/ElasticSearchAggregation.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/elasticsearch/entity/ElasticSearchCountResponse.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/elasticsearch/entity/PayloadEntity.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/proxy/processor/AaiUiProxyProcessorTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/rest/config/RestEndpointConfigTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/sas/config/SearchServiceConfigTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/sas/entity/DocumentEntity.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/sas/entity/EntityCountResponse.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/sas/entity/GroupByAggregationEntity.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/sas/entity/GroupByAggregationResponseEntity.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/sas/entity/HitEntity.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/sas/entity/SearchAbstractionEntityBuilder.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/sas/entity/SearchAbstractionResponse.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/dal/sas/entity/SearchResult.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/editattributes/AttributeUpdaterTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/editattributes/EditAttributesTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/editattributes/TestUserAuthorizationReader.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/editattributes/TestUserValidator.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/editattributes/entity/EditRequestTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/inventory/EntityHistoryQueryBuilderTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/inventory/GeoIndexDocumentTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/inventory/entity/TopographicalEntityTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/logging/util/LoggingUtilsTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/EntityCountHistoryProcessorTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/EntityTypeSummaryBucketTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/EntityTypeSummaryTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/SearchEntityPropertiesTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/SearchServiceAdapterTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/UnifiedSearchProcessorTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/config/SuggestionConfigTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/entity/MockSearchResponse.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/filters/FilterProcessorTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/filters/FilteredSearchHelperTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/filters/config/FiltersConfigTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/filters/config/FiltersDetailsConfigTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/filters/config/FiltersForViewsConfigTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/filters/config/UiFilterConfigTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/filters/config/UiFilterDataSourceConfigTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/filters/config/UiFilterListItemConfigTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/filters/config/UiFilterOptionsValuesConfigTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/filters/config/UiViewListItemConfigTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/filters/entity/DiscoverFiltersRequest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/filters/entity/ViewConfiguration.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/search/filters/entity/ViewFilter.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/security/SecurityContextFactoryImplTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/security/portal/TestPortalRestAPIServiceImpl.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/security/portal/TestUserManager.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/subscription/config/SubscriptionConfigTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/subscription/payload/entity/MessageTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/subscription/payload/entity/ObjectInspectorPayloadTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/subscription/payload/entity/ParamsTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/subscription/payload/entity/PayloadTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/sync/AbstractEntitySynchronizerTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/sync/AggregationSynchronizerTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/sync/ElasticSearchIndexCleanerTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/sync/SyncControllerImplTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/sync/config/ElasticSearchEndpointConfigTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/sync/config/ElasticSearchSchemaConfigTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/sync/config/NetworkStatisticsConfigTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/sync/config/SyncControllerConfigTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/synchronizer/AsyncRateControlTester.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/synchronizer/GizmoEntitySummarizer.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/synchronizer/IndexDocumentTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/synchronizer/IndexableCrossEntityReferenceTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/synchronizer/SyncControllerBuilder.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/synchronizer/SyncControllerServiceTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/synchronizer/TestSyncController.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/synchronizer/entity/AggregationSuggestionEntityTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/synchronizer/entity/SuggestionSearchEntityTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/synchronizer/task/PerformActiveInventoryRetrievalTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/util/CaptureLoggerAppender.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/util/ExceptionHelper.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/util/HttpServletHelper.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/util/LogValidator.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/util/OxmModelAndProcessorHelper.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/util/SparkyTestConstants.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/util/StringCollectionContainsMatcher.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/util/SuggestionsPermutationTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/util/TestResourceLoader.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/util/TreeWalkerTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/BaseVisualizationContextTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/BaseVisualizationServiceTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/SchemaVisualizationProcessorTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/SearchAdapterTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/SearchResponseTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/SearchServletTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/SearchableGroupsTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/ViewAndInspectSearchRequestTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/VisualizationTransformerTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/config/VisualizationConfigTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/ActiveInventoryNodeTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/D3VisualizationOutputTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/EntityEntryTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/GraphMetaTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/GraphRequestTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/InlineMessageTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/JsonNodeLinkTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/NodeDebugTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/NodeMetaTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/NodeProcessingTransactionTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/QueryParamsTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/QueryRequestTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/RelatedToPropertyTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/RelationshipDataTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/RelationshipListTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/RelationshipTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/SearchResponseTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/SearchableEntityListTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/SelfLinkDeterminationTransactionTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/SparkyGraphLinkTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/entity/SparkyGraphNodeTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/services/BaseVisualizationContextTest.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/sync/ViewInspectGizmoEntitySynchronizer.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/sync/ViewInspectGizmoSyncController.java
create mode 100644 sparkybe-onap-service/src/test/java/org/onap/aai/sparky/viewandinspect/util/SchemaVisualizationTestDataBuilder.java
create mode 100644 sparkybe-onap-service/src/test/resources/bundleconfig/etc/appprops/source-of-truth.properties
create mode 100644 sparkybe-onap-service/src/test/resources/es_test_scripts/commands.txt
create mode 100644 sparkybe-onap-service/src/test/resources/es_test_scripts/geoEntities.json
create mode 100644 sparkybe-onap-service/src/test/resources/es_test_scripts/prepareGeoEntityBulkImport.pl
create mode 100644 sparkybe-onap-service/src/test/resources/es_test_scripts/sampleGeoEntities.csv
create mode 100644 sparkybe-onap-service/src/test/resources/es_test_scripts/topoHistoryBulkLoad.json
create mode 100644 sparkybe-onap-service/src/test/resources/es_test_scripts/topoHistoryConfigSettings.json
create mode 100644 sparkybe-onap-service/src/test/resources/es_test_scripts/topographicalConfigSettings.json
create mode 100644 sparkybe-onap-service/src/test/resources/es_test_scripts/topographysearch_schema.json
create mode 100644 sparkybe-onap-service/src/test/resources/filters/AggregationSuggestionEntity_getIndexDocumentJson_expected.json
create mode 100644 sparkybe-onap-service/src/test/resources/filters/aaiui_filters.json
create mode 100644 sparkybe-onap-service/src/test/resources/filters/aaiui_filters_testConfig.json
create mode 100644 sparkybe-onap-service/src/test/resources/filters/aaiui_views.json
create mode 100644 sparkybe-onap-service/src/test/resources/filters/aaiui_views_testConfig.json
create mode 100644 sparkybe-onap-service/src/test/resources/filters/filterAggregationEndpoint_emptyRequestBody_expectedResponse.json
create mode 100644 sparkybe-onap-service/src/test/resources/filters/filterAggregationEndpoint_emptyRequestFilterArray_expectedResponse.json
create mode 100644 sparkybe-onap-service/src/test/resources/filters/filterAggregationEndpoint_emptyRequestFilterArray_requestBody.json
create mode 100644 sparkybe-onap-service/src/test/resources/filters/filterAggregationEndpoint_successPath_expectedResponse.json
create mode 100644 sparkybe-onap-service/src/test/resources/filters/filterAggregationEndpoint_successPath_operationResult.json
create mode 100644 sparkybe-onap-service/src/test/resources/filters/filterAggregationEndpoint_successPath_requestBody.json
create mode 100644 sparkybe-onap-service/src/test/resources/portal/portal-authentication.properties
create mode 100644 sparkybe-onap-service/src/test/resources/portal/roles.config
create mode 100644 sparkybe-onap-service/src/test/resources/sync/ElasticSearch/AfterSync_ElasticSearch_ScrollApi_Successful.json
create mode 100644 sparkybe-onap-service/src/test/resources/sync/ElasticSearch/BeforeSync_ElasticSearch_ScrollApi_Successful.json
create mode 100644 sparkybe-onap-service/src/test/resources/sync/ElasticSearch/docEntityFromElasticSearch1.json
create mode 100644 sparkybe-onap-service/src/test/resources/sync/ElasticSearch/docEntityFromElasticSearch2.json
create mode 100644 sparkybe-onap-service/src/test/resources/sync/ElasticSearch/docEntityFromElasticSearch3.json
create mode 100644 sparkybe-onap-service/src/test/resources/sync/ElasticSearch/docEntityFromElasticSearch4.json
create mode 100644 sparkybe-onap-service/src/test/resources/sync/ElasticSearch/docEntityFromElasticSearch5.json
create mode 100644 sparkybe-onap-service/src/test/resources/sync/aai/aai-resources/customer/customer-4.json
create mode 100644 sparkybe-onap-service/src/test/resources/sync/aai/aai-resources/service-instance/service-instance-50.json
create mode 100644 sparkybe-onap-service/src/test/resources/sync/aai/aai-resources/service-instance/service-instance-51.json
create mode 100644 sparkybe-onap-service/src/test/resources/sync/aai/aai-resources/service-instance/service-instance-52.json
create mode 100644 sparkybe-onap-service/src/test/resources/sync/aai/aai-resources/service-instance/service-instance-53.json
create mode 100644 sparkybe-onap-service/src/test/resources/sync/aai/aai-resources/service-instance/service-instance-54.json
create mode 100644 sparkybe-onap-service/src/test/resources/sync/aai/aai-resources/service-instance/service-instance-55.json
create mode 100644 sparkybe-onap-service/src/test/resources/sync/aai/aai-resources/service-instance/service-instance-56.json
create mode 100644 sparkybe-onap-service/src/test/resources/sync/aai/aai-resources/service-instance/service-instance-57.json
create mode 100644 sparkybe-onap-service/src/test/resources/sync/aai/aai-resources/service-instance/service-instance-58.json
create mode 100644 sparkybe-onap-service/src/test/resources/sync/aai/aai-resources/service-instance/service-instance-59.json
create mode 100644 sparkybe-onap-service/src/test/resources/sync/aai/aai-resources/service-subscription/service-subscription-2.json
create mode 100644 sparkybe-onap-service/src/test/resources/sync/aai/aai-resources/tenant/tenant-1.json
create mode 100644 sparkybe-onap-service/src/test/resources/sync/aai/aai-traversal/generic-query/service-instance-50.json
create mode 100644 sparkybe-onap-service/src/test/resources/sync/aai/aai-traversal/generic-query/service-instance-51.json
create mode 100644 sparkybe-onap-service/src/test/resources/sync/aai/aai-traversal/generic-query/service-instance-52.json
create mode 100644 sparkybe-onap-service/src/test/resources/sync/aai/aai-traversal/generic-query/service-instance-53.json
create mode 100644 sparkybe-onap-service/src/test/resources/sync/aai/aai-traversal/generic-query/service-instance-54.json
create mode 100644 sparkybe-onap-service/src/test/resources/sync/aai/aai-traversal/generic-query/service-instance-55.json
create mode 100644 sparkybe-onap-service/src/test/resources/sync/aai/aai-traversal/generic-query/service-instance-56.json
create mode 100644 sparkybe-onap-service/src/test/resources/sync/aai/aai-traversal/generic-query/service-instance-57.json
create mode 100644 sparkybe-onap-service/src/test/resources/sync/aai/aai-traversal/generic-query/service-instance-58.json
create mode 100644 sparkybe-onap-service/src/test/resources/sync/aai/aai-traversal/generic-query/service-instance-59.json
create mode 100644 sparkybe-onap-service/src/test/resources/sync/aai/aai-traversal/generic-query/service-instance/service-instance-54.json
create mode 100644 sparkybe-onap-service/src/test/resources/sync/aai/aai-traversal/generic-query/service-instance/service-instance-55.json
create mode 100644 sparkybe-onap-service/src/test/resources/sync/aai/aai-traversal/generic-query/service-subscription/service-subscription-2.json
create mode 100644 sparkybe-onap-service/src/test/resources/sync/aai/activeInventory_complex_nodesQuery_response.json
create mode 100644 sparkybe-onap-service/src/test/resources/sync/aai/activeInventory_generic-vnf_nodesQuery_response.json
create mode 100644 sparkybe-onap-service/src/test/resources/sync/aai/activeInventory_service-subscription_nodesQuery_response.json
create mode 100644 sparkybe-onap-service/src/test/resources/sync/aai/complex1_fullDepth_aaiEntityRetrieval.json
create mode 100644 sparkybe-onap-service/src/test/resources/sync/aai/complex2_fullDepth_aaiEntityRetrieval.json
create mode 100644 sparkybe-onap-service/src/test/resources/sync/aai/complex3_fullDepth_aaiEntityRetrieval.json
create mode 100644 sparkybe-onap-service/src/test/resources/sync/aai/complex4_fullDepth_aaiEntityRetrieval.json
create mode 100644 sparkybe-onap-service/src/test/resources/sync/aai/complex5_fullDepth_aaiEntityRetrieval.json
create mode 100644 sparkybe-onap-service/src/test/resources/sync/aai/generic-vnf-generic-vnf-1_full_depth.json
create mode 100644 sparkybe-onap-service/src/test/resources/sync/aai/generic-vnf-generic-vnf-2_full_depth.json
create mode 100644 sparkybe-onap-service/src/test/resources/sync/aai/generic-vnf-generic-vnf-3_full_depth.json
create mode 100644 sparkybe-onap-service/src/test/resources/sync/aai/service-subscription-service-subscription-1.json
create mode 100644 sparkybe-onap-service/src/test/resources/sync/aai/service-subscription-service-subscription-2.json
create mode 100644 sparkybe-onap-service/src/test/resources/sync/aai/service-subscription-service-subscription-3.json
create mode 100644 sparkybe-onap-service/src/test/resources/sync/auth/emptyCert.p12
create mode 100644 sparkybe-onap-service/src/test/resources/sync/etc/autoSuggestMappings.json
create mode 100644 sparkybe-onap-service/src/test/resources/sync/etc/autoSuggestSettings.json
create mode 100644 sparkybe-onap-service/src/test/resources/user-auth-reader/authorized-users-empty.config
create mode 100644 sparkybe-onap-service/src/test/resources/user-auth-reader/authorized-users.config
create mode 100644 sparkybe-onap-service/src/test/resources/user-validator/authorized-users.config
(limited to 'sparkybe-onap-service/src')
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 filtersToQuery = new ArrayList();
+ 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 filtersToQuery) throws IOException {
+
+ List searchFilters = new ArrayList();
+ 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 search(QuerySearchEntity queryRequest) {
+
+ List returnList = new ArrayList();
+
+ 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 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 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 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 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 attributes) {
+ JsonObjectBuilder jsonBuilder = Json.createObjectBuilder();
+ if (attributes.size() == 1) {
+ Map.Entry 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 aggregationEntityToIndexMap;
+ private Map indexNameToSchemaConfigMap;
+
+ private ElasticSearchEndpointConfig elasticSearchEndpointConfig;
+ private SyncControllerConfig syncControllerConfig;
+ private SyncControllerRegistry syncControllerRegistry;
+ private NetworkStatisticsConfig aaiStatConfig;
+ private NetworkStatisticsConfig esStatConfig;
+ private OxmEntityLookup oxmEntityLookup;
+ private ElasticSearchSchemaFactory elasticSearchSchemaFactory;
+
+ private List syncControllers;
+
+ public AggregationSyncControllerFactory(ElasticSearchEndpointConfig esEndpointConfig,
+ SyncControllerConfig syncControllerConfig, SyncControllerRegistry syncControllerRegistry,
+ SuggestionEntityLookup suggestionEntityLookup,
+ OxmEntityLookup oxmEntityLookup,
+ ElasticSearchSchemaFactory elasticSearchSchemaFactory) {
+ this.elasticSearchSchemaFactory = elasticSearchSchemaFactory;
+ this.syncControllers = new ArrayList();
+ 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 getIndexNameToSchemaConfigMap() {
+ return indexNameToSchemaConfigMap;
+ }
+
+ public void setIndexNameToSchemaConfigMap(
+ Map 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 getAggregationEntityToIndexMap() {
+ return aggregationEntityToIndexMap;
+ }
+
+ public void setAggregationEntityToIndexMap(Map aggregationEntityToIndexMap) {
+ this.aggregationEntityToIndexMap = aggregationEntityToIndexMap;
+ }
+
+ public void buildControllers() {
+
+ if (syncControllerConfig.isEnabled()) {
+
+ Map 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 selflinks;
+ private Deque retryQueue;
+ private Map retryLimitTracker;
+ protected ExecutorService esPutExecutor;
+ private ConcurrentHashMap entityCounters;
+ private boolean syncInProgress;
+ private Map 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();
+ 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();
+ this.retryQueue = new ConcurrentLinkedDeque();
+ this.retryLimitTracker = new ConcurrentHashMap();
+
+ 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 contextMap = MDC.getCopyOfContextMap();
+ final String entity = this.getEntityType();
+ try {
+
+ aaiWorkOnHand.set(1);
+
+ supplyAsync(new Supplier() {
+
+ @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) {
+ /**
+ *
+ *
+ * As part of the response processing we need to do the following:
+ * - 1. Extract the version (if present), it will be the ETAG when we use the
+ * Search-Abstraction-Service
+ *
- 2. Spawn next task which is to do the PUT operation into elastic with or with the version
+ * tag
+ *
- a) if version is null or RC=404, then standard put, no _update with version tag
+ *
- b) if version != null, do PUT with _update?version= versionNumber in the URI to elastic
+ *
+ *
+ */
+ 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 sourceObject = new ArrayList();
+ 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 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 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 entityCounters;
+ private boolean syncInProgress;
+ private Map 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();
+ 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 descriptorMap =
+ searchableEntityLookup.getSearchableEntityDescriptors();
+
+ if (descriptorMap.isEmpty()) {
+ LOG.error(AaiUiMsgs.OXM_FAILED_RETRIEVAL, "historical entities");
+
+ return OperationState.ERROR;
+ }
+
+ Collection entityTypes = descriptorMap.keySet();
+
+ AtomicInteger asyncWoH = new AtomicInteger(0);
+
+ asyncWoH.set(entityTypes.size());
+
+ try {
+ for (String entityType : entityTypes) {
+
+ supplyAsync(new Supplier() {
+
+ @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 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> entityCounterEntries = entityCounters.entrySet();
+
+ for (Entry entityCounterEntry : entityCounterEntries) {
+
+ supplyAsync(new Supplier() {
+
+ @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 namedCounters;
+ private HashMap namedHistograms;
+
+ /**
+ * Instantiates a new abstract statistics.
+ */
+ protected AbstractStatistics() {
+ namedCounters = new HashMap();
+ namedHistograms = new HashMap();
+ }
+
+ /* (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 selflinks;
+ private ConcurrentHashMap entityCounters;
+ private boolean syncInProgress;
+ private Map contextMap;
+ protected ExecutorService esPutExecutor;
+ private Deque retryQueue;
+ private Map 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();
+ this.entityCounters = new ConcurrentHashMap();
+ 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();
+ this.retryLimitTracker = new ConcurrentHashMap();
+ this.syncDurationInMs = -1;
+ this.filtersConfig = filtersConfig;
+ }
+
+ /**
+ * Collect all the work.
+ *
+ * @return the operation state
+ */
+ private OperationState collectAllTheWork() {
+ final Map contextMap = MDC.getCopyOfContextMap();
+ Map 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 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() {
+
+ @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 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 getSuggestableAttrNamesFromReponse(JsonNode node, String entityName) {
+ List suggestableAttr = new ArrayList();
+
+ HashMap desc =
+ suggestionEntityLookup.getSuggestionSearchEntityOxmModel().get(entityName);
+
+ if (desc != null) {
+
+ String attr = desc.get("suggestibleAttributes");
+
+ if (attr != null) {
+ suggestableAttr = Arrays.asList(attr.split(","));
+ List suggestableValue = new ArrayList();
+ for (String attribute : suggestableAttr) {
+ if (node.get(attribute) != null && node.get(attribute).asText().length() > 0) {
+ suggestableValue.add(attribute);
+ }
+ }
+ return suggestableValue;
+ }
+ }
+
+ return new ArrayList();
+ }
+
+ /**
+ * 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 availableSuggestableAttrName =
+ getSuggestableAttrNamesFromReponse(entityNode, entityName);
+
+ ArrayList> 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 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 primaryKeyValues = new ArrayList();
+ 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) {
+ /**
+ *
+ *
+ * As part of the response processing we need to do the following:
+ * - 1. Extract the version (if present), it will be the ETAG when we use the
+ * Search-Abstraction-Service
+ *
- 2. Spawn next task which is to do the PUT operation into elastic with or with the version
+ * tag
+ *
- a) if version is null or RC=404, then standard put, no _update with version tag
+ *
- b) if version != null, do PUT with _update?version= versionNumber in the URI to elastic
+ *
+ *
+ */
+ 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 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 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 filterValues = new ArrayList<>();
+
+ public CommonSearchSuggestion() {}
+
+ public CommonSearchSuggestion(String hashId, String route, String text, String perspective,
+ List filterValues) {
+ this.hashId = hashId;
+ this.route = route;
+ this.text = text;
+ this.filterValues = filterValues;
+ }
+
+ public List 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 referenceAttributes;
+
+ /**
+ * Instantiates a new cross entity reference.
+ */
+ public CrossEntityReference() {
+ targetEntityType = null;
+ referenceAttributes = new ArrayList();
+ }
+
+ public String getTargetEntityType() {
+ return targetEntityType;
+ }
+
+ public void setTargetEntityType(String targetEntityType) {
+ this.targetEntityType = targetEntityType;
+ }
+
+ public List getReferenceAttributes() {
+ return referenceAttributes;
+ }
+
+ public void setReferenceAttributes(List 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> crossReferenceEntityOxmModel;
+ private Map crossReferenceEntityDescriptors;
+
+
+ public CrossEntityReferenceLookup() {
+ crossReferenceEntityOxmModel = new LinkedHashMap>();
+ crossReferenceEntityDescriptors = new HashMap();
+ }
+
+ @Override
+ public void processOxmModel(DynamicJAXBContext jaxbContext) {
+
+ @SuppressWarnings("rawtypes")
+ List descriptorsList = jaxbContext.getXMLContext().getDescriptors();
+
+ for (@SuppressWarnings("rawtypes")
+ Descriptor desc : descriptorsList) {
+
+ DynamicType entity = jaxbContext.getDynamicType(desc.getAlias());
+
+ LinkedHashMap oxmProperties = new LinkedHashMap();
+
+ // 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 properties = entity.getDescriptor().getProperties();
+ if (properties != null) {
+ for (Map.Entry entry : properties.entrySet()) {
+
+ if (entry.getKey().equalsIgnoreCase("crossEntityReference")) {
+ oxmProperties.put("crossEntityReference", entry.getValue());
+ }
+ }
+ }
+
+ if (oxmProperties.containsKey("crossEntityReference")) {
+ crossReferenceEntityOxmModel.put(entityName, oxmProperties);
+ }
+
+ }
+
+ for (Entry> crossRefModel : crossReferenceEntityOxmModel
+ .entrySet()) {
+ HashMap attribute = crossRefModel.getValue();
+ CrossEntityReferenceDescriptor entity = new CrossEntityReferenceDescriptor();
+ entity.setEntityName(attribute.get("entityName"));
+ entity.setPrimaryKeyAttributeNames(
+ Arrays.asList(attribute.get("primaryKeyAttributeNames").replace(" ", "").split(",")));
+
+ List 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> getCrossReferenceEntityOxmModel() {
+ return crossReferenceEntityOxmModel;
+ }
+
+ public void setCrossReferenceEntityOxmModel(
+ Map> crossReferenceEntityOxmModel) {
+ this.crossReferenceEntityOxmModel = crossReferenceEntityOxmModel;
+ }
+
+ public Map getCrossReferenceEntityDescriptors() {
+ return crossReferenceEntityDescriptors;
+ }
+
+ public void setCrossReferenceEntityDescriptors(
+ Map 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> geoEntityOxmModel;
+
+ private Map geoEntityDescriptors;
+
+ public GeoEntityLookup() {
+ geoEntityOxmModel = new LinkedHashMap>();
+ geoEntityDescriptors = new HashMap();
+ }
+
+ public Map> getGeoEntityOxmModel() {
+ return geoEntityOxmModel;
+ }
+
+ public void setGeoEntityOxmModel(Map> geoEntityOxmModel) {
+ this.geoEntityOxmModel = geoEntityOxmModel;
+ }
+
+ public Map getGeoEntityDescriptors() {
+ return geoEntityDescriptors;
+ }
+
+ public void setGeoEntityDescriptors(Map geoEntityDescriptors) {
+ this.geoEntityDescriptors = geoEntityDescriptors;
+ }
+
+ @Override
+ public void processOxmModel(DynamicJAXBContext jaxbContext) {
+
+ @SuppressWarnings("rawtypes")
+ List descriptorsList = jaxbContext.getXMLContext().getDescriptors();
+
+ for (@SuppressWarnings("rawtypes")
+ Descriptor desc : descriptorsList) {
+
+ DynamicType entity = jaxbContext.getDynamicType(desc.getAlias());
+
+ LinkedHashMap oxmProperties = new LinkedHashMap();
+
+ // 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 properties = entity.getDescriptor().getProperties();
+
+ if (properties != null) {
+ for (Map.Entry 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> entityModel : geoEntityOxmModel.entrySet()) {
+
+ HashMap 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 primaryKeyAttributeNames;
+
+ public OxmEntityDescriptor() {
+ primaryKeyAttributeNames = new ArrayList();
+ }
+
+ public String getEntityName() {
+ return entityName;
+ }
+
+ public void setEntityName(String entityName) {
+ this.entityName = entityName;
+ }
+
+ public List getPrimaryKeyAttributeNames() {
+ return primaryKeyAttributeNames;
+ }
+
+ public void setPrimaryKeyAttributeNames(List 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> oxmModel;
+
+ private Map entityTypeLookup;
+
+ private Map entityDescriptors;
+
+
+ public OxmEntityLookup() {
+ oxmModel = new LinkedHashMap>();
+ entityTypeLookup = new LinkedHashMap();
+ entityDescriptors = new HashMap();
+ }
+
+ @Override
+ public void processOxmModel(DynamicJAXBContext jaxbContext) {
+
+ @SuppressWarnings("rawtypes")
+ List descriptorsList = jaxbContext.getXMLContext().getDescriptors();
+
+ for (@SuppressWarnings("rawtypes")
+ Descriptor desc : descriptorsList) {
+
+ DynamicType entity = jaxbContext.getDynamicType(desc.getAlias());
+
+ LinkedHashMap oxmProperties = new LinkedHashMap();
+
+ // 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 properties = entity.getDescriptor().getProperties();
+
+ oxmModel.put(entityName, oxmProperties);
+
+ }
+
+ for (Entry> entityModel : oxmModel.entrySet()) {
+ HashMap 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> getOxmModel() {
+ return oxmModel;
+ }
+
+ public void setOxmModel(Map> oxmModel) {
+ this.oxmModel = oxmModel;
+ }
+
+ public Map getEntityTypeLookup() {
+ return entityTypeLookup;
+ }
+
+ public void setEntityTypeLookup(Map entityTypeLookup) {
+ this.entityTypeLookup = entityTypeLookup;
+ }
+
+ public Map getEntityDescriptors() {
+ return entityDescriptors;
+ }
+
+ public void setEntityDescriptors(Map 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 processors;
+ private int latestVersionNum = 0;
+
+ private final static Pattern p = Pattern.compile("aai_oxm_(v)(.*).xml");
+
+ public OxmModelLoader() {
+ this(-1, new HashSet());
+ }
+
+ public OxmModelLoader(int apiVersionOverride,Set oxmModelProcessors) {
+ this.oxmApiVersionOverride = apiVersionOverride;
+ this.processors = oxmModelProcessors;
+ }
+
+ protected synchronized Map getStreamHandlesForOxmFromResource() {
+ Map listOfOxmFiles = new HashMap();
+ 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 properties = new HashMap();
+ 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 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> searchableOxmModel;
+ private Map searchableEntityDescriptors;
+
+ public SearchableEntityLookup() {
+ searchableOxmModel = new LinkedHashMap>();
+ searchableEntityDescriptors = new HashMap();
+ }
+
+ @Override
+ public void processOxmModel(DynamicJAXBContext jaxbContext) {
+
+ @SuppressWarnings("rawtypes")
+ List descriptorsList = jaxbContext.getXMLContext().getDescriptors();
+
+ for (@SuppressWarnings("rawtypes")
+ Descriptor desc : descriptorsList) {
+
+ DynamicType entity = jaxbContext.getDynamicType(desc.getAlias());
+
+ LinkedHashMap oxmProperties = new LinkedHashMap();
+
+ // 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 properties = entity.getDescriptor().getProperties();
+ if (properties != null) {
+ for (Map.Entry 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> searchableModel : searchableOxmModel.entrySet()) {
+ HashMap 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> getSearchableOxmModel() {
+ return searchableOxmModel;
+ }
+
+ public void setSearchableOxmModel(Map> searchableOxmModel) {
+ this.searchableOxmModel = searchableOxmModel;
+ }
+
+ public Map getSearchableEntityDescriptors() {
+ return searchableEntityDescriptors;
+ }
+
+ public void setSearchableEntityDescriptors(
+ Map 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 searchableAttributes;
+
+ public List getSearchableAttributes() {
+ return searchableAttributes;
+ }
+
+ public void setSearchableAttributes(List 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> suggestionSearchEntityOxmModel;
+ private Map suggestionSearchEntityDescriptors;
+ private FiltersConfig filtersConfig;
+
+ public SuggestionEntityLookup(FiltersConfig filtersConfig) {
+ suggestionSearchEntityOxmModel = new LinkedHashMap>();
+ suggestionSearchEntityDescriptors = new HashMap();
+ this.filtersConfig = filtersConfig;
+ }
+
+ @Override
+ public void processOxmModel(DynamicJAXBContext jaxbContext) {
+
+ @SuppressWarnings("rawtypes")
+ List descriptorsList = jaxbContext.getXMLContext().getDescriptors();
+
+ for (@SuppressWarnings("rawtypes")
+ Descriptor desc : descriptorsList) {
+
+ DynamicType entity = jaxbContext.getDynamicType(desc.getAlias());
+
+ LinkedHashMap oxmProperties = new LinkedHashMap();
+
+ // 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 properties = entity.getDescriptor().getProperties();
+ if (properties != null) {
+ for (Map.Entry entry : properties.entrySet()) {
+
+
+ if (entry.getKey().equalsIgnoreCase("containsSuggestibleProps")) {
+
+ oxmProperties.put("containsSuggestibleProps", "true");
+
+ Vector descriptorMaps = entity.getDescriptor().getMappings();
+ List listOfSuggestableAttributes = new ArrayList();
+
+ 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> suggestionEntityModel : suggestionSearchEntityOxmModel
+ .entrySet()) {
+ HashMap 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> getSuggestionSearchEntityOxmModel() {
+ return suggestionSearchEntityOxmModel;
+ }
+
+ public void setSuggestionSearchEntityOxmModel(
+ Map> suggestionSearchEntityOxmModel) {
+ this.suggestionSearchEntityOxmModel = suggestionSearchEntityOxmModel;
+ }
+
+ public Map getSuggestionSearchEntityDescriptors() {
+ return suggestionSearchEntityDescriptors;
+ }
+
+ public void setSuggestionSearchEntityDescriptors(
+ Map 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 selflinks;
+ private Deque retryQueue;
+ private Map 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();
+ this.retryQueue = new ConcurrentLinkedDeque();
+ this.retryLimitTracker = new ConcurrentHashMap();
+ 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 contextMap = MDC.getCopyOfContextMap();
+ Map descriptorMap =
+ crossEntityReferenceLookup.getCrossReferenceEntityDescriptors();
+
+ if (descriptorMap.isEmpty()) {
+ LOG.error(AaiUiMsgs.ERROR_LOADING_OXM);
+
+ return OperationState.ERROR;
+ }
+
+ Collection 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() {
+
+ @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 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:
+ *
+ * .:
+ *
+ * @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 primaryKeyNames = entityDescriptor.getPrimaryKeyAttributeNames();
+ final List keyValues = new ArrayList();
+ 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:
+ *
+ * Extract primary key name and value from the parent type.
+ * Extract the primary key and value from the nested child instance.
+ * Build a generic query to discover the self-link for the nested-child-instance using
+ * parent and child.
+ * Set the self-link on the child.
+ * Generate the id that will allow the elastic-search upsert to work.
+ * 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 extractedParentEntityAttributeValues = new ArrayList();
+
+ NodeUtils.extractFieldValuesFromObject(convertedNode,
+ cerDefinition.getReferenceAttributes(),
+ extractedParentEntityAttributeValues);
+
+ List nestedTargetEntityInstances = new ArrayList();
+ NodeUtils.extractObjectsByKey(convertedNode, cerDefinition.getTargetEntityType(),
+ nestedTargetEntityInstances);
+
+ for (JsonNode targetEntityInstance : nestedTargetEntityInstances) {
+
+ if (cerDescriptor != null) {
+
+ String childEntityType = cerDefinition.getTargetEntityType();
+ OxmEntityDescriptor childDesciptor = oxmEntityLookup.getEntityDescriptors().get(childEntityType);
+
+ List childPrimaryKeyNames = null;
+
+ if (childDesciptor != null) {
+ childPrimaryKeyNames = childDesciptor.getPrimaryKeyAttributeNames();
+ } else {
+ childPrimaryKeyNames = new ArrayList();
+ }
+
+ List childKeyValues = new ArrayList();
+ 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 orderedQueryKeyParams = new ArrayList();
+
+ /**
+ * 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 entityLinks = new ArrayList();
+ 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) {
+ /**
+ *
+ *
+ * As part of the response processing we need to do the following:
+ * - 1. Extract the version (if present), it will be the ETAG when we use the
+ * Search-Abstraction-Service
+ *
- 2. Spawn next task which is to do the PUT operation into elastic with or with the version
+ * tag
+ *
- a) if version is null or RC=404, then standard put, no _update with version tag
+ *
- b) if version != null, do PUT with _update?version= (versionNumber) in the URI to elastic
+ *
+ *
+ */
+ 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 sourceObject = new ArrayList();
+ 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 primaryKeyValues = new ArrayList();
+ 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> getMessageHeaders() {
+
+ Map> headers = new HashMap>();
+
+ headers.putIfAbsent(HEADER_FROM_APP_ID, new ArrayList());
+ headers.get(HEADER_FROM_APP_ID).add(UI_APP_NAME);
+
+ headers.putIfAbsent(HEADER_TRANS_ID, new ArrayList());
+ headers.get(HEADER_TRANS_ID).add(TRANSACTION_ID_PREFIX + NodeUtils.getRandomTxnId());
+
+ if (endpointConfig.getRestAuthenticationMode() == RestAuthenticationMode.SSL_BASIC) {
+
+ headers.putIfAbsent(HEADER_AUTHORIZATION, new ArrayList());
+ 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 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> getMessageHeaders() {
+ Map> headers = new HashMap>();
+ // 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> headers = getMessageHeaders();
+ headers.putIfAbsent("X-HTTP-Method-Override", new ArrayList());
+ 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> getMessageHeaders() {
+
+ Map> headers = new HashMap>();
+
+ headers.putIfAbsent(HEADER_FROM_APP_ID, new ArrayList());
+ headers.get(HEADER_FROM_APP_ID).add(UI_APP_NAME);
+
+ headers.putIfAbsent(HEADER_TRANS_ID, new ArrayList());
+ headers.get(HEADER_TRANS_ID).add(TRANSACTION_ID_PREFIX + NodeUtils.getRandomTxnId());
+
+ if (endpointConfig.getRestAuthenticationMode() == RestAuthenticationMode.SSL_BASIC) {
+
+ headers.putIfAbsent(HEADER_AUTHORIZATION, new ArrayList());
+ 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> activeInventoryEntityStatistics;
+
+ /**
+ * Creates the entity op stats.
+ *
+ * @return the hash map
+ */
+ private HashMap createEntityOpStats() {
+
+ HashMap opStats = new HashMap();
+
+ 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 keys = activeInventoryEntityStatistics.keySet();
+
+ Set opStatKeySet = null;
+ Map 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>();
+ 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 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 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> activeInventoryEntitySortedTreeMap =
+ new TreeMap>(new Comparator() {
+
+ @Override
+ public int compare(String o1, String o2) {
+ return o1.toLowerCase().compareTo(o2.toLowerCase());
+ }
+ });
+
+ activeInventoryEntitySortedTreeMap.putAll(activeInventoryEntityStatistics);
+
+ for (String counterEntityKey : activeInventoryEntitySortedTreeMap.keySet()) {
+
+ HashMap 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> entityStatistics;
+
+ /**
+ * Creates the entity op stats.
+ *
+ * @return the hash map
+ */
+ private HashMap createEntityOpStats() {
+
+ HashMap opStats = new HashMap();
+
+ 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 keys = entityStatistics.keySet();
+
+ Set opStatKeySet = null;
+ Map 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>();
+ 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 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 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> elasticEntitySortedTreeMap =
+ new TreeMap>(new Comparator() {
+
+ @Override
+ public int compare(String o1, String o2) {
+ return o1.toLowerCase().compareTo(o2.toLowerCase());
+ }
+ });
+
+ elasticEntitySortedTreeMap.putAll(entityStatistics);
+
+ for (String counterEntityKey : elasticEntitySortedTreeMap.keySet()) {
+
+ HashMap 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> getHeaders() {
+ Map> 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> 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 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 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 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 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 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 attributeValues) throws AttributeUpdateException {
+
+ ObjectMapper mapper = new ObjectMapper();
+ mapper.setPropertyNamingStrategy(new PropertyNamingStrategy.KebabCaseStrategy());
+ ObjectWriter ow = mapper.writer();
+
+ Map 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,
+ *
+ *
+ * user1
+ * user2
+ *
+ */
+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 getUsers() throws IOException {
+ List userList = new ArrayList<>();
+ try (Stream 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 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 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 getAttributes() {
+ return attributes;
+ }
+
+ public void setAttributes(Map 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 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 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> getTxnHeaders() {
+ Map> headers = new HashMap>();
+ 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